Log4j实现全局日志traceId详解

一、为何需要全局 traceId

在分布式系统中,一个请求可能会经过多个服务、多个线程。在日志中引入全局 traceId,可以让你轻松地追踪某一次请求全链路的日志,极大提升排障和分析效率。


二、实现方案总览

  1. 生成 traceId:每次请求生成唯一的 traceId(如 UUID)。
  2. 请求上下文传递 traceId:前端或上游服务发起请求时携带,或本服务自行生成,并在整个流程中传递。
  3. 日志输出 traceId:让 log4j 能在每条日志中输出 traceId,一般用MDC(Mapped Diagnostic Context)机制实现。

三、具体实现步骤(以 Java log4j2 为例)

1. 添加 log4j2 依赖

<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.x.x</version> </dependency>

2. 日志格式配置 TraceId(log4j2.xml)

在 log4j2.xml (或 log4j2.properties)中添加%X{traceId}

<PatternLayout pattern="[%d{ISO8601}] [%t] [%p] [traceId=%X{traceId}] %c{1} - %m%n"/>

3. 使用 MDC 设置和清理 TraceId

MDC是用来为被同一线程处理的日志增加上下文信息,这样这些信息可以自动加在日志里面。

生成和绑定 TraceId

【推荐:在每次请求开始时设置,请求结束后清除】

示例:

import org.apache.logging.log4j.ThreadContext; public class TraceIdUtil { public static void setTraceId() { String traceId = UUID.randomUUID().toString().replace("-", ""); ThreadContext.put("traceId", traceId); } public static void clear() { ThreadContext.remove("traceId"); } }
在 Controller 或 Filter 中设置和清理 TraceId

如 Spring Boot 项目推荐用 Filter 拦截每次 Web 请求:

@WebFilter(urlPatterns = "/*") public class TraceIdFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { String traceId = request.getHeader("X-TraceId"); if (traceId == null) { traceId = UUID.randomUUID().toString().replace("-", ""); } ThreadContext.put("traceId", traceId); chain.doFilter(request, response); } finally { ThreadContext.remove("traceId"); } } }

4. 日志打印

每次调用log.info()log.error()等,日志格式自动输出 traceId:

[2024-06-12 12:00:00.123] [main] [INFO] [traceId=acb1e2008ff94d919c0c2b761a17c234] MyService - foo started

四、分布式传递 TraceId

  • 服务间传递:前端或服务A调用服务B时,要将 traceId 作为请求头(如X-TraceId)传递,服务B读取后继续传递、写日志。
  • 多线程/异步:ThreadContext 只对当前线程有效,多线程需要手动传递 MDC 上下文,推荐工具如 MDC transmittable thread。

五、通用方案小结

  • 请求入口处生成/获取 traceId,并绑定到 MDC。
  • 日志模板加%X{traceId}占位符。
  • 记得请求结束后清除 traceId,防止线程复用产生污染。

六、补充:老版 log4j(log4j 1.x)

使用org.apache.log4j.MDC,方法类似。

七、TraceId 更好的生成和传递

  1. 生成策略

    • 可以用UUID或雪花算法。
    • 如果有调用链,可以拼接上下游 ID,或用 OpenTracing/Zipkin/SkyWalking 等分布式链路追踪工具。
  2. 传递策略

    • HTTP协议推荐用请求头,例如X-TraceId
    • MQ等异步通讯方式,将 traceId 放入消息体或消息header。
    • RPC自定义协议中,也要传递 traceId。

八、多线程与异步任务下 MDC 传递问题

1. 问题分析

log4j的MDC(ThreadContext)是线程本地变量,只对当前线程生效。如果你在主线程设置后,创建了新线程(比如用线程池、异步处理等),那么子线程默认无法感知traceId。

2. 解决方案

a. 手动传递MDC内容

在开启子线程、异步任务前,先获取主线程的MDC内容,然后在子线程恢复:

Map<String, String> mdcContext = ThreadContext.getImmutableContext(); // 获取主线程的MDC new Thread(() -> { ThreadContext.putAll(mdcContext); // 传递到子线程 // log输出时就有traceId了 }).start();

异步框架(如CompletableFuture)同理。

b. 使用中间件或MDC工具

推荐使用阿里开源 TransmittableThreadLocal,它能够自动让ThreadLocal(包括MDC)在线程池/异步任务传递。

示例,配合Spring:

// 引入依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> <version>2.x.x</version> </dependency>

使用TTL提供的线程池包装,例如:

import com.alibaba.ttl.threadpool.TtlExecutors; ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(10)); // 用ttlExecutorService提交异步任务就能自动传递MDC上下文

这样异步日志也能打出正确的traceId。

c. Spring Sleuth/分布式链路追踪工具自动解决

Spring Cloud Sleuth、zipkin、skywalking可以自动在分布式调用和线程异步间传递traceId,无需自己维护MDC。


九、TraceId在微服务间的跨服务传递

  1. 前端到网关:建议前端/移动端生成唯一traceId(也叫requestId),作为请求头带着,Nginx等网关可以自动补齐。
  2. 网关到后端服务:网关会读取和透传traceId,服务收到后可写入MDC,继续向下游服务传递。
  3. 跨服务调用:在Feign/RestTemplate/HTTP Client等发起请求时,把traceId作为header带上。服务间只需要在入口Filter把traceId写入MDC,日志和下游都自动带上。

示例:

// 发起下游调用时,透传TraceId HttpHeaders headers = new HttpHeaders(); headers.add("X-TraceId", ThreadContext.get("traceId"));

十、日志查找的技巧和工具

  • 保证全链路所有服务日志都包含traceId,可用grep traceId=xxx一步查到完整链路。
  • 推荐配合ELK/Splunk/Skywalking/Zipkin等工具,可自动聚合traceId相同的日志,提供链路可视化查询。

十一、完整代码示例整理

对于完整Spring Boot集成,其实很简单:

  1. 创建一个拦截器/filter,一律set/clear TraceId到MDC。
  2. 日志格式配置好,比如:[traceId=%X{traceId}]
  3. 发起子线程或下游HTTP请求时把traceId带过去。

Filter 示例:

@Component public class TraceIdFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { String traceId = ((HttpServletRequest)request).getHeader("X-TraceId"); if (traceId == null) { traceId = UUID.randomUUID().toString().replace("-", ""); } ThreadContext.put("traceId", traceId); chain.doFilter(request, response); } finally { ThreadContext.remove("traceId"); } } }

十二、常见问题

  1. traceId丢失:线程池异步没传递、服务没透传都可能丢失,要关注这些点。
  2. traceId污染:未及时清理,导致协程/线程池任务复用,traceId混乱。一定要在请求结束/线程结束后ThreadContext.remove("traceId")
  3. 性能问题:MDC本身很轻量,但频繁操作还是建议简洁高效,特别是高并发场景。

总结

log4j下全局traceId最佳实践:

  • 请求入口统一生成/获取/存放到MDC
  • 日志格式加%X{traceId}
  • 子线程/异步场景主动传递MDC或用TTL
  • 服务间调用按约定自动透传traceId
  • 配合检索工具,链路聚合,定位效率极高

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1159519.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多线程与并发-知识总结1

一、run()和start()方法的区别&#xff1f;1、核心区别&#xff1a;是否创建了线程1.1、start()方法&#xff1a;用于创建并启动一个新的独立子线程调用start()时&#xff0c;JVM 会为该 Thread 实例分配新的线程资源&#xff08;脱离当前调用线程&#xff09;&#xff0c;将线…

Java实习模拟面试|字节跳动业务中台后端校招一面面经:Kafka vs RabbitMQ、死锁避免、TCP握手与链表翻转深度解析

Java实习模拟面试&#xff5c;字节跳动业务中台后端校招一面面经&#xff1a;Kafka vs RabbitMQ、死锁避免、TCP握手与链表翻转深度解析关键词&#xff1a;字节跳动校招&#xff5c;业务中台后端&#xff5c;Kafka vs MQ&#xff5c;死锁条件&#xff5c;线程池实现&#xff5c…

Java实习模拟面试|上海禾赛科技后端实习一面面经:高并发数据去重、事务与MQ一致性、反射争议与缓存选型深度解析

Java实习模拟面试&#xff5c;上海禾赛科技后端实习一面面经&#xff1a;高并发数据去重、事务与MQ一致性、反射争议与缓存选型深度解析关键词&#xff1a;禾赛科技后端实习&#xff5c;Java高并发&#xff5c;消息可靠性&#xff5c;事务传播行为&#xff5c;Redis vs 本地缓存…

深度学习毕设选题推荐:基于python-CNN训练识别蔬菜是否新鲜基于机器学习python-CNN训练识别蔬菜是否新鲜

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

Java实习模拟面试|字节跳动TTS后端校招二面面经:WaitGroup性能优化、分布式锁实现、线程安全LRU与Optional实战深度解析

Java实习模拟面试&#xff5c;字节跳动TTS后端校招二面面经&#xff1a;WaitGroup性能优化、分布式锁实现、线程安全LRU与Optional实战深度解析关键词&#xff1a;字节跳动TTS后端&#xff5c;WaitGroup原理&#xff5c;分布式锁&#xff5c;SETNX&#xff5c;线程安全LRU&…

9个降aigc工具推荐,本科生高效避坑指南

9个降aigc工具推荐&#xff0c;本科生高效避坑指南 AI降重工具&#xff1a;高效避坑的得力助手 在当今学术写作中&#xff0c;越来越多的本科生开始接触到AI辅助写作工具&#xff0c;但随之而来的AIGC率过高、查重率超标等问题也让人头疼。如何在保持原文语义和逻辑的基础上&am…

大模型黑箱揭秘:从分词到输出的全流程解析(程序员必看)

本文详细解析了大语言模型从文本输入到语言输出的完整工作流程&#xff0c;包括分词与嵌入、Transformer架构与自注意力机制、位置编码等核心技术。文章以通俗易懂的方式解释了文本如何转换为矩阵形式&#xff0c;模型如何理解上下文关系&#xff0c;以及如何将高维向量"翻…

【课程设计/毕业设计】基于python-CNN训练识别蔬菜是否新鲜基于python-CNN深度学习训练识别蔬菜是否新鲜

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

收藏!无GPU也能做的大模型项目,3个零算力落地方案+完整学习路线,简历不再空白

文章介绍3个无需GPU算力即可落地的大模型项目&#xff1a;智能客服机器人(DifyRAG)、多Agent论文精读助手(LangChain免费API)和个性化文案生成系统(PromptOllama)。这些项目通过Prompt工程和开源工具实现&#xff0c;重点在于解决实际问题的能力而非单纯堆算力。同时提供AI大模…

深度学习计算机毕设之基于python-CNN卷神经网络训练识别蔬菜是否新鲜基于python-CNN训练识别蔬菜是否新鲜

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

收藏!面试必问:对称量化与非对称量化核心区别+实战选型指南

面试官&#xff1a;“你对量化&#xff08;Quantization&#xff09;有深入了解吗&#xff1f;能不能详细说说非对称量化和对称量化的核心区别&#xff0c;以及实际应用中的选择逻辑&#xff1f;” 这道题堪称算法岗、部署岗面试的“高频送分题”——既考察你对深度学习底层原理…

深度学习毕设项目:基于python的识别蔬菜是否新鲜基于python-CNN训练识别蔬菜是否新鲜

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

Qwen2.5-VL大模型深度解析:从视觉感知到视频理解的全方位技术指南

Qwen2.5-VL模型通过原生动态分辨率ViT、Window Attention和高效Patch Merger技术解决了高分辨率输入的计算不可扩展性问题&#xff1b;采用绝对坐标建模和Multimodal RoPE实现了真实尺度感知和绝对时间对齐&#xff1b;三阶段预训练范式逐步构建视觉表示、跨模态对齐和长上下文…

大模型新人逆袭指南:从零到Offer的实战路径,项目经验+面试迭代双轮驱动

文章面向大模型领域新人&#xff0c;提出两大入行建议&#xff1a;一是先完成2-3个完整项目作为敲门砖&#xff0c;完成度比完美度更重要&#xff1b;二是通过"随机梯度下降"方式学习八股文&#xff0c;即面试-反馈-学习的循环迭代提升能力。作者强调行动的重要性&am…

Node.js用spawn流式读取子进程输出

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Node.js流式处理子进程输出&#xff1a;构建高效实时数据管道的终极指南目录Node.js流式处理子进程输出&#xff1a;构建高效实时…

AI产品经理与普通产品经理的区别:不止懂算法,更要培养AI思维_大模型产品经理成长路线,AI大模型产品经理从零基础到进阶

文章阐述了AI产品经理的核心竞争力在于AI思维而非仅懂算法&#xff0c;详细介绍了人工智能产业链三层结构(基础层、技术层、应用层)&#xff0c;以及AI产品经理的四象限分类(突破型、创新型、应用型、普及型)。强调AI产品设计需前端简单后端复杂&#xff0c;技术成熟度和业务渗…

《创业之路》-853- 商业模式创新、技术创新的比较?

商业模式创新与技术创新是企业实现竞争优势和价值增长的两大核心驱动力。它们常常并行发生&#xff0c;有时相互促进&#xff0c;但本质不同、路径各异。理解两者的异同、适用场景与协同关系&#xff0c;对企业家、投资者和管理者至关重要。一、基本定义概念定义商业模式创新&a…

计算机深度学习毕设实战-基于卷积神经网络识别花卉基于python_CNN卷积神经网络识别花卉

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

从参数竞赛到场景落地,收藏级干货助程序员和小白全面掌握AI大模型市场

文章介绍了2025年中国AI大模型市场规模达498.57亿元&#xff0c;年均增速98.12%&#xff0c;形成"科技巨头技术新贵垂直深耕者"的竞争格局。分析了技术演进路径、垂直领域应用案例、头部企业策略&#xff0c;并展望了2026年的发展机遇与挑战。核心观点是AI大模型已从…

国外的文献资料在哪里查等相关问题解答

刚开始做科研的时候&#xff0c;我一直以为&#xff1a; 文献检索就是在知网、Google Scholar 里反复换关键词。 直到后来才意识到&#xff0c;真正消耗精力的不是“搜不到”&#xff0c;而是—— 你根本不知道最近这个领域发生了什么。 生成式 AI 出现之后&#xff0c;学术检…