Scala Akka Logging with SLF4J MDC

孤街浪徒 提交于 2019-11-29 02:29:21

If all your code outside the actor system is single-threaded (i.e. you don't spawn any additional futures or threads), there's a simpler solution than the one @jasop references.

I have this mixin that takes care of populating the MDC both inside and outside actors:

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
  }
}

The non-actor code can use any logger, e.g. mix in the com.typesafe.scalalogging.LazyLogging trait.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!