MDC 是 Logback 和 Log4j2 提供的线程级上下文映射工具,需配合 traceId 生成、透传、绑定及跨线程传递才能实现全链路日志追踪,关键在于请求入口注入、日志格式配置、异步场景手动传递和 HTTP/RPC 跨进程透传。

MDC 是 Logback 和 Log4j2 提供的线程级上下文映射工具,它本身不解决分布式链路追踪问题,但能为单次请求(尤其在 Web 容器或线程池场景下)提供轻量、高效的日志上下文绑定能力。要实现“全链路”效果,需配合唯一 traceId 的生成、透传与 MDC 绑定,再通过日志格式输出该字段。
1. 生成并注入 traceId 到 MDC
在请求入口(如 Spring Boot 的 Filter 或 WebMvcConfigurer)中生成全局唯一 traceId,并写入 MDC:
- 推荐使用
UUID.randomUUID().toString().replace("-", "")或更优的 Snowflake/TraceID 工具(如 Brave 的Tracer.currentSpan().context().traceIdString()) - 调用
MDC.put("traceId", traceId)将其绑定到当前线程 - 务必在请求结束时调用
MDC.clear(),避免线程复用导致日志污染(尤其在 Tomcat 线程池中)
2. 配置日志格式输出 traceId
在 logback-spring.xml 中修改 pattern,加入 %X{traceId} 占位符:
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - [traceId:%X{traceId}] - %msg%n</pattern>
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
Log4j2 对应使用 %X{traceId}(需确保配置了 PatternLayout)。
3. 跨线程传递 traceId(关键!)
MDC 默认只在当前线程有效。异步操作(如 CompletableFuture、线程池提交任务、@Async)会丢失 traceId,必须手动传递:
- 使用
MDC.getCopyOfContextMap()获取当前上下文快照 - 在线程创建前(如
executor.submit(() -> { MDC.setContextMap(...); ... }))恢复 MDC - Spring Boot 可借助
ThreadPoolTaskExecutor的setThreadFactory+ 自定义ThreadFactory实现自动继承 - 对于
CompletableFuture,建议封装工具方法(如withMdc(() -> doWork()))显式传递
4. 分布式场景下的 traceId 透传
MDC 不跨进程,因此 HTTP 调用需靠协议透传:
- 上游服务将 traceId 写入请求头(如
X-Trace-ID) - 下游服务在拦截器中读取该 header,再
MDC.put("traceId", headerValue) - Feign 客户端可通过
RequestInterceptor自动注入;RestTemplate 可用ClientHttpRequestInterceptor - RPC 框架(如 Dubbo)需扩展
Filter实现类似逻辑
不复杂但容易忽略的是 MDC 生命周期管理和跨线程传递——这两点没做好,日志看似有 traceId,实际在异步或子线程里就断掉了。

















