在Java中使用play framewok和akka进行映射诊断上下文记录
|
我正在尝试mdc日志记录在 java中的所有请求我在这个教程中遵循 Scala并尝试转换为java http://yanns.github.io/blog/2014/05/04/slf4j-mapped-diagnostic-context-mdc-with-play-framework/ 但仍然mdc不传播到所有执行上下文. 下面是我的java代码 import java.util.Map;
import org.slf4j.MDC;
import scala.concurrent.ExecutionContext;
import scala.concurrent.duration.Duration;
import scala.concurrent.duration.FiniteDuration;
import akka.dispatch.Dispatcher;
import akka.dispatch.ExecutorServiceFactoryProvider;
import akka.dispatch.MessageDispatcherConfigurator;
public class MDCPropagatingDispatcher extends Dispatcher {
public MDCPropagatingDispatcher(
MessageDispatcherConfigurator _configurator,String id,int throughput,Duration throughputDeadlineTime,ExecutorServiceFactoryProvider executorServiceFactoryProvider,FiniteDuration shutdownTimeout) {
super(_configurator,id,throughput,throughputDeadlineTime,executorServiceFactoryProvider,shutdownTimeout);
}
@Override
public ExecutionContext prepare() {
final Map<String,String> mdcContext = MDC.getCopyOfContextMap();
return new ExecutionContext() {
@Override
public void execute(Runnable r) {
Map<String,String> oldMDCContext = MDC.getCopyOfContextMap();
setContextMap(mdcContext);
try {
r.run();
} finally {
setContextMap(oldMDCContext);
}
}
@Override
public ExecutionContext prepare() {
return this;
}
@Override
public void reportFailure(Throwable t) {
play.Logger.info("error occured in dispatcher");
}
};
}
private void setContextMap(Map<String,String> context) {
if (context == null) {
MDC.clear();
} else {
play.Logger.info("set context "+ context.toString());
MDC.setContextMap(context);
}
}
}
import java.util.concurrent.TimeUnit;
import scala.concurrent.duration.Duration;
import scala.concurrent.duration.FiniteDuration;
import com.typesafe.config.Config;
import akka.dispatch.DispatcherPrerequisites;
import akka.dispatch.MessageDispatcher;
import akka.dispatch.MessageDispatcherConfigurator;
public class MDCPropagatingDispatcherConfigurator extends
MessageDispatcherConfigurator {
private MessageDispatcher instance;
public MDCPropagatingDispatcherConfigurator(Config config,DispatcherPrerequisites prerequisites) {
super(config,prerequisites);
Duration throughputDeadlineTime = new FiniteDuration(-1,TimeUnit.MILLISECONDS);
FiniteDuration shutDownDuration = new FiniteDuration(1,TimeUnit.MILLISECONDS);
instance = new MDCPropagatingDispatcher(this,"play.akka.actor.contexts.play-filter-context",100,configureExecutor(),shutDownDuration);
}
public MessageDispatcher dispatcher() {
return instance;
}
}
过滤拦截器 public class MdcLogFilter implements EssentialFilter {
@Override
public EssentialAction apply(final EssentialAction next) {
return new MdcLogAction() {
@Override
public Iteratee<byte[],SimpleResult> apply(
final RequestHeader requestHeader) {
final String uuid = Utils.generateRandomUUID();
MDC.put("uuid",uuid);
play.Logger.info("request started"+uuid);
final ExecutionContext playFilterContext = Akka.system()
.dispatchers()
.lookup("play.akka.actor.contexts.play-custom-filter-context");
return next.apply(requestHeader).map(
new AbstractFunction1<SimpleResult,SimpleResult>() {
@Override
public SimpleResult apply(SimpleResult simpleResult) {
play.Logger.info("request ended"+uuid);
MDC.remove("uuid");
return simpleResult;
}
},playFilterContext);
}
@Override
public EssentialAction apply() {
return next.apply();
}
};
}
} 解决方法以下是我的解决方案,在现实生活中证明.它在Scala,而不是Play,而是Scalatra,但其基本概念是一样的.希望您能够找出如何将其移植到Java.import org.slf4j.MDC
import java.util.{Map => JMap}
import scala.concurrent.{ExecutionContextExecutor,ExecutionContext}
object MDCHttpExecutionContext {
def fromExecutionContextWithCurrentMDC(delegate: ExecutionContext): ExecutionContextExecutor =
new MDCHttpExecutionContext(MDC.getCopyOfContextMap(),delegate)
}
class MDCHttpExecutionContext(mdcContext: JMap[String,String],delegate: ExecutionContext)
extends ExecutionContextExecutor {
def execute(runnable: Runnable): Unit = {
val callingThreadMDC = MDC.getCopyOfContextMap()
delegate.execute(new Runnable {
def run() {
val currentThreadMDC = MDC.getCopyOfContextMap()
setContextMap(callingThreadMDC)
try {
runnable.run()
} finally {
setContextMap(currentThreadMDC)
}
}
})
}
private[this] def setContextMap(context: JMap[String,String]): Unit = {
Option(context) match {
case Some(ctx) => {
MDC.setContextMap(context)
}
case None => {
MDC.clear()
}
}
}
def reportFailure(t: Throwable): Unit = delegate.reportFailure(t)
}
您必须确保在所有异步调用中使用此ExecutionContext.我通过依赖注入来实现这一点,但有不同的方法.这就是我用subcut做的: bind[ExecutionContext] idBy BindingIds.GlobalExecutionContext toSingle {
MDCHttpExecutionContext.fromExecutionContextWithCurrentMDC(
ExecutionContext.fromExecutorService(
Executors.newFixedThreadPool(globalThreadPoolSize)
)
)
}
这种做法背后的想法如下. MDC使用线程本地存储来获取属性及其值.如果您的单个请求可以在多个线程上运行,那么您需要确保您启动的新线程使用正确的MDC.为此,您创建一个自定义执行程序,确保在开始执行您分配给它的任务之前将MDC值正确复制到新线程中.您还必须确保当线程完成任务并继续执行其他操作时,将旧值放入其MDC,因为来自池的线程可以在不同请求之间切换. (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
