当前位置: 首页 > news >正文

SpringBoot项目注入 traceId 来追踪整个请求的日志链路

SpringBoot项目注入 traceId 来追踪整个请求的日志链路,有了 traceId, 我们在排查问题的时候,可以迅速根据 traceId 查找到相关请求的日志,特别是在生产环境的时候,用户可能只提供一个错误截图,我们作为开发人员想要更详细的日志,这时候我们就可以直接根据用户提供的 traceId 来查找用户这次请求的整个日志,会方便很多。

springboot 单体项目没办法做到有 traceId 一样的效果吗?

即使是在单体应用中,为请求添加一个唯一的traceId以追踪整个请求链路的日志也是完全可行的。虽然Spring Cloud Sleuth等工具主要用于分布式系统中的链路追踪,但在单体Spring Boot应用中你仍然可以通过一些方法来实现类似的功能。下面是一个基本的方法来手动实现这样的功能:

手动实现 traceId 注入

1. 创建一个过滤器或拦截器:你可以创建一个Servlet过滤器或者Spring的拦截器,用于在每个请求到达时生成一个唯一的traceId(如果不存在的话),并将其存储到当前线程的上下文中。

2. 使用MDC(Mapped Diagnostic Context):SLF4J提供了MDC工具,可以用来保存日志的上下文信息。你可以在过滤器或拦截器中将traceId放入MDC中,这样所有的日志记录器都可以自动包含这个ID。 示例代码:

TraceIdFilter :

# 我这里用的是 jdk17, 所以 servlet 工具类被移动到了 jakarta 包下,如果你用的是比较老的 jdk, 可以删除后重新导入 servlet 的类。
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;import java.io.IOException;
import java.util.UUID;
@Compone
nt
public class TraceIdFilter extends OncePerRequestFilter {private static final String TRACE_ID = "traceId";@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {String traceId = request.getHeader(TRACE_ID);if (traceId == null) {traceId = UUID.randomUUID().toString();}MDC.put(TRACE_ID, traceId);try {filterChain.doFilter(request, response);} finally {MDC.remove(TRACE_ID);}}
}

3. 配置日志格式:确保你的日志配置文件(如logback.xml、log4j2.xml等)中包含了输出traceId的配置。例如,在logback中,你可以这样做:

<configuration><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} - [%thread] %-5level %logger{36} - [%X{traceId}] - %msg%n</pattern></encoder></appender><root level="info"><appender-ref ref="CONSOLE"/></root>
</configuration>

我的项目使用的是 logback-spring.xml ,我的文件完整内容如下:
logback-spring.xml:

<configuration debug="true"><!-- 引用Spring Boot全局配置文件中的日期格式配置项 --><springProperty scope="context" name="dateformat" source="logging.pattern.dateformat" defaultValue="yyyy-MM-dd HH:mm:ss.SSS"/><springProperty scope="context" name="APP_NAME"  source="spring.application.name"/><springProperty scope="context" name="LOG_FILE"  source="logging.file.path"/><!-- 定义颜色编码 --><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/><conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/><!-- 定义日志输出到控制台的appender --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%clr(%d{${dateformat}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%15.15t]){faint} [%-40.40logger{39}] [%X{traceId}] %clr(%msg%n){faint}%wEx</pattern></encoder></appender><!-- 开发环境配置 --><springProfile name="local | test"><root level="DEBUG"><appender-ref ref="STDOUT" /></root><!-- 开发环境专属的详细日志 --><logger name="com.tylerzhong" level="TRACE" additivity="false"><appender-ref ref="STDOUT" /></logger></springProfile><springProfile name="dev | prod"><!-- 文件日志:输出全部日志到文件 --><appender name="FILE_INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_FILE}/${APP_NAME}.log</file><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>ACCEPT</onMatch><onMismatch>ACCEPT</onMismatch></filter><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_FILE}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern><maxHistory>180</maxHistory><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>50MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{${dateformat}} [%thread] %-5level %logger{36} [%X{traceId}] - %msg%n</pattern><charset>UTF-8</charset></encoder></appender><!-- 错误日志:用于将错误日志输出到独立文件 --><appender name="FILE_ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_FILE}/error-${APP_NAME}.log</file><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_FILE}/error-${APP_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern><maxHistory>180</maxHistory><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>50MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>%d{${dateformat}} [%thread] %-5level %logger{36} [%X{traceId}] - %msg%n</pattern><charset>UTF-8</charset></encoder></appender><root level="INFO"><appender-ref ref="STDOUT" /><appender-ref ref="FILE_INFO_LOG" /><appender-ref ref="FILE_ERROR_LOG" /></root></springProfile></configuration>

关于更具体的日志输出配置,可以参考我的这篇文章《SpringBoot 项目配置日志输出》。

通过这种方式,你就可以在单体Spring Boot项目中为每个请求生成一个唯一的traceId,并通过日志输出它,从而实现在处理请求期间的所有日志条目都能关联起来的效果。这种方法不仅适用于单体应用,也可以作为理解更复杂的分布式追踪概念的基础。

这样配置之后,你在代码中打印日志的时候就会携带上 traceId 了。

 log.info("请求参数: {}", arg);

输出示例:

2025-02-26 19:25:02.187  INFO [nio-8070-exec-2] [com.tylerzhong.web.config.LoggingAspect       ] [ab85097a-6d31-44c3-bcfb-2bcc97b87ab9] 方法: TransferController.xxx(..)

当然,我们不止要将 traceId 输出到控制台,还需要将 traceId 返回给前端用户,这样用户找我们排查问题的时候,只需要给一个 traceId 给我们即可。

所以在返回的包装类中注入 traceId 返回给前端。
我的代码如下:

import lombok.Getter;
import lombok.NoArgsConstructor;
import org.slf4j.MDC;@Getter
@NoArgsConstructor
public class Result<T> {private int code;private boolean flag;private String desc;private String cause;private String traceId;private T data;public Result(int code, boolean flag, String desc) {this.code = code;this.flag = flag;this.desc = desc;}public Result(int code, boolean flag, String desc, String traceId) {this.code = code;this.flag = flag;this.desc = desc;this.traceId = traceId;}public Result(int code, boolean flag, String desc, String cause, String traceId) {this.code = code;this.flag = flag;this.desc = desc;this.cause = cause;this.traceId = traceId;}public Result(int code, boolean flag, String desc, T data, String traceId) {this.code = code;this.flag = flag;this.desc = desc;this.data = data;this.traceId = traceId;}public static <T> Result<T> success() {return new Result<>(0, true, "成功", MDC.get("traceId"));}public static <T> Result<T> success(T data) {return new Result<>(0, true,"成功", data, MDC.get("traceId"));}public static <T> Result<T> fail(int code, String desc, String cause) {return new Result<>(code, false, desc, cause, MDC.get("traceId"));}
}

返回给前端的失败示例:

{"code": 405,"flag": false,"desc": "请求方式不支持.","cause": "Request method 'POST' is not supported","traceId": "ebd77e99-361c-47b3-8569-2d321d011418","data": null
}

返回给前端的成功示例:

{"code": 0,"flag": true,"desc": "成功","cause": null,"traceId": "07a3b99c-8cf8-45dc-a758-6c7636472cab","data": {"count": 100,"name": "张三"}
}

扩展

打印日志内容,你很可能会涉及到 Spring 的 AOP 切面打印日志。可以参考这篇文章《Spring AOP 切面打印日志完整版》

相关文章:

SpringBoot项目注入 traceId 来追踪整个请求的日志链路

SpringBoot项目注入 traceId 来追踪整个请求的日志链路&#xff0c;有了 traceId&#xff0c; 我们在排查问题的时候&#xff0c;可以迅速根据 traceId 查找到相关请求的日志&#xff0c;特别是在生产环境的时候&#xff0c;用户可能只提供一个错误截图&#xff0c;我们作为开发…...

【Block总结】SAFMN,空间自适应调制与局部特征增强的协同设计|即插即用

论文信息 标题&#xff1a;Spatially-Adaptive Feature Modulation for Efficient Image Super-Resolution论文链接&#xff1a;https://arxiv.org/pdf/2302.13800代码与模型&#xff1a;https://github.com/sunny2109/SAFMN 创新点 空间自适应特征调制&#xff08;SAFM&…...

Python爬虫:一文掌握PyQuery模块

文章目录 1. PyQuery 简介2. PyQuery 的安装2.1 安装 PyQuery2.2 安装依赖库3. PyQuery 的基本使用3.1 初始化 PyQuery 对象3.2 选择元素3.3 获取元素内容3.4 遍历元素4. PyQuery 的高级用法4.1 过滤元素4.2 查找子元素4.3 获取属性值4.4 修改元素4.5 添加和删除元素4.6 遍历文…...

LearnOpenGL之Shader编程用算法绘画

———————————————————— 前序 ——————————————————— AndroidLearnOpenGL是本博主自己实现的LearnOpenGL练习集合&#xff1a; Github地址&#xff1a;GitHub - wangyongyao1989/AndroidLearnOpenGL: OpenGL基础及运用 系列文章&#xff…...

如何使用Spring Boot框架整合Redis:超详细案例教程

目录 # 为什么选择Spring Boot与Redis整合&#xff1f; 1. 更新 pom.xml 2. 配置application.yml 3. 创建 Redis 配置类 4. Redis 操作类 5. 创建控制器 6. 启动应用程序 7. 测试 # 为什么选择Spring Boot与Redis整合&#xff1f; 将Spring Boot与Redis整合可以充分利…...

算法--贪心

贪心 原理经典例题[860. 柠檬水找零](https://leetcode.cn/problems/lemonade-change/description/)[2208. 将数组和减半的最少操作次数](https://leetcode.cn/problems/minimum-operations-to-halve-array-sum/description/)[179. 最大数](https://leetcode.cn/problems/large…...

线程控制(创建、终止、等待、分离)

目录 1.前言 2.创建线程 pthread_create函数 3.线程终止 pthread_exit函数 pthread_cancel函数 4.线程等待 5.线程分离 1.前言 在Linux系统中&#xff0c;并不存在真正的线程&#xff0c;只有轻量级进程。所以&#xff0c;Linux系统只提供了操作轻量级进程的系统调用…...

【备份】php项目处理跨域请求踩坑

这都是老生常谈的东西了。我还在踩坑&#xff0c;记录一下。 我在项目入口明明写了如下代码&#xff1a; // 处理预检请求 (OPTIONS) if ($_SERVER[REQUEST_METHOD] OPTIONS) {header("Access-Control-Allow-Origin: https://xxx.vip");header("Access-Cont…...

目标检测YOLO实战应用案例100讲-面向无人机图像的小目标检测

目录 知识储备 YOLO v8无人机拍摄视角小目标检测 数据集结构 环境部署说明 安装依赖 模型训练权重和指标可视化展示 训练 YOLOv8 PyQt5 GUI 开发 主窗口代码 main_window.py 使用说明 无人机目标跟踪 一、目标跟踪的基本原理 二、常用的目标跟踪算法 基于YOLOv…...

实现 Leaflet 多类型点位标记与聚合功能的实战经验分享

在现代的地理信息系统&#xff08;GIS&#xff09;应用中&#xff0c;地图功能是不可或缺的一部分。无论是展示商业网点、旅游景点还是公共服务设施&#xff0c;地图都能以直观的方式呈现数据。然而&#xff0c;当数据量较大时&#xff0c;地图上可能会出现大量的标记点&#x…...

Linux 环境“从零”部署 MongoDB 6.0:mongosh 安装与数据操作全攻略

前提 完成linux平台部署MongoDB【部署教程】且完成mongosh的安装 由于本人使用的是6.0版本的MongoDB&#xff0c;新版本 MongoDB&#xff08;尤其是 6.0 及以上版本&#xff09;已经不再默认捆绑传统的 mongo shell&#xff0c;而改用新的 MongoDB Shell&#xff08;mongosh&am…...

深度学习五大模型:CNN、Transformer、BERT、RNN、GAN详细解析

# 深度学习五虎将&#xff1a;当CNN遇见Transformer的奇幻漂流 ## 序章&#xff1a;AI江湖的兵器谱排行 2012年&#xff0c;多伦多大学的厨房里&#xff0c;Hinton的学生们用GPU煎了个"AlexNet"荷包蛋&#xff0c;从此开启了深度学习的热兵器时代。如今五大模型各显…...

004 rocketmq集群

1、集群模式 在RocketMQ中&#xff0c;集群的部署模式是比较多的&#xff0c;有以下几种&#xff1a; public class ConsumerDemo {public static void main(String[] args) throws Exception {DefaultMQPushConsumer consumer new DefaultMQPushConsumer("test-group&qu…...

基于 Python 深度学习的电影评论情感分析可视化系统(2.0 全新升级)

基于 Python 深度学习的电影评论情感分析可视化系统&#xff0c;基于 Flask 深度学习&#xff0c;构建了一个 影评情感分析系统&#xff0c;能够 自动分析影评、计算情感趋势 并 可视化展示&#xff0c;对于电影行业具有重要参考价值&#xff01; 基于 Python 深度学习的电影评…...

Linux内核配置与构建原理

Kconfig文件 Kconfig是Linux内核中用于配置功能的脚本语言系统&#xff0c;由众多内核源码树中每个目录下的Kconfig文件组成。它定义Linux相关的配置选项层次结构和依赖关系。 menuconfig工具&#xff0c;会抓取Kconfig中的信息&#xff0c;为用户输出友好的交互式菜单选项配…...

大语言模型微调的基本概念介绍

大型语言模型&#xff08;LLMs&#xff09;正在以惊人的速度发展&#xff0c;LLM微调的潜力更是如此。大型语言模型的生命周期有几个关键步骤&#xff0c;今天我们将要介绍这个周期中最丰富、最耗时的一部分——LLM微调过程。 大语言模型的生命周期 在深入了解大型语言模型&a…...

实例分割 | yolov11训练自己的数据集

前言 因工作要求使用的都是yolov5系列的模型&#xff0c;今天学习一下最先进的yolov11&#xff0c;记录一下环境配置及训练过程。 1.项目下载及环境安装 源码位置&#xff1a;yolov11 可以看到&#xff0c;这里要求python版本大于等于3.8&#xff0c;我这里安装python3.10.…...

vue3:四嵌套路由的实现

一、前言 1、嵌套路由的含义 嵌套路由的核心思想是&#xff1a;在某个路由的组件内部&#xff0c;可以定义子路由&#xff0c;这些子路由会渲染在父路由组件的特定位置&#xff08;通常是 <router-view> 标签所在的位置&#xff09;。通过嵌套路由&#xff0c;你可以实…...

AIGC和搜索引擎的异同

AIGC&#xff08;生成式人工智能&#xff09;与搜索引擎的核心差异体现在信息处理方式和输出形态上&#xff0c;我们可以从以下维度对比&#xff1a; 一、工作原理的本质差异 信息检索机制 搜索引擎&#xff1a;基于关键词匹配&#xff08;如"中暑怎么办"→返回相关…...

ES批量查询

在 Elasticsearch 中&#xff0c;multi_search&#xff08;也称为 msearch&#xff09;是一种允许你在单个请求中执行多个搜索操作的 API。它可以显著减少网络开销&#xff0c;尤其是在需要执行多个查询时。multi_search 会将多个查询打包成一个请求发送给 Elasticsearch&#…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...

实战三:开发网页端界面完成黑白视频转为彩色视频

​一、需求描述 设计一个简单的视频上色应用&#xff0c;用户可以通过网页界面上传黑白视频&#xff0c;系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观&#xff0c;不需要了解技术细节。 效果图 ​二、实现思路 总体思路&#xff1a; 用户通过Gradio界面上…...