Skip to content

十二、基于 SLF4J MDC 机制的日志链路追踪功能

ZeroOrInfinity edited this page Dec 17, 2020 · 4 revisions
  • 使用此功能在日志配置文件中的 pattern 中添加 %X{MDC_TRACE_ID} 即可.
<!-- 控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- 日志格式 -->
    <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level ${PID:- } --- [%thread] %X{MDC_TRACE_ID} %logger[%L] - %msg%n</pattern>
        <charset>utf-8</charset>
    </encoder>
    <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <!-- 只有这个日志权限才能看,sql语句 -->
        <level>DEBUG</level>
    </filter>
</appender>
  • 自定义 SLF4J MDC 机制实现日志链路追踪 id 的类型: 可通过属性 ums.mdc.type 定义:
# 基于 SLF4J MDC 机制实现日志链路追踪 id 的类型, 默认为 uuid. 当需要自定义 id 时, type = MdcIdType.CUSTOMIZE_ID, 再实现 MdcIdGenerator.getMdcId() 方法, 注入 IOC 容器即可.
ums:
  mdc:
    type: UUID/THREAD_ID/SESSION_ID/CUSTOMIZE_ID

当 ums.mdc.type = CUSTOMIZE_ID 时 需要实现接口 MdcIdGenerator 并注入 IOC 容器.

  • 多线程使用问题: 父线程新建子线程之前调用 MDC.getCopyOfContextMap() 方法获取 MDC context, 子线程在执行操作前先调用 MDC.setContextMap(context) 方法将父线程的 MDC context 设置到子线程中. ThreadPoolTaskExecutor 的配置请参考 ScheduleAutoConfiguration.
  • 多线程传递 MDC context 简单示例:
final Logger log = LoggerFactory.getLogger(this.getClass());
// 获取父线程 MDC 中的内容
final Map<String, String> context = MDC.getCopyOfContextMap();
final Runnable r = () -> {
    log.info("testMDC");
    System.out.println("...");
};
new Thread(() -> {
    // 将父线程的 MDC context 设置到子线程中
    MDC.setContextMap(context);
    r.run();
}, "testMDC").start();