Skip to content

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 实现全面可观测性。

License

Notifications You must be signed in to change notification settings

mr-box/log-tracing

Repository files navigation

log-tracing 分布式链路追踪组件

Build Status GitHub release License JitPack

概述

在微服务架构中,一个用户请求往往需要经过多个服务协同处理。当系统出现问题时,如何快速定位问题?如何追踪请求的完整调用链路?

log-tracing 是一个轻量级、低侵入的分布式链路追踪组件,通过统一的 traceId 串联起分散在各个服务中的日志,让您能够:

  • 在海量日志中快速检索出一个请求的所有相关日志
  • 清晰地看到请求在各个服务间的流转路径和调用关系
  • 快速定位问题发生在哪个服务、哪个环节

核心特性

  • 开箱即用:引入依赖即可使用,Spring Boot 自动配置
  • 自动传递:HTTP、Feign、RabbitMQ 自动传递 traceId
  • 异步支持:提供工具类和自动增强功能,解决线程池、@Async、消息队列等异步场景的链路断裂问题
  • SkyWalking 集成:与 SkyWalking 无缝集成,保持链路连续性
  • 安全可控:支持 traceId 长度限制、格式验证,防止恶意攻击
  • 灵活配置:支持自定义键名,避免与其他追踪组件冲突
  • 按需启用:支持按需启用/禁用功能模块

模块结构

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 仓库源:

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

第二步:添加组件依赖:

<dependency>
    <groupId>com.github.mr-box.log-tracing</groupId>
    <artifactId>log-tracing-spring-boot-starter</artifactId>
    <version>1.0.1</version>
</dependency>

组件会自动配置并启用以下功能:

  1. Web 请求链路追踪
  2. Feign 客户端链路追踪(如果使用了 Feign)
  3. Spring Rabbit 消息链路追踪(如果使用了 Spring Rabbit)
  4. SkyWalking 集成(如果使用了 SkyWalking Agent)

1.2 配置日志格式

logback-spring.xml 中配置日志格式,添加 traceId:

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

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 中进行配置,以下示例配置无特殊说明均为默认配置:

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 / 最上游服务

mr-box:
  tracing:
    web-interceptor:
      accept-header-trace-id: false      # 不接受客户端 traceId,防止恶意注入
      max-trace-id-length: 256
      validate-trace-id-format: false

内部微服务 - 高安全要求

mr-box:
  tracing:
    web-interceptor:
      accept-header-trace-id: true       # 接受上游服务 traceId
      max-trace-id-length: 256           # 限制长度,防止超长攻击
      validate-trace-id-format: true     # 启用格式验证,防止日志注入

内部微服务 - 默认配置

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 共存

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:

mr-box:
  tracing:
    enable-pool-task-executor-enhance: true

开启后,Spring 容器中所有的 ThreadPoolTaskExecutor Bean 都会自动支持链路追踪,无需修改代码。

增强 @Async 线程池(通过 AsyncConfigurer 配置):

如果您通过实现 AsyncConfigurer 接口来配置 @Async 的线程池:

@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;
    }
}

可以开启自动增强:

mr-box:
  tracing:
    enable-async-configurer-executor-enhance: true

开启后,@Async 注解的方法会自动传递 traceId,无需修改代码。

注意: 此配置仅对通过 AsyncConfigurer 接口配置的线程池生效。如果您使用其他方式配置 @Async(如 @Bean 方式),请使用方式一或方式二。

方式二:使用 TracedThreadPoolTaskExecutor / TracedThreadPoolExecutor

@Bean
public ThreadPoolTaskExecutor taskExecutor() {
    TracedThreadPoolTaskExecutor executor = new TracedThreadPoolTaskExecutor();
    executor.setCorePoolSize(10);
    executor.setMaxPoolSize(20);
    executor.setQueueCapacity(200);
    executor.setThreadNamePrefix("async-");
    return executor;
}

方式三:手动包装任务

// Runnable 包装
Runnable task = RunnableTraceWrapper.of(() -> {
    // 异步任务,可以获取主线程的 traceId
})
executor.execute(task);

// Callable 包装
Future<String> future = executor.submit(CallableTraceWrapper.of(() -> {
    // 业务逻辑
}));

// Consumer 包装(适用于 Stream)
list.parallelStream().forEach(ConsumerTraceWrapper.of(item -> {
    // 业务逻辑
}));

// Supplier 包装
Supplier<String> supplier = SupplierTraceWrapper.of(() -> {
   // 业务逻辑
});

// Function 包装
Function<String, String> function = FunctionTraceWrapper.of(item -> {
   // 业务逻辑
});

3.3 工具类

获取 TraceId

// 获取当前 MDC 中的 traceId
Optional<String> traceId = TraceUtils.getMDCTraceId();

// 获取或生成 traceId
String traceId = TraceUtils.getOrGenerateMDCTraceId();

设置 TraceId

// 设置 traceId
TraceUtils.setMDCTraceId("your-trace-id");

// 清理 traceId
TraceUtils.removeMDCTraceId();

4. 高级用法

4.1 自定义 TraceId 生成器

默认情况下,组件使用 SkyWalking的TID或UUID 作为 TraceId。如果需要自定义生成策略(如雪花算法、短ID、业务前缀等),可以实现 TraceIdGenerator 接口。

当存在多个生成器时,优先级顺序为:

手动设置 > Spring Bean > SPI > 默认实现

方式一:Spring Bean(推荐)

@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 文件中注册实现类

方式三:手动设置

适用于需要在运行时动态切换生成器的场景。

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 使用

推荐方式:使用支持追踪的线程池

TracedThreadPoolTaskExecutor executor = new TracedThreadPoolTaskExecutor();
executor.initialize();

CompletableFuture
    .runAsync(() -> { /* 任务1 */ }, executor)
    .thenRunAsync(() -> { /* 任务2 */ }, executor)
    .thenRun(() -> { /* 任务3 */ })
    .exceptionally(ex -> { /* 异常处理 */ return null; });

不推荐方式:手动包装所有任务

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

@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 配置示例:

<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/application.log</file>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/application.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>
    
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

5.2 服务分层配置

API Gateway:

mr-box:
  tracing:
    web-interceptor:
      accept-header-trace-id: false  # 不接受客户端 traceId

业务服务:

mr-box:
  tracing:
    web-interceptor:
      accept-header-trace-id: true   # 接受上游 traceId
      validate-trace-id-format: true # 启用格式验证
    enable-pool-task-executor-enhance: true  # 启用线程池自动增强

消息消费者:

mr-box:
  tracing:
    rabbitmq:
      enabled: true
    enable-pool-task-executor-enhance: true

6. 故障排查

6.1 traceId 没有传递

检查清单:

  1. 确认组件已启用

    mr-box:
      tracing:
        enabled: true
  2. 确认日志配置正确

    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId}] ...</pattern>
  3. 确认 MDC 键名匹配

    key-names:
      mdc-trace-id: traceId  # 与日志配置中的 %X{traceId} 匹配

6.2 异步任务没有 traceId

解决方案:

  1. 启用自动增强

    enable-pool-task-executor-enhance: true
  2. 或使用 TracedThreadPoolTaskExecutor

  3. 或手动包装任务

    executor.execute(RunnableTraceWrapper.of(() -> { ... }));

6.3 RabbitMQ 消息没有 traceId

检查清单:

  1. 确认 RabbitMQ 增强已启用

    rabbitmq:
      enabled: true
  2. 检查是否禁用了增强器

    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,组件会自动集成:

java -javaagent:/path/to/skywalking-agent.jar -jar your-app.jar

8. 贡献指南

CONTRIBUTING.md

9. 许可证

本项目采用 Apache License 2.0 许可证。

10. 联系方式


⭐ 如果这个项目对您有帮助,请给个 Star!

About

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 实现全面可观测性。

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages