实现Spring Cloud Sleuth的Trace ID追踪日志
Spring Cloud Sleuth的Trace ID追踪主要用于分布式系统中实现请求链路跟踪,其核心作用包括:
请求链路串联:Trace ID在一次服务请求链路中保持并传递,将不同服务的请求跟踪信息串联起来,确保所有服务的日志关联。例如,一个请求从前端A到后端D,Trace ID在各服务中保持一致,形成完整链路。
问题定位:通过Trace ID,可以快速定位请求经过的服务单元及顺序,尤其在微服务架构中,帮助快速识别故障服务。例如,若请求在服务C失败,Trace ID可追踪到完整调用路径。
性能分析:Trace ID结合Span ID(工作单元ID)统计各服务处理延迟,区分执行时间和网络延迟,优化性能。例如,分析服务调用耗时,识别瓶颈服务。
可视化监控:与Zipkin等工具集成后,Trace ID生成的链路数据可可视化展示,提供服务拓扑图和性能指标。例如,通过Zipkin UI查看调用关系和响应时间。
日志关联:在日志系统中,Trace ID作为关键字段,通过ELK等工具可快速检索同一请求的全链路日志。例如,通过Trace ID提取所有服务的日志片段,形成完整日志链路。
综上,Trace ID是分布式系统中实现链路追踪、问题定位和性能优化的核心机制。
添加依赖
在项目的pom.xml文件中添加Spring Cloud Sleuth依赖。确保版本与Spring Boot和Spring Cloud兼容。
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
如果使用日志聚合工具如Zipkin,可以添加以下依赖:
xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
配置日志格式
在application.properties或application.yml中配置日志格式以显示Trace ID和Span ID。
properties
logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]
或使用YAML格式:
yaml
logging:
pattern:
level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
示例控制器代码
创建一个简单的控制器以验证Trace ID是否正常工作。
java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TraceController {
private static final Logger logger = LoggerFactory.getLogger(TraceController.class);
@GetMapping("/trace")
public String trace() {
logger.info("This is a log message with Trace ID");
return "Trace ID is working!";
}
}
启用Zipkin集成(可选)
如果需要将跟踪数据发送到Zipkin服务器,配置application.properties:
properties
spring.zipkin.base-url=http://localhost:9411
spring.sleuth.sampler.probability=1.0
或YAML格式:
yaml
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1.0
日志输出验证
启动应用并访问/trace端点,检查日志输出。日志中应包含Trace ID和Span ID,格式如下:
csharp
INFO [my-application,3c7a8b1e2f6d4a5b,9e1f0a3b5c7d8e2f] This is a log message with Trace ID
自定义日志字段
如果需要自定义日志字段,可以在日志配置中添加更多Sleuth提供的变量:
properties
logging.pattern.level=%d{yyyy-MM-dd HH:mm:ss} [%X{traceId:-},%X{spanId:-},%X{parentId:-}] %-5level %logger{36} - %msg%n
跨服务追踪
确保所有微服务都添加了Spring Cloud Sleuth依赖。通过HTTP调用(如RestTemplate或Feign)时,Trace ID会自动传递。
java
import org.springframework.web.client.RestTemplate;
public class SomeService {
private final RestTemplate restTemplate;
public SomeService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String callAnotherService() {
return restTemplate.getForObject("http://another-service/trace", String.class);
}
}
异步任务支持
对于异步任务,使用@Async注解时,Trace ID会自动传递。确保启用异步支持:
java
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
@Async
public void asyncMethod() {
// 异步方法中的日志会包含Trace ID
}
}
手动创建Span
如果需要手动创建Span,可以使用Tracer接口:
java
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.stereotype.Service;
@Service
public class CustomTraceService {
private final Tracer tracer;
public CustomTraceService(Tracer tracer) {
this.tracer = tracer;
}
public void customTrace() {
var span = tracer.nextSpan().name("custom-span").start();
try {
// 业务逻辑
} finally {
span.end();
}
}
}
测试验证
编写测试用例验证Trace ID是否正常工作:
java
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TraceTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testTraceId() {
String response = restTemplate.getForObject("/trace", String.class);
// 验证日志输出中是否包含Trace ID
}
}
注意事项
- 确保所有服务使用相同的日志格式配置。
- 在生产环境中,设置适当的采样率(如
spring.sleuth.sampler.probability=0.1)。 - 如果需要更复杂的追踪功能,考虑使用Zipkin或Jaeger等分布式追踪系统。