alibaba / transmittable-thread-local

📌 a missing Java std lib(simple & 0-dependency) for framework/middleware, provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.
https://github.com/alibaba/transmittable-thread-local
Apache License 2.0
7.59k stars 1.69k forks source link

能否提供与LOG4J(2)中的MDC集成或增强 #49

Closed bwzhang2011 closed 9 years ago

bwzhang2011 commented 9 years ago

Hi~

注意到multiple-thread-context提供了上下文线程变量的传递,并提供了针对RunnableCallable的支持。由于上述场景中有一部分是用在日志中,当前log4j(2)提供了MDC的支持。

想问的是,能否提供一个针对其的增强支持,以log4j2为例已经提供了入口操作的类ThreadContext,若在Executor中传递则需要 使用 该类中的 getContext() and cloneStack() 方法。

此外,框架是否考虑了如何清除这些线程安全变量(以WEB为例大多数是在filter里面使用PUT然后 执行完毕后 POPCLEAR)——是否有好的建议(以multi-thread-context的使用为例)。

oldratlee commented 9 years ago

LOG4J(2)的集成 想法不错,我理解和思考一下你说的实现过程。

另外,在MDC的需求说明中,关于日志场景的说明还是比较模糊的,你能给一下更明确实际些的场景说明不?这样做起来更有目标感 :smile_cat: @bwzhang2011

bwzhang2011 commented 9 years ago

@oldratlee 感谢回复。

使用MDC是用来记录跟应用上下文环境中需要保存的一些数据,比如请求类提取的、跟执行有关的跟踪信息还有当异常发生的时候提取的,这些可以在appender中的layout来指定这些信息(比如%X{key1}: %X{key2}等)。

一般场景可以是:

  1. filter类中写入parent thread的内容(MDC.put)——带有一traceId或其余标记信息(用户)
  2. 业务类中写入业务类的信息(MDC.put)——可提取跟traceId或标记有关的信息(提取),并保存其余的消息(跟本线程有关的)并进行保存保存
  3. 清空filter的线程变量,finally { ThreadContext.clearAll() }
oldratlee commented 9 years ago

MtContextThreadLocal新加上callback方法:

    protected void beforeExecute() {
    }

    protected void afterExecute() {
    }

MtContextThreadLocal.java

可以覆盖这个方法 来完成 log4j2的设置,达到filter的效果:

    static MtContextThreadLocal<Map<String, String>> mtc = new MtContextThreadLocal<Map<String, String>>() {
        @Override
        protected void beforeExecute() {
            final Map<String, String> log4j2Context = get();
            for (Map.Entry<String, String> entry : log4j2Context.entrySet()) {
                ThreadContext.put(entry.getKey(), entry.getValue());
            }
        }

        @Override
        protected void afterExecute() {
            ThreadContext.clearAll();
        }

        @Override
        protected Map<String, String> initialValue() {
            return new HashMap<String, String>();
        }
    };

Log的代码:

    public static void main(String[] args) throws Exception {
        // Init Log Context, set MTC
        // More KV if needed
        final String TRACE_ID = "trace-id";
        final String TRACE_ID_VALUE = "XXX-YYY-ZZZ";
        ThreadContext.put(TRACE_ID, TRACE_ID_VALUE);
        mtc.get().put(TRACE_ID, TRACE_ID_VALUE);

        // Log in Main Thread
        logger.info("Log in main!");

        // Run task in thread pool
        final ExecutorService executorService = Executors.newFixedThreadPool(1);
        final Runnable task = new Runnable() {
            @Override
            public void run() {
                // Log in thread pool
                logger.info("Log in Runnable!");
            }
        };
        final Future<?> submit = executorService.submit(MtContextRunnable.get(task));
        submit.get();

        executorService.shutdown();
    }

完整示例:Log4j2ContextFilter.javalog4j2.xml

输出:

22:50:52.823 [main] INFO  log4j2.Log4j2ContextFilter XXX-YYY-ZZZ - Log in main!
22:50:52.826 [pool-2-thread-1] INFO  log4j2.Log4j2ContextFilter XXX-YYY-ZZZ - Log in Runnable!

@bwzhang2011 看看这样是不是可以解决你的问题了? 如果OK,我就发一个新版本,加上这个功能。

oldratlee commented 9 years ago

v1.2.0 已发布。 @bwzhang2011

bwzhang2011 commented 9 years ago

@oldratlee, 我再仔细看一下,看是否能合到工程中。T.K.S

bwzhang2011 commented 9 years ago

@oldratlee SL4JMDC类依赖于MDCAdapter,个人感觉如果集成则需要提供一个针对其的实现。这样我仍然只需要操作MDC即可。

oldratlee commented 9 years ago

相关的 SL4JMDCmultiple-thread-context的集成,涉及如果设置业务的Log Contexttrace-id,这个需要业务来完成, multi-thread-context提供能力。

个人感觉如果集成则需要提供一个针对其的实现

你说能一下 『针对其的实现』如何做,给一下示例代码?

如果你比较清楚了,能直接实现一下,给个PullRequest吗? :smile_cat: @bwzhang2011

jidian commented 6 years ago

很赞

zhangshity commented 1 year ago

oldratlee commented 1 year ago

PS: 已提供集成库:

<dependency>
    <groupId>com.ofpay</groupId>
    <artifactId>logback-mdc-ttl</artifactId>
    <version>1.4.0</version>
</dependency>

说明参见: https://github.com/alibaba/transmittable-thread-local/blob/master/docs/requirement-scenario.md#log4j2-mdc%E7%9A%84ttl%E9%9B%86%E6%88%90