Spring Boot 生成链路追踪 ID

Spring Boot 为每个请求生成唯一的 TraceId

TraceId 介绍

TraceId (链路追踪 ID) 是贯穿一次完整请求生命周期的唯一标识。

一般用于分布式系统排查、监控、定位问题。从网关/入口服务开始生成,一路穿透传给所有下游服务、中间件、日志、数据库等。

本文目标

本文只针对单个 Spring Boot 工程实现 TraceId 生成。用于单体服务,多请求并发时精准识别某个请求的日志。

  1. 使用 hutool 实现唯一 ID
  2. 基于 MDC 实现日志记录并重写 logback 默认日志输出格式,添加 traceId 输出
  3. 返回 Response 头 X-Trace-Id
  4. 支持多线程

代码实现

定义 Interceptor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import cn.hutool.core.util.IdUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@RequiredArgsConstructor
@Component
public class TraceIdInterceptor implements HandlerInterceptor {
    
    public static final String TRACE_ID = "traceId";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String tracedId = IdUtil.fastSimpleUUID();
        MDC.put(TRACE_ID, tracedId);
        response.setHeader("X-Trace-Id", tracedId);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        MDC.remove(TRACE_ID);
    }
}

注册 Interceptor

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class TraceIdConfig implements WebMvcConfigurer {

    private TraceIdInterceptor traceIdInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(traceIdInterceptor)
                .addPathPatterns("/**");
    }

    @Autowired
    public void setTraceIdInterceptor(TraceIdInterceptor traceIdInterceptor) {
        this.traceIdInterceptor = traceIdInterceptor;
    }
}

多线程支持

通过 TaskDecorator 实现多线程支持,将 MDC 中的 traceId 传递给子线程。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import org.slf4j.MDC;
import org.springframework.core.task.TaskDecorator;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class MdcTaskDecorator implements TaskDecorator {
    @Override
    public Runnable decorate(Runnable runnable) {
        Map<String, String> context = MDC.getCopyOfContextMap();
        return () -> {
            try {
                if (context != null) MDC.setContextMap(context);
                runnable.run();
            } finally {
                MDC.clear();
            }
        };
    }
}

如上,即可在 @Async 的方法中日志显示 traceId。

日志格式修改

在 logback 中使用 %X{traceId} 来获取 traceId 内容。作者使用如下 pattern (供参考):

1
[%X{traceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${PID:- } --- [%15.15t] %-40.40logger{39} : %m%n

logback 完整配置可参考 logback.xml 文件解析

如果本文对您有所帮助,欢迎打赏支持作者!

Licensed under CC BY-NC-SA 4.0
最后更新于 2025-12-12 13:20
使用 Hugo 构建
主题 StackJimmy 设计