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 来追踪整个请求的日志链路,有了 traceId, 我们在排查问题的时候,可以迅速根据 traceId 查找到相关请求的日志,特别是在生产环境的时候,用户可能只提供一个错误截图,我们作为开发…...
【Block总结】SAFMN,空间自适应调制与局部特征增强的协同设计|即插即用
论文信息 标题:Spatially-Adaptive Feature Modulation for Efficient Image Super-Resolution论文链接:https://arxiv.org/pdf/2302.13800代码与模型:https://github.com/sunny2109/SAFMN 创新点 空间自适应特征调制(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练习集合: Github地址:GitHub - wangyongyao1989/AndroidLearnOpenGL: OpenGL基础及运用 系列文章ÿ…...
如何使用Spring Boot框架整合Redis:超详细案例教程
目录 # 为什么选择Spring Boot与Redis整合? 1. 更新 pom.xml 2. 配置application.yml 3. 创建 Redis 配置类 4. Redis 操作类 5. 创建控制器 6. 启动应用程序 7. 测试 # 为什么选择Spring Boot与Redis整合? 将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系统中,并不存在真正的线程,只有轻量级进程。所以,Linux系统只提供了操作轻量级进程的系统调用…...
【备份】php项目处理跨域请求踩坑
这都是老生常谈的东西了。我还在踩坑,记录一下。 我在项目入口明明写了如下代码: // 处理预检请求 (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 多类型点位标记与聚合功能的实战经验分享
在现代的地理信息系统(GIS)应用中,地图功能是不可或缺的一部分。无论是展示商业网点、旅游景点还是公共服务设施,地图都能以直观的方式呈现数据。然而,当数据量较大时,地图上可能会出现大量的标记点&#x…...
Linux 环境“从零”部署 MongoDB 6.0:mongosh 安装与数据操作全攻略
前提 完成linux平台部署MongoDB【部署教程】且完成mongosh的安装 由于本人使用的是6.0版本的MongoDB,新版本 MongoDB(尤其是 6.0 及以上版本)已经不再默认捆绑传统的 mongo shell,而改用新的 MongoDB Shell(mongosh&am…...
深度学习五大模型:CNN、Transformer、BERT、RNN、GAN详细解析
# 深度学习五虎将:当CNN遇见Transformer的奇幻漂流 ## 序章:AI江湖的兵器谱排行 2012年,多伦多大学的厨房里,Hinton的学生们用GPU煎了个"AlexNet"荷包蛋,从此开启了深度学习的热兵器时代。如今五大模型各显…...
004 rocketmq集群
1、集群模式 在RocketMQ中,集群的部署模式是比较多的,有以下几种: public class ConsumerDemo {public static void main(String[] args) throws Exception {DefaultMQPushConsumer consumer new DefaultMQPushConsumer("test-group&qu…...
基于 Python 深度学习的电影评论情感分析可视化系统(2.0 全新升级)
基于 Python 深度学习的电影评论情感分析可视化系统,基于 Flask 深度学习,构建了一个 影评情感分析系统,能够 自动分析影评、计算情感趋势 并 可视化展示,对于电影行业具有重要参考价值! 基于 Python 深度学习的电影评…...
Linux内核配置与构建原理
Kconfig文件 Kconfig是Linux内核中用于配置功能的脚本语言系统,由众多内核源码树中每个目录下的Kconfig文件组成。它定义Linux相关的配置选项层次结构和依赖关系。 menuconfig工具,会抓取Kconfig中的信息,为用户输出友好的交互式菜单选项配…...
大语言模型微调的基本概念介绍
大型语言模型(LLMs)正在以惊人的速度发展,LLM微调的潜力更是如此。大型语言模型的生命周期有几个关键步骤,今天我们将要介绍这个周期中最丰富、最耗时的一部分——LLM微调过程。 大语言模型的生命周期 在深入了解大型语言模型&a…...
实例分割 | yolov11训练自己的数据集
前言 因工作要求使用的都是yolov5系列的模型,今天学习一下最先进的yolov11,记录一下环境配置及训练过程。 1.项目下载及环境安装 源码位置:yolov11 可以看到,这里要求python版本大于等于3.8,我这里安装python3.10.…...
vue3:四嵌套路由的实现
一、前言 1、嵌套路由的含义 嵌套路由的核心思想是:在某个路由的组件内部,可以定义子路由,这些子路由会渲染在父路由组件的特定位置(通常是 <router-view> 标签所在的位置)。通过嵌套路由,你可以实…...
AIGC和搜索引擎的异同
AIGC(生成式人工智能)与搜索引擎的核心差异体现在信息处理方式和输出形态上,我们可以从以下维度对比: 一、工作原理的本质差异 信息检索机制 搜索引擎:基于关键词匹配(如"中暑怎么办"→返回相关…...
ES批量查询
在 Elasticsearch 中,multi_search(也称为 msearch)是一种允许你在单个请求中执行多个搜索操作的 API。它可以显著减少网络开销,尤其是在需要执行多个查询时。multi_search 会将多个查询打包成一个请求发送给 Elasticsearch&#…...
适配多层级组织管理,科学运用 360 度反馈打造公平高效绩效文化
360度绩效反馈评估是一种从上级、下属、同事、客户等多个维度收集反馈的综合绩效评估方法,通过多源数据消除单一评价者的主观偏差,帮助企业获得更全面、客观的员工能力画像。相比传统的上级单向评价,360度反馈能将评估准确度提升40%以上&…...
短波通讯:魔术6米波
制作一个用于50MHz(6米波段)的天线,是业余无线电爱好者探索这一“魔术波段”的基础。该频段天线相对短波天线更易于制作和架设,但良好的设计对捕捉稍纵即逝的远距离传播至关重要。以下是基于不同需求的天线类型、设计要点和制作指…...
Midjourney V6玻璃渲染失效?深度解析--noharsh、--style raw与refine prompt的黄金配比公式
更多请点击: https://intelliparadigm.com 第一章:Midjourney V6玻璃渲染失效现象全景透视 Midjourney V6 在发布后显著提升了材质真实感与光照建模能力,但大量用户反馈其对玻璃、水晶、液态透明体等高折射率材质的渲染出现系统性失真&#…...
远程办公远控软件怎么选?ToDesk、向日葵、UU远程深度对比
远程办公远控软件怎么选?ToDesk、向日葵、UU远程深度对比远程办公这件事,现在很多人已经习惯了。但很多人忽略了一个问题——远程办公体验好不好,很大程度上取决于你用的远控软件怎么样。我之前帮公司选远控工具的时候,认真把市面…...
AI大模型核心:Prompt、Tool、Skill、Agent,一篇彻底搞懂它们之间的区别与实战应用!
如果你最近在用AI大模型,一定会被这四个词绕晕:Prompt、Tool、Skill、Agent。 这篇文章用最通俗的语言,一次性讲透四个概念的本质、核心区别。一、讲清楚每个概念到底是什么? 1、Prompt 本质上是人类给大模型的单次文本指令&#…...
2026年SSL证书市场便宜且安全的SSL证书调研
随着互联网安全标准的不断升级,HTTPS加密已成为网站和各类数字应用的“标配”。然而,对于广大的中小企业、个人开发者以及初创团队而言,如何在控制成本的前提下,获取一张既便宜又足够安全的SSL证书,始终是一道棘手的难…...
AI行业4大神仙岗位,0基础也能拿下?薪资直逼200万!
文科生,能进AI行业吗? 毕业做了两年行政,现在想转行,是不是来不及了? 看到AI岗位都要写代码,我连Python都没碰过,是不是没戏了? … 想一想都是问题,做一做一定会有答案&a…...
工厂实验室建设公司厂家:建不好,产品质量白搞|中南实验室建设
在工业4.0浪潮席卷全球的今天,工厂实验室早已不是传统意义上"摆几台仪器、刷几面墙"的简单工程。它是企业质量管控的第一道闸门,是工艺优化的数据引擎,更是技术创新的核心载体。从新能源电池的毫秒级安全测试,到半导体工…...
Audio Slicer:智能音频分割终极指南,告别繁琐手动剪辑
Audio Slicer:智能音频分割终极指南,告别繁琐手动剪辑 【免费下载链接】audio-slicer A simple GUI application that slices audio with silence detection 项目地址: https://gitcode.com/gh_mirrors/aud/audio-slicer 还在为音频剪辑的繁琐操作…...
别再只删node_modules了!npm run serve报错‘There is likely additional logging output above’的完整排查与修复手册
从日志溯源到根治:npm run serve报错的系统性排查指南 当你满怀期待地敲下npm run serve,却迎面撞上那句"There is likely additional logging output above"时,是否感到一阵无力?删除node_modules重装就像重启电脑——…...
