Java 在log4j2异步记录器中传递threadId的最佳方法
我想使用Java 在log4j2异步记录器中传递threadId的最佳方法,java,asynchronous,logging,log4j,log4j2,Java,Asynchronous,Logging,Log4j,Log4j2,我想使用log4j2Async日志记录将线程Id记录为日志消息的一部分 使用log4j22.4.1,可以通过覆盖logMessage方法的自定义AsyncLogger实现这一点 public class ThreadIdAsyncLogger extends AsyncLogger { private static final long serialVersionUID = 1L; private static final ThreadLocal<Boolean>
log4j2
Async日志记录将线程Id记录为日志消息的一部分
使用log4j2
2.4.1,可以通过覆盖logMessage方法的自定义AsyncLogger
实现这一点
public class ThreadIdAsyncLogger extends AsyncLogger {
private static final long serialVersionUID = 1L;
private static final ThreadLocal<Boolean> THREAD_CONTEXT_SETUP = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};
public ThreadIdAsyncLogger(final LoggerContext context, final String name, final MessageFactory messageFactory) {
super(context, name, messageFactory);
}
@Override
public void logMessage(final String fqcn,
final Level level,
final Marker marker,
final Message message,
final Throwable thrown) {
if (!THREAD_CONTEXT_SETUP.get()) {
// it is enough to set it once per thread
ThreadContext.put(Constants.ContextMapKeys.THREAD_ID, String.valueOf(Thread.currentThread().getId()));
THREAD_CONTEXT_SETUP.set(true);
}
super.logMessage(fqcn, level, marker, message, thrown);
}
}
公共类ThreadIdAsyncLogger扩展了AsyncLogger{
私有静态最终长serialVersionUID=1L;
私有静态最终线程本地线程\u上下文\u设置=新线程本地(){
@凌驾
受保护的布尔初始值(){
返回false;
}
};
公共线程IDASyncLogger(最终LoggerContext上下文、最终字符串名称、最终MessageFactory MessageFactory){
super(上下文、名称、消息工厂);
}
@凌驾
公共无效日志消息(最终字符串fqcn,
最后一级,
最终标记,
最后的信息,
最后一次投掷){
如果(!THREAD\u CONTEXT\u SETUP.get()){
//每个线程设置一次就足够了
ThreadContext.put(Constants.ContextMapKeys.THREAD_ID,String.valueOf(THREAD.currentThread().getId());
THREAD_CONTEXT_SETUP.set(真);
}
super.logMessage(fqcn、级别、标记、消息、抛出);
}
}
我刚刚尝试更新到2.5.0版,现在我似乎无法再创建自己的AsyncLogger
,因为AsyncLoggerDisruptor
是包私有的。
我知道我可以使用反射,但我想有更好的方法
实现相同功能的最佳实践(设计和性能方面)是什么?这方面的工作正在进行中:
同时,您可以使用ThreadLocal映射或堆栈方法来实现这一点。就性能而言,ThreadLocal堆栈比我认为的map稍微便宜一些 我应该在代码中的哪个位置将threadId推送到堆栈上?我想在logger中一次性执行此操作,而不是在每次logger调用应用程序代码之前。你有什么建议?我应该等待(停留在2.4.1)直到您提到的问题得到解决吗?通常有一个入口点,您的应用程序从提供线程模型的框架接收回调。如果应用程序是线程池中的某些任务,则可能是Runnable的run()方法或Callable的call()方法。对于servlet,它是service()或doXxx()方法之一。其他框架有其他回调,但一般来说,这些入口点将是推送线程ID(并在代码完成后弹出)的理想候选。不幸的是,我只能对我控制的代码这样做,而不能对某些“中间件”线程这样做。查看log4j异步记录器代码,我发现您已经需要获取threadid了,如果您已经获得了它,那么可以将它与LogEvent一起传递。我会考虑一些解决方案..嗯,再看看AsyncLogger和RingBufferLogEventTranslator的代码,如果我使用的是非缓存线程名称策略@AsyncLogger#initTranslatorThreadValues,那么threadId应该已经在LogEvent上了。你正在查看GitHub中的主分支?这将在即将发布的2.6版中发布。