springboot项目添加请求链路追踪日志traceId

前言:

在springboot项目中,我们想要知道一次请求,从开始到结束的控制台的所有日志,方便快速区分与第二次请求的日志,我们就需要加入traceId链路追踪日志。

注意: 此方法只适用于单项目单线程使用,如果用到多线程如ThreadPoolTaskExecutor(文章末尾有解决方案 ),traceId会断联,因为 MDC 底层是 ThreadLocal ------ 数据只跟当前线程 走。还有在分布式微服务,从A服务发送请求到B服务,请求到达B服务的时候源traceId就会丢失,在B服务就会产生新的traceId。所以你是分布式微服务项目还是建议用SkyWalking/Zipkin等专业的 APM,如果只是简单的开发调试, 这种方式够用了**。**

下面开始上代码,2步搞定:

一,生成并放入 MDC

以下代码可以放入你的项目工具类包中:

复制代码
import cn.hutool.core.lang.UUID;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


@Component
@Order(-1)   // 保证最先执行
public class TraceIdFilter extends OncePerRequestFilter {

    public static final String TRACE_ID = "traceId";

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        // 1. 优先取网关传过来的 traceId,没有则新生成
        String traceId = request.getHeader(TRACE_ID);
        if (traceId == null || traceId.isEmpty()) {
            // hutool 无横杠
            traceId = UUID.randomUUID().toString(true);
        }

        // 2. 放入 MDC,后续日志模板里 %X{traceId} 自动打印
        MDC.put(TRACE_ID, traceId);

        // 3. 返回给前端/下游,方便链路追踪
        response.setHeader(TRACE_ID, traceId);

        try {
            chain.doFilter(request, response);
        } finally {
            MDC.clear();   // 防止线程复用串号
        }
    }
}

二,在你的项目日志文件中添加traceId配置

我项目中的日志文件是logback.xml,你看你自己的项目日志文件是那个,将以下配置替换即可

<!-- 原来 -->

<property name="log.pattern"

value="%d{HH:mm:ss.SSS} %thread %-5level %logger{20} - %method,%line - %msg%n"/>

<!-- 加上 traceId 占位符 -->

<property name="log.pattern"

value="%d{HH:mm:ss.SSS} %thread %-5level %X{traceId} %logger{20} - %method,%line - %msg%n"/>

主要是添加了:%X{traceId}

可以先比对一下你日志文件中是否有log.pattern下的%d{HH:mm:ss.SSS} 这一段文本,然后比对一下除**%X{traceId}**其他的文本是否一样,如果一样,你就可以直接将以下配置复制粘贴替换就文本:

复制代码
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}]  %logger{20} - [%method,%line] - %msg%n" />

三,演示效果

重启项目,随便请求一个接口

四,拓展:多线程ThreadPoolTaskExecutor解决traceId断联

复制代码
@Bean
public ThreadPoolTaskExecutor executor() {
    ThreadPoolTaskExecutor exec = new ThreadPoolTaskExecutor();
    exec.setCorePoolSize(8);
    exec.setMaxPoolSize(16);
    exec.setQueueCapacity(200);
    exec.setThreadNamePrefix("async-");
    // ========== 把主线程 MDC 复制到子线程 ==========
    exec.setTaskDecorator(runnable -> {
        Map<String, String> context = MDC.getCopyOfContextMap();   // 快照
        return () -> {
            if (context != null) MDC.setContextMap(context);
            try {
                runnable.run();
            } finally {
                MDC.clear();        // 执行完清掉
            }
        };
    });
    exec.initialize();
    return exec;
}

到此结束!!!

相关推荐
爱勇宝21 小时前
《道德经》第 7 章:真正厉害的领导者,不抢主角
前端·后端·程序员
用户2080468045621 小时前
Python3 条件控制新手实战指南
后端
HONG````21 小时前
HarmonyOS ArkUI RelativeContainer 相对定位布局:ID 锚点与 alignRules 实战
后端
Conan在掘金21 小时前
�鸿蒙报错速查:Cannot find name 'AppStorageV2',忘 import 编译就炸,根因 + 眜解法
后端
夏雪coding21 小时前
Dify 自定义插件实战:FastAPI + localtunnel 30 分钟搭一个天气查询工具
后端·ai编程
用户693717500138421 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
前端双越老师21 小时前
如何以前端视角(非0基础)学 Java ?
java·node.js·全栈
dear_bi_MyOnly21 小时前
【SpringBoot配置文件】
java·spring boot·后端·学习·spring·java-ee·学习方法
一缕清烟在人间1 天前
HarmonyOS应用开发实战:萌宠日记 - 健康提醒列表与动态数据绑定
后端
HONG````1 天前
HarmonyOS 6.1 实战:Stack 层叠布局与 Overlay 浮层详解
后端