MDC(Mapped Diagnostic Context) 的核心介绍与使用教程
关于日志框架中 MDC(Mapped Diagnostic Context) 的核心介绍与使用教程,结合其在分布式系统中的实际应用场景,分模块说明:
一、MDC 简介
MDC(映射诊断上下文) 是 SLF4J/Logback 提供的一种线程级上下文存储机制,用于在多线程或分布式环境中为每个请求绑定唯一标识(如用户ID、请求ID),使日志能关联同一请求的全链路信息。其核心价值包括:
- 区分请求来源:在并发场景下追踪特定客户端的日志流 。
- 减少日志管理开销:避免为每个客户端创建独立 Logger 实例 。
- 自动化上下文注入:通过配置,MDC 中的键值可自动输出到每条日志中 。
二、核心方法与使用
MDC 通过静态方法操作线程局部的 Map
,关键方法如下:
put(key, value)
MDC.put(\"requestId\", UUID.randomUUID());
get(key)
String id = MDC.get(\"requestId\");
remove(key)
MDC.remove(\"requestId\");
clear()
MDC.clear();
getCopyOfContextMap()
Map copy = MDC.getCopyOfContextMap();
代码示例:基础操作
// 存储上下文MDC.put(\"userId\", \"user123\");MDC.put(\"requestId\", UUID.randomUUID().toString());// 日志自动携带 MDC 值(见第三节配置)logger.info(\"Processing request...\");// 清理防止内存泄漏MDC.clear();
三、Spring Boot 集成实战
1. 添加依赖
确保包含 Logback 依赖(Spring Boot 默认集成):
ch.qos.logback logback-classic 1.2.3
2. 配置 Logback 模式
在 logback.xml
中使用 %X{key}
注入 MDC 值:
%d{HH:mm:ss} [%thread] [%X{requestId}] %-5level %logger{36} - %msg%n
3. 拦截器自动管理 MDC
通过 HandlerInterceptor
在请求生命周期绑定/清理 MDC:
@Componentpublic class MdcInterceptor implements HandlerInterceptor { private static final String REQ_ID = \"requestId\"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { MDC.put(REQ_ID, UUID.randomUUID().toString()); // 绑定请求ID return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { MDC.remove(REQ_ID); // 请求结束移除 }}
注册拦截器:
@Configurationpublic class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MdcInterceptor()); }}
4. 验证日志输出
日志将自动携带 requestId
:
12:45:22 [http-nio-8080-exec-1] [c6acd0ff-9c6a-4153-a12b] INFO com.example.Controller - Handling request from user123
️ 四、关键注意事项
- 线程池场景
- 线程池中的线程会复用 MDC 上下文,需手动传递:
// 父线程复制上下文 Map context = MDC.getCopyOfContextMap(); executorService.submit(() -> { MDC.setContextMap(context); // 子线程绑定 // ... 业务逻辑 MDC.clear(); });
2. 内存泄漏风险
- 必须在请求结束时调用
remove()
或clear()
,否则 MDC 数据会随线程复用污染后续请求 。
- 内置过滤器
- 使用
MDCInsertingServletFilter
自动注入请求基础信息(如 URL、IP):
- 使用
@Bean public FilterRegistrationBean mdcFilter() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new MDCInsertingServletFilter()); bean.addUrlPatterns(\"/*\"); return bean; }
五、适用场景总结
traceId
52
userId
到 MDC58
通过 MDC,开发者能以低侵入方式实现日志的精细化治理,尤其在微服务架构中,它是提升可观测性的基础工具。完整代码示例可参考 Logback 官方文档。