【问题标题】:Best way to pass threadId in log4j2 AsyncLogger在 log4j2 AsyncLogger 中传递 threadId 的最佳方法
【发布时间】:2016-04-02 21:29:02
【问题描述】:

我想使用 log4j2 异步日志记录将线程 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);
    }
}

我刚刚尝试更新到 2.5.0 版,现在我似乎无法再创建自己的 AsyncLogger,因为 AsyncLoggerDisruptor 是包私有的。 我知道我可以使用反射,但我想有更好的方法。

实现相同功能的最佳实践(设计和性能方面)是什么?

【问题讨论】:

    标签: java asynchronous logging log4j log4j2


    【解决方案1】:

    正在为此进行工作:https://issues.apache.org/jira/browse/LOG4J2-1270

    同时,您可以使用 ThreadLocal 映射或堆栈方法来完成此操作。就性能而言,ThreadLocal 堆栈比我认为的地图要便宜一些。

    【讨论】:

    • 我应该在代码中的哪个位置将 threadId 压入堆栈?我想在记录器中一次执行此操作,而不是在应用程序代码中的每个记录器调用之前执行此操作。你在这里有什么建议?我应该等(停留在2.4.1)直到你提到的票被解决了吗?
    • 通常只有一个入口点,您的应用程序会在其中接收来自提供线程模型的框架的回调。如果您的应用程序是线程池中的一些任务,那将是 Runnable 的 run() 方法或 Callable 的 call() 方法。对于 Servlet,它是 service() 或 doXxx() 方法之一。其他框架有其他回调,但通常这些入口点将是推送线程 ID(并在您的代码完成后弹出它)的理想候选者。
    • 好的,我明白了。不幸的是,我只能对我控制的代码执行此操作,而不能对某些“中间件”线程执行此操作。查看 log4j 异步记录器代码,我发现您已经需要获取 threadid,如果您仍然拥有它,也许可以将它与 LogEvent 一起传递。我会考虑一些解决方案..
    • hm,再次查看 AsyncLogger 和 RingBufferLogEventTranslator 的代码,如果我使用未缓存的线程名称策略 @AsyncLogger#initTranslatorThreadValues,看起来 threadId 应该已经在 LogEvent 上
    • 您正在查看 GitHub 中的 master 分支?这将在即将发布的 2.6 版中发布。
    猜你喜欢
    • 2014-08-02
    • 2021-09-22
    • 2014-11-13
    • 1970-01-01
    • 1970-01-01
    • 2015-01-28
    • 1970-01-01
    • 2013-12-29
    • 1970-01-01
    相关资源
    最近更新 更多