Spring Cloud Sleuth 获取当前 Trace ID
1、概览
本文将带你了解 Spring Cloud Sleuth,以及如何在 Spring Boot 中使用它进行链路追踪。
它可以在日志中添加额外有用的信息,并通过唯一链路 ID 帮助 Debug。这些操作在 Sleuth 术语中称为追踪(Trace)。它们可以由多个步骤组成,称为 Span。
例如,链路追踪可以是一个从应用中查询数据的 GET 请求。当应用处理该请求时,可以将其分割成更小的步骤:用户授权、执行数据库查询、转换响应。每个步骤都是属于同一链路追踪的唯一 Span。
在某些情况下,我们可能需要获取当前 Trace 或 Span 的 ID。例如,当发生事故时,我们可以将这些信息发送给开发团队。然后,他们就可以用它来调试和解决问题。
2、应用设置
创建一个 Spring Boot 项目,并添加 spring-cloud-starter-sleuth dependency 依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>3.1.0</version>
</dependency>
此 Starter 可与 Spring Boot 完美集成,并提供 Spring Cloud Sleuth 开箱即用的配置。
接下来,在 application.properties
文件中设置应用名称,这样就能在日志中看到该名称以及 Trace 和 Span ID:
spring.application.name=Baeldung Sleuth Tutorial
现在,创建一个 REST Controller,提供一个 GET 端点:
@RestController
public class SleuthTraceIdController {
@GetMapping("/traceid")
public String getSleuthTraceId() {
return "Hello from Sleuth";
}
}
启动应用后访问这个 API 端点 http://localhost:8080/traceid
,你可以看到响应:Hello from Sleuth
。
3、日志
在 getSleuthTraceId
方法中添加日志输出。
创建一个 Logger
,然后就可以输出日志了。
private static final Logger logger = LoggerFactory.getLogger(SleuthTraceIdController.class);
@GetMapping("/traceid")
public String getSleuthTraceId() {
logger.info("Hello with Sleuth");
return "Hello from Sleuth";
}
再次调用 API 端点并查看日志。你应该能看到类似于如下的内容:
INFO [Baeldung Sleuth Tutorial,e48f140a63bb9fbb,e48f140a63bb9fbb] 9208 --- [nio-8080-exec-1] c.b.s.traceid.SleuthTraceIdController : Hello with Sleuth
注意,应用名称位于开头的括号内。这些括号是 Sleuth 添加的。它们代表应用名称、Trace ID 和 Span ID。
4、当前 Trace 和 Span
我们可以使用上述示例来 Debug 应用中的问题,但要确定问题的起因和追踪哪个链路可能会很困难。这就是为什么要以编程方式获取当前 Trace,然后利用它进行进一步调查。
在本例中,简化了实现,只在控制台中记录 Trace ID。
首先,在 Controller 中注入 Tracer
对象,用于获取当前 Span:
@Autowired
private Tracer tracer;
@GetMapping("/traceid")
public String getSleuthTraceId() {
logger.info("Hello with Sleuth");
Span span = tracer.currentSpan();
return "Hello from Sleuth";
}
注意,如果当前没有活动 Span,则 currentSpan
方法可能返回 null
。因此,必须执行额外的检查,以确定是否可以继续使用该 Span
对象,避免 NullPointerException
。
记录当前 Trace 和 Span ID:
Span span = tracer.currentSpan();
if (span != null) {
logger.info("Trace ID {}", span.context().traceIdString());
logger.info("Span ID {}", span.context().spanIdString());
}
运行应用,并在访问 API 端点时查看这些信息。它们应该与 Sleuth 添加的括号中的 ID 相同。
5、十进制的 Trace ID 和 Span ID
还有另一种获取 Span ID 的方法,即使用 spanId
方法而不是 spanIdString
方法。它们的区别在于,后一种方法返回值的十六进制表示法,而前一种方法返回的是十进制数。
Span span = tracer.currentSpan();
if (span != null) {
logger.info("Span ID hex {}", span.context().spanIdString());
logger.info("Span ID decimal {}", span.context().spanId());
}
这两个值代表相同的数值,输出结果类似于如下:
INFO [Baeldung Sleuth Tutorial,0de46b6fcbc8da83,0de46b6fcbc8da83] 8648 --- [nio-8080-exec-3] c.b.s.traceid.SleuthTraceIdController : Span ID hex 0de46b6fcbc8da83
INFO [Baeldung Sleuth Tutorial,0de46b6fcbc8da83,0de46b6fcbc8da83] 8648 --- [nio-8080-exec-3] c.b.s.traceid.SleuthTraceIdController : Span ID decimal 1001043145087572611
同样,这也适用于 Trace ID。traceIdString
返回十六进制值,而 traceId
返回十进制值:
logger.info("Trace ID hex {}", span.context().traceIdString());
logger.info("Trace ID decimal {}", span.context().traceId());
输出结果和上面类似。首先是十六进制的 Trace ID,然后是十进制:
INFO [Baeldung Sleuth Tutorial,34ec0b8ac9d65e91,34ec0b8ac9d65e91] 7384 --- [nio-8080-exec-1] c.b.s.traceid.SleuthTraceIdController : Trace ID hex 34ec0b8ac9d65e91
INFO [Baeldung Sleuth Tutorial,34ec0b8ac9d65e91,34ec0b8ac9d65e91] 7384 --- [nio-8080-exec-1] c.b.s.traceid.SleuthTraceIdController : Trace ID decimal 3813435675195629201
6、总结
本文介绍了如何通过 Spring Cloud Sleuth 追踪 Spring Boot 中的事件,以帮助 Debug。
参考:https://www.baeldung.com/spring-cloud-sleuth-get-trace-id