通过MDC实现多线程链路跟踪

查找日志的时候大家可能会有感受,由于日志打印一般是无序的,多线程下想要拿到一次请求中的相关日志简直是大海捞针。亦或者多系统间相互调用的时候如何快速找到某次请求的链路,MDC的出现就是解决当前问题很好的选择。

SLF4J的MDC

SLF4J 提供了MDC ( Mapped Diagnostic Contexts )功能,它的实现也是利用了 ThreadLocal 机制。 在代码中,只需要将指定的值 put 到线程上下文的 Map 中,然后在对应的地方使用 get 方法获取对应的值,从而达到自定义和修改日志输出格式内容的目的。目前只有log4j和logback提供原生的MDC支持。

应用方法

  • 创建Interceptor或者filter。拦截所有请求,在处理请求前将TRACE_ID放到MDC中,在处理完请求后清除MDC的内容。
public class LoggingInterceptor implements HandlerInterceptor {
    public static final String PROJECT_NAME = "PANACEA-";

    private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        MDC.put(MDCKeys.REQUEST_URI, request.getRequestURI());
        MDC.put(MDCKeys.REQUEST_METHOD, request.getMethod());
        MDC.put(MDCKeys.TRACE_ID, TraceIdGenerator.nextTraceId(PROJECT_NAME));

        logger.info("LoggingInterceptor.preHandle,request:",request);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        logger.info("LoggingInterceptor.afterCompletion");
        MDC.clear();
    }
}
  • 注册Interceptor
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/**");
    }
}
  • 设置日志输出格式,日志文件添加对应的MDC变量值
    
        
        
            %n [%-5level][%d{yyyy-MM-dd HH:mm:ss.SSS}] 
                *******[%mdc{TRACE_ID}] [%thread] [%mdc{REQUEST_URI}] *****
                %msg [%file:%line] %logger{35}%n
        
    

以上!

你可能感兴趣的:(通过MDC实现多线程链路跟踪)