# log-tracing **Repository Path**: mrbox/log-tracing ## Basic Information - **Project Name**: log-tracing - **Description**: Zero-dependency tracing library that correlates logs across HTTP, Feign, RabbitMQ, and async executions using unified traceId. With SkyWalking integration for microservices observability. / Spring Boot 微服务零依赖追踪库,通过统一 traceId 关联 HTTP、Feign、RabbitMQ 和异步执行日志,集成 SkyWalking 实现全面可观测性。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-01-28 - **Last Updated**: 2026-01-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: 微服务, 接口日志, RabbitMQ, Skywalking, traceid ## README # log-tracing 分布式链路追踪组件 ![Build Status](https://github.com/mr-box/log-tracing/actions/workflows/ci.yml/badge.svg) [![GitHub release](https://img.shields.io/github/release/mr-box/log-tracing.svg)](https://github.com/mr-box/log-tracing/releases) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![JitPack](https://jitpack.io/v/mr-box/log-tracing.svg)](https://jitpack.io/#mr-box/log-tracing) ## 概述 在微服务架构中,一个用户请求往往需要经过多个服务协同处理。当系统出现问题时,如何快速定位问题?如何追踪请求的完整调用链路? **log-tracing** 是一个轻量级、低侵入的分布式链路追踪组件,通过统一的 traceId 串联起分散在各个服务中的日志,让您能够: - 在海量日志中快速检索出一个请求的所有相关日志 - 清晰地看到请求在各个服务间的流转路径和调用关系 - 快速定位问题发生在哪个服务、哪个环节 ### 核心特性 - **开箱即用**:引入依赖即可使用,Spring Boot 自动配置 - **自动传递**:HTTP、Feign、RabbitMQ 自动传递 traceId - **异步支持**:提供工具类和自动增强功能,解决线程池、`@Async`、消息队列等异步场景的链路断裂问题 - **SkyWalking 集成**:与 SkyWalking 无缝集成,保持链路连续性 - **安全可控**:支持 traceId 长度限制、格式验证,防止恶意攻击 - **灵活配置**:支持自定义键名,避免与其他追踪组件冲突 - **按需启用**:支持按需启用/禁用功能模块 ### 模块结构 ```text log-tracing ├── log-tracing-core # 核心逻辑模块 │ ├── consts # 常量与枚举定义 │ ├── enhancer # 外部组件增强逻辑 │ │ └── rabbit # RabbitMQ 链路传递增强(支持 MDC 与 SkyWalking) │ ├── generator # TraceId 生成策略接口及默认实现 │ ├── interceptor # 拦截器(Feign 客户端、WebService) │ ├── toolkit # 链路追踪工具集 │ │ ├── TracedThreadPoolExecutor # 支持链路传递的 Java 原生线程池 │ │ ├── TracedThreadPoolTaskExecutor # 支持链路传递的 Spring 线程池 │ │ └── XxxTraceWrapper # 函数式接口装饰器(Runnable, Callable, etc.) │ └── util # 工具类(MDC 操作、SkyWalking 状态检测等) ├── log-tracing-spring-boot-autoconfigure # 自动配置模块 │ ├── config # 各功能模块的条件装配配置 │ ├── processor # Bean 后置处理器(用于自动增强线程池、@Async 等) │ └── TracingProperties # 属性配置类 └── log-tracing-spring-boot-starter # 启动器模块(快速引入依赖) ``` ### 技术栈 - Java 8+ - Spring Boot 2.7.x - Spring Framework 5.3.x - SkyWalking 9.3.0(可选) - RabbitMQ(可选) - Feign(可选) ## 1. 快速开始 ### 1.1 引入依赖 本组件通过 JitPack 发布。 **第一步**:在项目根目录的 `pom.xml` 中添加 JitPack 仓库源: ```xml jitpack.io https://jitpack.io ``` **第二步**:添加组件依赖: ```xml com.github.mr-box.log-tracing log-tracing-spring-boot-starter 1.0.0 ``` 组件会自动配置并启用以下功能: 1. Web 请求链路追踪 2. Feign 客户端链路追踪(如果使用了 Feign) 3. Spring Rabbit 消息链路追踪(如果使用了 Spring Rabbit) 4. SkyWalking 集成(如果使用了 SkyWalking Agent) ### 1.2 配置日志格式 在 `logback-spring.xml` 中配置日志格式,添加 traceId: ```xml %d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] %-5level %logger{36} - %msg%n ``` ### 1.3 验证效果 启动应用后,查看日志,您会看到每条日志都包含了 traceId: ``` 2024-01-23 10:30:15.123 [c466ca11-71c9-4dff-9fbe-d0471d421524] INFO c.e.UserService - 处理用户请求 2024-01-23 10:30:15.234 [c466ca11-71c9-4dff-9fbe-d0471d421524] INFO c.e.OrderService - 创建订单 ``` ## 2. 配置说明 ### 2.1 配置总览 | 配置项 | 默认值 | 说明 | |--------|--------|------| | `enabled` | `true` | 组件总开关 | | `enable-pool-task-executor-enhance` | `false` | 是否自动增强所有 ThreadPoolTaskExecutor | | `enable-async-configurer-executor-enhance` | `false` | 是否自动增强通过 AsyncConfigurer 配置的 @Async 线程池 | | `web-interceptor.accept-header-trace-id` | `true` | 是否接受请求头中的 traceId | | `web-interceptor.max-trace-id-length` | `256` | traceId 最大长度 | | `web-interceptor.validate-trace-id-format` | `false` | 是否验证 traceId 格式 | | `rabbitmq.enabled` | `true` | 是否启用 RabbitMQ 增强 | | `key-names.mdc-trace-id` | `traceId` | MDC 中的键名 | | `key-names.http-header-trace-id` | `X-TraceId` | HTTP Header 中的键名 | | `key-names.mq-header-trace-id` | `mdc-trace-id` | MQ Header 中的键名 | ### 2.2 完整配置示例 在 `application.yml` 中进行配置,以下示例配置无特殊说明均为默认配置: ```yaml mr-box: tracing: # ========== 基础配置 ========== # 组件总开关,默认开启 enabled: true # 是否自动增强所有 ThreadPoolTaskExecutor Bean(默认:false) # 开启后,Spring 容器中所有的 ThreadPoolTaskExecutor 都会自动支持链路追踪 enable-pool-task-executor-enhance: false # 是否自动增强通过 AsyncConfigurer 配置的 @Async 线程池(默认:false) # 开启后,通过实现 AsyncConfigurer 接口配置的 @Async 方法会自动传递 traceId # 注意:仅对通过 AsyncConfigurer 方式配置的线程池生效,不影响其他配置方式 enable-async-configurer-executor-enhance: false # ========== 追踪ID键名配置 ========== # 用于避免与其他追踪组件(Sleuth、SkyWalking、OpenTelemetry)冲突 key-names: # MDC中的trace id键名(默认:traceId) mdc-trace-id: traceId # HTTP请求头、响应头中的trace id键名(默认:X-TraceId) http-header-trace-id: X-TraceId # MQ消息header中的trace id键名(默认:mdc-trace-id) mq-header-trace-id: mdc-trace-id # ========== Web拦截器配置 ========== web-interceptor: # 是否接受请求头中的 traceId(默认:true) # true: 从请求头中读取 traceId(适用于内部微服务) # false: 忽略请求头中的 traceId,总是生成新的(适用于 最上游服务/API Gateway) accept-header-trace-id: true # traceId 最大长度限制(默认:256) # 超过此长度将被截断并记录警告日志 # 设置为 0 或负数表示不限制长度 max-trace-id-length: 256 # 是否启用 traceId 格式验证(默认:false) # true: 只接受符合格式规范的 traceId(字母、数字、中划线、下划线、点号) # false: 不验证格式 # 建议:面向客户端的服务且 accept-header-trace-id=true 时,推荐启用 validate-trace-id-format: false # ========== RabbitMQ配置 ========== rabbitmq: # 是否启用 RabbitMQ 的链路追踪增强(默认:true) enabled: true # 禁用的增强器名称列表(默认:空) # 可选值:MDC, SkyWalking(不区分大小写) disable-processors: [] ``` ### 2.3 Web 拦截器安全配置 针对不同的服务类型,推荐使用不同的安全配置: #### API Gateway / 最上游服务 ```yaml mr-box: tracing: web-interceptor: accept-header-trace-id: false # 不接受客户端 traceId,防止恶意注入 max-trace-id-length: 256 validate-trace-id-format: false ``` #### 内部微服务 - 高安全要求 ```yaml mr-box: tracing: web-interceptor: accept-header-trace-id: true # 接受上游服务 traceId max-trace-id-length: 256 # 限制长度,防止超长攻击 validate-trace-id-format: true # 启用格式验证,防止日志注入 ``` #### 内部微服务 - 默认配置 ```yaml mr-box: tracing: web-interceptor: accept-header-trace-id: true max-trace-id-length: 256 validate-trace-id-format: false ``` ### 2.4 追踪ID键名自定义 为了避免与其他追踪组件冲突(如 Sleuth ),组件提供了自定义键名的功能,支持自定义键名: #### 与 Sleuth 共存 ```yaml mr-box: tracing: key-names: http-header-trace-id: X-TraceId ``` **注意事项:** - 修改键名后,需要确保所有服务使用相同的配置 - 日志配置中的 MDC 键名需要同步修改 - 建议在项目初期就确定键名 ## 3. 功能详解 ### 3.1 自动传递场景 组件会在以下场景自动传递 traceId: | 场景 | 说明 | 配置要求 | |------|------|----------| | HTTP 请求 | Web 请求自动传递 | 默认启用 | | Feign 调用 | Feign 客户端自动传递 | 默认启用 | | RabbitMQ 消息 | 消息生产和消费自动传递 | 默认启用 | | SkyWalking | 与 SkyWalking 集成 | 需要 SkyWalking Agent | ### 3.2 异步场景支持 #### 方式一:自动增强(推荐) **增强所有 ThreadPoolTaskExecutor:** ```yaml mr-box: tracing: enable-pool-task-executor-enhance: true ``` 开启后,Spring 容器中所有的 `ThreadPoolTaskExecutor` Bean 都会自动支持链路追踪,无需修改代码。 **增强 @Async 线程池(通过 AsyncConfigurer 配置):** 如果您通过实现 `AsyncConfigurer` 接口来配置 `@Async` 的线程池: ```java @Configuration @EnableAsync public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.initialize(); return executor; } } ``` 可以开启自动增强: ```yaml mr-box: tracing: enable-async-configurer-executor-enhance: true ``` 开启后,`@Async` 注解的方法会自动传递 traceId,无需修改代码。 **注意:** 此配置仅对通过 `AsyncConfigurer` 接口配置的线程池生效。如果您使用其他方式配置 `@Async`(如 `@Bean` 方式),请使用方式一或方式二。 #### 方式二:使用 TracedThreadPoolTaskExecutor / TracedThreadPoolExecutor ```java @Bean public ThreadPoolTaskExecutor taskExecutor() { TracedThreadPoolTaskExecutor executor = new TracedThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.setQueueCapacity(200); executor.setThreadNamePrefix("async-"); return executor; } ``` #### 方式三:手动包装任务 ```java // Runnable 包装 Runnable task = RunnableTraceWrapper.of(() -> { // 异步任务,可以获取主线程的 traceId }) executor.execute(task); // Callable 包装 Future future = executor.submit(CallableTraceWrapper.of(() -> { // 业务逻辑 })); // Consumer 包装(适用于 Stream) list.parallelStream().forEach(ConsumerTraceWrapper.of(item -> { // 业务逻辑 })); // Supplier 包装 Supplier supplier = SupplierTraceWrapper.of(() -> { // 业务逻辑 }); // Function 包装 Function function = FunctionTraceWrapper.of(item -> { // 业务逻辑 }); ``` ### 3.3 工具类 #### 获取 TraceId ```java // 获取当前 MDC 中的 traceId Optional traceId = TraceUtils.getMDCTraceId(); // 获取或生成 traceId String traceId = TraceUtils.getOrGenerateMDCTraceId(); ``` #### 设置 TraceId ```java // 设置 traceId TraceUtils.setMDCTraceId("your-trace-id"); // 清理 traceId TraceUtils.removeMDCTraceId(); ``` ## 4. 高级用法 ### 4.1 自定义 TraceId 生成器 默认情况下,组件使用 SkyWalking的TID或UUID 作为 TraceId。如果需要自定义生成策略(如雪花算法、短ID、业务前缀等),可以实现 `TraceIdGenerator` 接口。 当存在多个生成器时,优先级顺序为: ``` 手动设置 > Spring Bean > SPI > 默认实现 ``` **方式一:Spring Bean(推荐)** ```java @Configuration public class TracingConfig { @Bean public TraceIdGenerator traceIdGenerator() { // 使用雪花算法生成数字ID return new SnowflakeTraceIdGenerator(1L, 1L); // 或使用短ID(16位随机字符串) // return new ShortIdGenerator(); // 或使用自定义格式 // return () -> "TRC-" + System.currentTimeMillis() + "-" + UUID.randomUUID().toString().substring(0, 8); } } ``` **方式二:SPI 机制** 1. 实现 `TraceIdGenerator` 接口 2. 在 `META-INF/services/com.github.mrbox.logtracing.core.generator.TraceIdGenerator` 文件中注册实现类 **方式三:手动设置** 适用于需要在运行时动态切换生成器的场景。 ```java package com.example; import com.github.mrbox.logtracing.core.generator.TraceIdGeneratorHolder; import com.example.tracing.CustomTraceIdGenerator; public class Application { public static void main(String[] args) { // 在应用启动时手动设置生成器 TraceIdGeneratorHolder.setGenerator(new CustomTraceIdGenerator()); // 启动 Spring Boot 应用 SpringApplication.run(Application.class, args); } } ``` ### 4.2 CompletableFuture 使用 **推荐方式:使用支持追踪的线程池** ```java TracedThreadPoolTaskExecutor executor = new TracedThreadPoolTaskExecutor(); executor.initialize(); CompletableFuture .runAsync(() -> { /* 任务1 */ }, executor) .thenRunAsync(() -> { /* 任务2 */ }, executor) .thenRun(() -> { /* 任务3 */ }) .exceptionally(ex -> { /* 异常处理 */ return null; }); ``` **不推荐方式:手动包装所有任务** ```java CompletableFuture .runAsync(RunnableTraceWrapper.of(() -> { /* 任务1 */ })) .thenRunAsync(RunnableTraceWrapper.of(() -> { /* 任务2 */ })) .thenRun(RunnableTraceWrapper.of(() -> { /* 任务3 */ })) .exceptionally(FunctionTraceWrapper.of(ex -> { return null; })); ``` ### 4.3 RabbitMQ 自定义配置 如果需要自定义 RabbitMQ 的线程池,注意不要使用 `TracedThreadPoolTaskExecutor` / `TracedThreadPoolExecutor`: ```java @Bean public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory( ConnectionFactory connectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(connectionFactory); // ❌ 错误:使用增强的 TracedThreadPoolTaskExecutor // ✅ 正确:使用普通的 ThreadPoolTaskExecutor ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); // ... 其他配置 executor.initialize(); factory.setTaskExecutor(executor); return factory; } ``` **原因:** 如果使用了`TracedXxxExecutor`,每个消费者线程都会创建一个异步链路且一直复用。 虽然当开启SkyWalking增强时会在首次消费时终止该链路,仍建议尽量避免使用。 ## 5. 最佳实践 ### 5.1 日志配置 **Logback 配置示例:** ```xml %d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] [%thread] %-5level %logger{36} - %msg%n logs/application.log %d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] [%thread] %-5level %logger{36} - %msg%n logs/application.%d{yyyy-MM-dd}.log 30 ``` ### 5.2 服务分层配置 **API Gateway:** ```yaml mr-box: tracing: web-interceptor: accept-header-trace-id: false # 不接受客户端 traceId ``` **业务服务:** ```yaml mr-box: tracing: web-interceptor: accept-header-trace-id: true # 接受上游 traceId validate-trace-id-format: true # 启用格式验证 enable-pool-task-executor-enhance: true # 启用线程池自动增强 ``` **消息消费者:** ```yaml mr-box: tracing: rabbitmq: enabled: true enable-pool-task-executor-enhance: true ``` ## 6. 故障排查 ### 6.1 traceId 没有传递 **检查清单:** 1. 确认组件已启用 ```yaml mr-box: tracing: enabled: true ``` 2. 确认日志配置正确 ```xml %d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] ... ``` 3. 确认 MDC 键名匹配 ```yaml key-names: mdc-trace-id: traceId # 与日志配置中的 %X{traceId} 匹配 ``` ### 6.2 异步任务没有 traceId **解决方案:** 1. 启用自动增强 ```yaml enable-pool-task-executor-enhance: true ``` 2. 或使用 `TracedThreadPoolTaskExecutor` 3. 或手动包装任务 ```java executor.execute(RunnableTraceWrapper.of(() -> { ... })); ``` ### 6.3 RabbitMQ 消息没有 traceId **检查清单:** 1. 确认 RabbitMQ 增强已启用 ```yaml rabbitmq: enabled: true ``` 2. 检查是否禁用了增强器 ```yaml rabbitmq: disable-processors: [] # 确保为空 ``` ## 7. 常见问题 ### Q1: 与 Spring Cloud Sleuth 有什么区别? **A:** 两者的侧重点完全不同。**log-tracing** 专注于解决“日志串联”问题,特别是针对 **Spring RabbitMQ 消费者端 SkyWalking 链路断裂** 的痛点进行了深度增强。 | 维度 | log-tracing | Spring Cloud Sleuth | | :--- | :--- | :--- | | **核心定位** | **轻量级日志增强工具** | **全功能链路追踪方案** | | **RabbitMQ 支持** | **深度增强**
在串联业务日志的基础上,重点解决了 **Consumer 端的 SkyWalking 链路断裂问题** | **基础支持**
支持生产/消费者日志串联,但**无法解决**异步消息消费导致的 SkyWalking 链路断开 | | **SkyWalking 集成** | **深度协同**
核心目标是保证 **SkyWalking 链路在异步/消息场景下的连续性**,同时也支持复用其 TraceId | **独立体系**
通常作为独立的追踪体系运行,无法解决 SkyWalking 的链路连续性痛点 | | **复杂度与性能** | **极低开销**
仅操作 MDC 和 Header,适合对性能要求严苛且只需日志串联的场景 | **中等开销**
包含 Span 管理、采样、耗时统计及数据上报,依赖较重 | **核心价值点:** 如果您在使用 SkyWalking 时发现 **RabbitMQ 消费者端链路断裂**,或者觉得 Sleuth 太重、只想纯粹地串联日志,**log-tracing** 是更精准的选择。它能完美补齐 APM 工具(如 SkyWalking)在消息队列场景下的“断链”短板。 ### Q2: 是否支持 Spring Boot 3.x? **A:** 当前版本基于 Spring Boot 2.7.x,Spring Boot 3.x 暂不支持。 ### Q3: 是否支持 RocketMQ/Kafka? **A:** 当前版本只支持 RabbitMQ,RocketMQ/Kafka 支持计划在后续版本中添加。 ### Q4: 如何与 SkyWalking 集成? **A:** 只需在启动时添加 SkyWalking Agent,组件会自动集成: ```bash java -javaagent:/path/to/skywalking-agent.jar -jar your-app.jar ``` ## 8. 贡献指南 [CONTRIBUTING.md](CONTRIBUTING.md) ## 9. 许可证 本项目采用 [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) 许可证。 ## 10. 联系方式 - **Issues**: [GitHub Issues](https://github.com/mr-box/log-tracing/issues) - **Email**: wel.come@qq.com --- **⭐ 如果这个项目对您有帮助,请给个 Star!**