zoukankan      html  css  js  c++  java
  • java多线程使用mdc追踪日志

    背景

    多线程情况下,子线程的sl4j打印日志缺少traceId等信息,导致定位问题不方便

    解决方案

    1. 打印日志时添加用户ID、trackId等信息,缺点是每个日志都要手动添加
    2. 使用mdc直接拷贝父线程值

    实现

    // 新建线程时:
    Map<String, String> mdcContextMap = MDC.getCopyOfContextMap()
    
    
    // 子线程运行时:
    if(null != mdcContextMap){
        MDC.setContextMap(mdcContextMap);
    }
    
    // 销毁线程时
    MDC.clear();
    
    

    参考

    import org.slf4j.MDC;
    
    import java.util.Map;
    import java.util.concurrent.*;
    
    /**
     * A SLF4J MDC-compatible {@link ThreadPoolExecutor}.
     * <p/>
     * In general, MDC is used to store diagnostic information (e.g. a user's session id) in per-thread variables, to facilitate
     * logging. However, although MDC data is passed to thread children, this doesn't work when threads are reused in a
     * thread pool. This is a drop-in replacement for {@link ThreadPoolExecutor} sets MDC data before each task appropriately.
     * <p/>
     * Created by jlevy.
     * Date: 6/14/13
     */
    public class MdcThreadPoolExecutor extends ThreadPoolExecutor {
    
        final private boolean useFixedContext;
        final private Map<String, Object> fixedContext;
    
        /**
         * Pool where task threads take MDC from the submitting thread.
         */
        public static MdcThreadPoolExecutor newWithInheritedMdc(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                                                                TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            return new MdcThreadPoolExecutor(null, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }
    
        /**
         * Pool where task threads take fixed MDC from the thread that creates the pool.
         */
        @SuppressWarnings("unchecked")
        public static MdcThreadPoolExecutor newWithCurrentMdc(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                                                              TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            return new MdcThreadPoolExecutor(MDC.getCopyOfContextMap(), corePoolSize, maximumPoolSize, keepAliveTime, unit,
                    workQueue);
        }
    
        /**
         * Pool where task threads always have a specified, fixed MDC.
         */
        public static MdcThreadPoolExecutor newWithFixedMdc(Map<String, Object> fixedContext, int corePoolSize,
                                                            int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                                                            BlockingQueue<Runnable> workQueue) {
            return new MdcThreadPoolExecutor(fixedContext, corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }
    
        private MdcThreadPoolExecutor(Map<String, Object> fixedContext, int corePoolSize, int maximumPoolSize,
                                      long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
            this.fixedContext = fixedContext;
            useFixedContext = (fixedContext != null);
        }
    
        @SuppressWarnings("unchecked")
        private Map<String, Object> getContextForTask() {
            return useFixedContext ? fixedContext : MDC.getCopyOfContextMap();
        }
    
        /**
         * All executions will have MDC injected. {@code ThreadPoolExecutor}'s submission methods ({@code submit()} etc.)
         * all delegate to this.
         */
        @Override
        public void execute(Runnable command) {
            super.execute(wrap(command, getContextForTask()));
        }
    
        public static Runnable wrap(final Runnable runnable, final Map<String, Object> context) {
            return new Runnable() {
                @Override
                public void run() {
                    Map previous = MDC.getCopyOfContextMap();
                    if (context == null) {
                        MDC.clear();
                    } else {
                        MDC.setContextMap(context);
                    }
                    try {
                        runnable.run();
                    } finally {
                        if (previous == null) {
                            MDC.clear();
                        } else {
                            MDC.setContextMap(previous);
                        }
                    }
                }
            };
        }
    }
    
    时间会记录下一切。
  • 相关阅读:
    C语言寒假大作战01
    C语言I作业12—学期总结
    C语言I博客作业11
    C语言I博客作业10
    浅谈js模块加载方式(初级)
    浅谈.net的后台校验
    api接口访问限制
    系统操作日志表单形式构建
    RedisUtil(未完,持续更新中....)
    定时处理组件---Quartz.net
  • 原文地址:https://www.cnblogs.com/bincoding/p/14307891.html
Copyright © 2011-2022 走看看