AKKA的日志: slf4j,logback和其他  

JerryXia 发表于 , 阅读 (0)
15 April 2015

AKKA的日志: slf4j,logback和其他

作为一个“搞kernel的”,对日志的理解不过是printk的EMERG,INFO,DEBUG等各种level,关键时刻还是得dump内存,上gcc单步跟踪。但在到处是异步并发,远程分布式通信的jdk世界,日志成了定位问题最重要甚至是唯一的手段。在akka上尤为如此。

akka日志的官方文档http://doc.akka.io/docs/akka/current/scala/logging.html

akka日志功能是基于slf4j构建的。对于不熟悉java的人,slf4j,log4j,logback等基本上是这样一个关系:SLF4J是一套log接口,java.util.logging, logback, log4j等是具体的实现,而logback已逐渐取代log4j成为事实标准。

所以要使用akka的日志,除了akka-slf4j还需增加logback依赖。

libraryDependencies ++= Seq(  "com.typesafe.akka" %% "akka-actor" % akkaVersion,  "com.typesafe.akka" %% "akka-contrib" % akkaVersion,  "com.typesafe.akka" %% "akka-testkit" % akkaVersion,  "com.typesafe.akka" %% "akka-slf4j" % akkaVersion,  "org.scalatest" %% "scalatest" % "2.2.4" % "test",  "ch.qos.logback" % "logback-classic" % "1.1.3",  "commons-io" % "commons-io" % "2.4" % "test")

actor系统中记录日志的三种方法

1 通过ActorLogging记录日志

akka提供了ActorLogging这个trait,方便在actor中记录日志。

class MasterActor extends Actor with akka.actor.ActorLogging{  def receive = {    case _ =>     log.debug("debug log")     log.info("info log")     log.warning("warning log")     log.error("error log")  }}

2 通过akka.event.Logging记录日志 

ActorLogging这个trait只能mix到Actor类上。

在其他非actor类上,如果能访问到actor系统,可利用它的event stream进行log。

import akka.event.Loggingval log = Logging(system.eventStream, "log prefix:")log.debug("debug log")

也可直接使用ActorSystem内置的LoggingAdapter。

val system = akka.actor.ActorSystem()system.log.error("log from ActorSystem")

3 直接通过slf4j访问logback记录日志

import org.slf4j.LoggerFactoryval log = LoggerFactory.getLogger(getClass)log.debug("Hello Logger!")

这3种log方式因为用的都是同一个logback实例,所以输出是统一的,区别是akka提供的log接口能够在记录时自动带上actor地址等信息,能极大的方便定位问题。

logback的配置

上面说了半天好像和printk的level级别没有太大差别,java的log系统最强大的地方在于它的可配置性。

如下面这个logback配置,可把ERROR及以上级别的打印输出到akka.log文件,同时把DEBUG及以上级别的打印输出到控制台。还可以配置输出格式,自动在log内容上附带一些上下文信息,如%X{akkaSource}这个变量会解析为发起log的具体actor地址,这在系统上百万actor并发时,将成为跟踪问题重要线索。如果输出到日志文件,还可控制文件体积的最大值,选择原有内容是追加还是覆盖。

<configuration>        <appender name="FILE" class="ch.qos.logback.core.FileAppender">        <file>akka.log</file>        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">            <level>ERROR</level>        </filter>        <append>false</append>        <!-- encoders are assigned the type             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->        <encoder>            <!--<pattern>%date{ISO8601} %-5level %logger{36} %X{sourceThread} - %msg%n</pattern>-->            <pattern>%date{ISO8601} %-5level %logger{36} %X{akkaSource} - %msg%n</pattern>        </encoder>    </appender>        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">        <encoder>            <pattern>%date{ISO8601} %-5level %logger{36} %X{akkaSource} - %msg%n</pattern>            <!--<pattern>%X{akkaTimestamp} %-5level %logger{36} %X{akkaSource} - %msg%n</pattern>-->        </encoder>    </appender>    <root level="DEBUG">        <appender-ref ref="STDOUT" />        <appender-ref ref="FILE" />    </root></configuration>

日志的每种输出方式对应一个appender,除了上面用到的ConsoleAppender和FileAppender,还有通过网络发送日志到远程日志服务器的Appender,用户也可自定义appender,如日志云服务提供商loggly就有自己的Appender。分布式消息系统kafka也能通过Appender直接在某个topic上接收log日志。

更多语法参考:http://logback.qos.ch/manual/appenders.html

最后推荐一篇LinkedIn工程师关于日志的长文The Log: What every software engineer should know about real-time data’s unifying abstraction,当然他说的日志已经超出了简单记录调试信息的范畴了,但其中一些观点很有意思,如数据库其实是一种特殊形式的日志,按照这个思路所谓大数据其实就是如何翻日志了,日志将是整个系统最重要的资产。

相关代码已提交github, 欢迎fork交流。