在前面的三篇文章中《Akka学习笔记:ACTORS介绍》《Akka学习笔记:Actor消息传递(1)》和《Akka学习笔记:Actor消息传递(2)》 ,我们只是简单地介绍了Actors以及消息传递如何工作。在这篇文章中我们将给TeacherActor类加一些日志和测试功能。
回顾
之前的TeacherActor代码的片段如下:
01 | class TeacherActor extends Actor { |
04 | "Moderation is for cowards" , |
05 | "Anything worth doing is worth overdoing" , |
06 | "The trouble is you think you have time" , |
07 | "You never gonna know if you never even try" ) |
11 | case QuoteRequest = > { |
16 | val quoteResponse = QuoteResponse(quotes(Random.nextInt(quotes.size))) |
18 | println (quoteResponse) |
用SLF4J 打印Akka日志
你可能注意到,我们直接将quoteResponse 打印到标准的输出是一个很不好的想法,让我们通过启用SLF4J Facade打印日志来修改这个。
通过日志来修复Actor类
Akka提供了一个非常小的trait 来打印日志,称为 ActorLogging。让我们来修改一下代码:
01 | class TeacherLogActor extends Actor with ActorLogging { |
04 | "Moderation is for cowards" , |
05 | "Anything worth doing is worth overdoing" , |
06 | "The trouble is you think you have time" , |
07 | "You never gonna know if you never even try" ) |
11 | case QuoteRequest = > { |
16 | val quoteResponse = QuoteResponse(quotes(Random.nextInt(quotes.size))) |
17 | log.info(quoteResponse.toString()) |
这里有点绕道。实际上,当我们以日志记下来一个message,ActorLogging 中的logging 方法已经将该消息publishes到了EventStream。那什么是EventStream?
EventStream and Logging
EventStream的行为其实有点像消息中介,我们可以通过它发布和接收消息。和一般的MOM的微秒区别就是,EventStream的订阅者(subscribers)只能是Actor。在logging消息的场景,所有的log message都会发布到EventStream中。默认情况下,订阅这些消息的Actor是DefaultLogger ,它只是简单的将消息打印到标准输出。代码片段如下:
1 | class DefaultLogger extends Actor with StdOutLogger { |
2 | override def receive : Receive = { |
4 | case event : LogEvent ⇒ print(event) |
这就是为什么当我面再次启动StudentSimulatorApp程序的时候,我们看到日志消息被打印到终端。
也就是说,EventStream不仅仅适合打日志。它是Actor世界中常用的public-subscribe机制。让我们再回到SLF4J
配置Akka来启用SLF4J
代码片段如下:
2 | loggers = [ "akka.event.slf4j.Slf4jLogger" ] |
4 | logging-filter = "akka.event.slf4j.Slf4jLoggingFilter" |
我们将这些配置信息存储在名为application.conf文件中,这个文件需要配置在你的classpath里面。在我们的工程目录下,可以放在main/resources目录下面。
从这个配置中,我们可以
1、loggers属性表明,Actor将消息订阅到log Event中。 Slf4jLogger所做的仅仅是消费 log messages并将它放到SLF4J Logger facade里。
2、loglevel 属性表明,日志的输出级别。
3、logging-filter和loglevel 结合,传入日志消息的输出级别并将符合的消息publishing到EventStream中。
你可能会说,在之前的例子里怎么就没有application.conf文件呢?那是因为Akka提供了一些默认的配置属性。
THROW IN A logback.xml
我们将通过logback.xml文件来配置SLF4J logger backed,如下:
01 | <? xml version = "1.0" encoding = "UTF-8" ?> |
04 | class = "ch.qos.logback.core.rolling.RollingFileAppender" > |
06 | < pattern >%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</ pattern > |
09 | < rollingPolicy class = "ch.qos.logback.core.rolling.TimeBasedRollingPolicy" > |
10 | < fileNamePattern >logs\akka.%d{yyyy-MM-dd}.%i.log</ fileNamePattern > |
11 | < timeBasedFileNamingAndTriggeringPolicy |
12 | class = "ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" > |
13 | < maxFileSize >50MB</ maxFileSize > |
14 | </ timeBasedFileNamingAndTriggeringPolicy > |
19 | < appender-ref ref = "FILE" /> |
同样将它放到 main/resources目录下面,你得确保 main/resources目录在你的eclipse或者其他IDE的Classpath里面。同时,你得将logback 和slf4j-api加入到你的pom文件中或者build.sbt中,如下:
01 | name := "AkkaNotes_Messaging" |
05 | organization := "com.arunma" |
07 | scalaVersion := "2.11.2" |
12 | libraryDependencies ++ = { |
13 | val akkaVersion = "2.3.4" |
14 | val sprayVersion = "1.3.1" |
16 | "com.typesafe.akka" %% "akka-actor" % akkaVersion, |
17 | "io.spray" %% "spray-can" % sprayVersion, |
18 | "io.spray" %% "spray-routing" % sprayVersion, |
19 | "io.spray" %% "spray-json" % "1.2.6" , |
20 | "com.typesafe.akka" %% "akka-slf4j" % akkaVersion, |
21 | "ch.qos.logback" % "logback-classic" % "1.1.2" , |
22 | "com.typesafe.akka" %% "akka-testkit" % akkaVersion, |
23 | "org.scalatest" %% "scalatest" % "2.2.0" |
当我们再次启动StudentSimulatorApp的时候,并且发送消息到新的TeacherLogActor中,将会生成一个名为akkaxxxxx.log的文件,内容大概如下:
如果想及时了解
Spark、Hadoop或者Hbase相关的文章,欢迎关注微信公共帐号:
iteblog_hadoop