在 Spring Boot 中实现基于 TraceId 的日志链路追踪
1 前言
1.1 什么是 TraceId?
TraceId
是一个唯一的标识符,用于跟踪分布式系统中的请求。每个请求从客户端发起到服务端处理,再到可能的多个微服务调用,都会携带这个 TraceId
,以便在整个请求链路中进行追踪和调试。
1.2 日志链路追踪的意义
日志链路追踪可以帮助开发者:
- 快速定位问题:通过
TraceId
关联所有相关日志,快速找到问题的根源。 - 性能分析:分析请求在各个服务中的耗时,优化性能瓶颈。
- 监控系统状态:实时监控系统的运行状态,确保系统的稳定性和可靠性。
1.3 适用场景
- 微服务架构:多个服务之间的调用需要追踪。
- 分布式系统:跨多个节点的请求需要追踪。
- 复杂业务流程:需要追踪请求在各个步骤中的处理情况。
2 环境准备
2.1 Spring Boot 版本要求
本文基于 Spring Boot 2.7.x 版本进行编写,其他版本可能需要调整依赖和配置。
2.2 引入依赖(Sleuth 或 MDC)
2.2.1 使用 Sleuth
Sleuth 是 Spring Cloud Sleuth 的一部分,可以自动为每个请求生成 TraceId
和 SpanId
,并将其注入到日志中。
在 pom.xml
中添加以下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
2.2.2 使用 MDC
MDC(Mapped Diagnostic Context)是 Logback 提供的一个工具,可以将上下文信息(如 TraceId
)绑定到当前线程,方便在日志中输出。
在 pom.xml
中添加以下依赖:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
2.3 配置日志格式
2.3.1 使用 Sleuth
Sleuth 默认会将 TraceId
和 SpanId
注入到日志中,无需额外配置。
2.3.2 使用 MDC
在 logback-spring.xml
中配置日志格式,添加 %X{traceId}
以输出 TraceId
:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - [%X{traceId}] %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
3 实现步骤
3.1 自动生成 TraceId
3.1.1 使用 Sleuth 自动生成 TraceId
Sleuth 会自动为每个请求生成 TraceId
和 SpanId
,无需额外代码。
3.1.2 自定义 TraceId 生成逻辑
如果需要自定义 TraceId
生成逻辑,可以实现 TraceIdProvider
接口:
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.Tracer.TraceIdProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.UUID;
@Configuration
public class TraceIdConfig {
@Bean
public TraceIdProvider traceIdProvider() {
return new TraceIdProvider() {
@Override
public String nextTraceId() {
return UUID