Scala Akka使用SLF4J MDC进行日志记录

8
我正在配置我的Akka应用程序,按照此处指定的方式使用SLF4J记录器:

http://doc.akka.io/docs/akka/2.3.4/scala/logging.html

在底层,我依赖于Logback来进行日志记录。我正在为日志记录目的开发一个通用模块,用户可以在其actor系统中使用。主要是创建一个他们可以混入的特质。
我有一个特质可以做到这一点:
我有以下代码:
trait ActorLogger {

    val log: DiagnosticLoggingAdapter = Logging(this);

}

我有一些额外的逻辑,它将向DiagnosticLoggingAdapter的MDC中添加MDC值。 问题现在是这样的:如果用户想要混合到他们的非Actor类中,我会完全公开一个不同的日志记录器。因此,我可能会有像这样的内容:

trait ClassLogger {

    val log = LoggerFactory getLogger getClass.getName
}

我希望MDC值能够传递到这个记录器中。例如,如果我将MDC值放入我的DiagnosticAdapterLogger中,我应该能够从org.slf4j.MDC获取这些值。
如何以清晰的方式实现这一点?
谢谢!

1
这篇博客文章与您想要的类似。它确保MDC跨线程和actor进行复制:http://yanns.github.io/blog/2014/05/04/slf4j-mapped-diagnostic-context-mdc-with-play-framework/ - jasop
1个回答

2
如果您的actor系统之外的所有代码都是单线程的(即您不会生成任何额外的futures或线程),那么就有比@jasop提供的解决方案更简单的解决方案。
我有一个mixin,可以在actor内外都填充MDC:
import akka.actor.DiagnosticActorLogging
import akka.contrib.pattern.ReceivePipeline
import org.slf4j.MDC
import scala.collection.JavaConverters.mapAsJavaMapConverter

trait MdcActorLogging extends DiagnosticActorLogging {
  this: ReceivePipeline =>

  /**
    * This is for logging in Akka actors.
    */
  override def mdc(message: Any): akka.event.Logging.MDC = {
    message match {
      case MyMessage(requestId) => Map("requestId" -> requestId)
      case _ => Map()
    }
  }

  /**
    * This makes the MDC accessible for logging outside of Akka actors by wrapping the actor's
    * `receive` method.
    * Implements the [[http://doc.akka.io/docs/akka/2.4/contrib/receive-pipeline.html ReceivePipeline]]
    * pattern.
    */
  pipelineOuter {
    case e @ MyMessage(requestId) =>
      val origContext = MDC.getCopyOfContextMap
      val mdcWithPath = Map("requestId" -> requestId,
        // inside actors this is already provided, but outside we have to add this manually
        "akkaSource" -> self.path.toString)
      MDC.setContextMap(mdcWithPath.asJava)
      ReceivePipeline.Inner(evt) // invoke actual actor logic
        .andAfter {
          if (origContext != null)
            MDC.setContextMap(origContext)
          else
            MDC.clear()
        }
    case e => ReceivePipeline.Inner(e) // pass through
  }
}

非Actor代码可以使用任何记录器,例如混入 com.typesafe.scalalogging.LazyLogging 特质。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接