排查trace_id断层需检查MDC是否被意外清空、覆盖或未传递:1.拦截器/过滤器中提前clear();2.@Around切面未调用proceed()或吞异常;3.跨线程场景未透传MDC;4.通过日志+断点定位断点。

排查多层切面或拦截器嵌套中因错误捕获导致 trace_id 断层,核心在于确认 MDC 上下文是否在任意一层被意外清空、覆盖或未传递。这类问题不表现为编译报错,而是在日志中突然出现 %X{TRACE_ID} 为空,或同一请求前后日志出现两个不同 trace_id。
检查拦截器/过滤器是否提前清除 MDC
很多老项目会在权限校验、日志记录等拦截器末尾调用 MDC.clear(),意图“释放资源”。但若该拦截器位于链路中间(非最外层),就会切断后续逻辑的上下文。尤其注意以下场景:
- 自定义
OncePerRequestFilter中,在doFilter结束前执行了MDC.clear() - Spring Interceptor 的
afterCompletion方法里无条件清空 MDC - 全局异常处理器(
@ControllerAdvice)在处理异常后主动清空 MDC,却未考虑当前请求尚未结束
验证切面中是否遗漏 proceed() 或吞掉异常
使用 @Around 切面时,若逻辑分支中未调用 pjp.proceed(),或在 catch 块中静默处理异常而不重新抛出,会导致后续拦截器、控制器方法完全不执行,MDC 自然无法延续。
- 检查所有
@Around方法,确保每个执行路径都包含且仅包含一次pjp.proceed() - 避免在
try-catch中捕获异常后仅打日志却不throw e或rethrow - 特别留意带重试、熔断、降级逻辑的切面,它们最容易引入“短路”行为
确认跨线程场景下 MDC 未丢失
即使单线程流程正常,一旦涉及异步(@Async、线程池、CompletableFuture)、消息监听(Kafka Listener)、定时任务(@Scheduled),MDC 默认不会自动传递。
- 查看是否有
ThreadPoolTaskExecutor自定义,但未包装为支持 MDC 透传的装饰器 - Kafka 消费者中是否在
@KafkaListener方法开头手动从 header 提取 trace_id 并塞入 MDC - 定时任务是否每次执行都新建 trace_id,而非继承触发源头的上下文(如 Quartz Job 中需显式传递)
定位具体断点:用日志+断点双验证
不要只依赖最终日志输出。在关键节点插入调试日志,打印 MDC.get("TRACE_ID") 和当前线程名:
- 网关入口过滤器首行
- 各拦截器
preHandle/doFilter开始与结束处 - 切面
@Around的前置、proceed()前后、后置逻辑中 - Controller 方法第一行
对比同一请求 ID(如 Nginx 日志中的 $request_id)对应的所有日志行,观察 trace_id 从哪一环开始变空或突变,即可快速锁死问题组件。

















