使用SLF4J MDC的Scala Akka日志记录 [英] Scala Akka Logging with SLF4J MDC
问题描述
我正在将我的Akka应用程序配置为使用此处指定的SLF4J记录器:
I'm configuring my Akka application to use the SLF4J logger as specified here:
http://doc.akka.io/docs/akka/2.3.4/scala/logging.html
在引擎盖下,我依靠Logback进行日志记录。我正在开发用于记录目的的通用模块,用户可以在其actor系统中使用。主要是我正在创建可以混合使用的特征。
Underneath the hood, I'm depending on Logback to do the logging. I'm developing a common module for logging purposes that users can use in their actor systems. Mainly, I'm creating a trait they can mixin.
我有一个特征可以做到这一点:
I have a trait that does this:
我有这样的东西:
trait ActorLogger {
val log: DiagnosticLoggingAdapter = Logging(this);
}
我有一些额外的逻辑可以将MDC值添加到DiagnosticLoggingAdapter的MDC。
现在的问题是:如果用户想混入非演员类,我将完全公开另一个记录器。所以我可能会有这样的东西:
I have some extra logic which will add MDC values to the DiagnosticLoggingAdapter's MDC. The problem is now this: I expose a different logger entirely if users want to mixin to their non-actor classes. So I might have something like this:
trait ClassLogger {
val log = LoggerFactory getLogger getClass.getName
}
我希望MDC值可以延续到此记录器中。因此,例如,如果我将MDC值放入DiagnosticAdapterLogger中,我应该期望能够从org.slf4j.MDC中获得这些值。
I want the MDC values to carry over to this logger. So for example, if I put MDC values into my DiagnosticAdapterLogger, I should expect to be able to get those values from org.slf4j.MDC
谢谢!
推荐答案
如果您的代码全部在actor系统外部是单线程的(即,您不会生成任何其他的期货或线程),有一个比@jasop引用更简单的解决方案。
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.
这个mixin负责填充参与者内部和外部的MDC:
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
}
}
非演员代码可以使用任何记录器,例如混入 com.typesafe.scalalogging.LazyLogging
特性。
The non-actor code can use any logger, e.g. mix in the com.typesafe.scalalogging.LazyLogging
trait.
这篇关于使用SLF4J MDC的Scala Akka日志记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!