首页 文章

Scala Akka使用SLF4J MDC进行记录

提问于
浏览
6

我正在配置我的Akka应用程序以使用此处指定的SLF4J Logger :

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

在引擎盖下,我依靠Logback进行日志记录 . 我正在开发一个用于日志记录目的的通用模块,用户可以在他们的actor系统中使用 . 主要是,我正在创造一个他们可以混合的特质 .

我有一个特点,这样做:

我有这样的东西:

trait ActorLogger {

    val log: DiagnosticLoggingAdapter = Logging(this);

}

我有一些额外的逻辑,它将MDC值添加到DiagnosticLoggingAdapter的MDC . 现在的问题是:如果用户想要混合到非演员类,我会完全暴露一个不同的 Logger . 所以我可能有这样的事情:

trait ClassLogger {

    val log = LoggerFactory getLogger getClass.getName
}

我希望MDC值能够延续到此 Logger . 因此,例如,如果我将MDC值放入我的DiagnosticAdapterLogger,我应该能够从org.slf4j.MDC获取这些值

如何以干净的方式实现这一目标?

谢谢!

1 回答

  • 1

    如果actor系统之外的所有代码都是单线程的(即你没有产生任何额外的期货或线程),那么有一个比@jasop引用更简单的解决方案 .

    我有这个mixin负责在演员内部和外部填充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
      }
    }
    

    非演员代码可以使用任何 Logger ,例如混合 com.typesafe.scalalogging.LazyLogging 特质 .

相关问题