1. Overview
1.概述
In this article, we’ll take a look at Spring Cloud Sleuth and see how we can use it for tracing in Spring Boot. It adds useful, extra information to our logs and makes it easier to debug actions by adding unique identifiers to them. These actions are called traces in Sleuth terminology. They can consist of several steps, called spans.
在本文中,我们将了解Spring Cloud Sleuth,并了解我们如何在Spring Boot中使用它进行跟踪。它为我们的日志添加了有用的、额外的信息,并通过为动作添加唯一的标识符,使我们更容易调试动作。这些动作在Sleuth的术语中被称为跟踪。它们可以由几个步骤组成,称为跨度。
For example, a trace can be a GET request that is querying data from our application. When our application processes the request, it can be split up into smaller steps: user authorization, executing the database query, transforming the response. Each of these steps is a unique span belonging to the same trace.
例如,一个跟踪可以是一个GET请求,该请求正在从我们的应用程序中查询数据。当我们的应用程序处理这个请求时,它可以被分割成更小的步骤:用户授权,执行数据库查询,转换响应。这些步骤中的每一步都是属于同一个跟踪的唯一跨度。
In some cases, we might want to get the ID of the current trace or span. For instance, we could send these to the development team when there is an incident. Then they can use this to debug and fix the problem.
在某些情况下,我们可能想获得当前跟踪或跨度的ID。例如,当有事件发生时,我们可以把这些发送给开发团队。然后他们就可以用这个来调试和解决这个问题。
2. Application Setup
2.应用程序的设置
Let’s start by creating a Spring Boot project and adding the spring-cloud-starter-sleuth dependency:
让我们首先创建一个Spring Boot项目,并添加spring-cloud-starter-sleuth依赖项:。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>3.1.0</version>
</dependency>
This starter dependency integrates well with Spring Boot and provides the necessary configuration to start using Spring Cloud Sleuth.
这个启动器依赖性与Spring Boot很好地整合,并提供必要的配置以开始使用Spring Cloud Sleuth。。
However, there is one extra step we can take. Let’s set the name of our application in the application.properties file, this way we’ll see this in the logs along with the trace and span IDs:
然而,我们可以采取一个额外的步骤。让我们在application.properties文件中设置我们的应用程序的名称,这样我们就可以在日志中看到这个名称以及跟踪和跨度ID:。
spring.application.name=Baeldung Sleuth Tutorial
Now we need an entry point to our application. Let’s create a REST controller with a single GET endpoint:
现在我们需要一个进入我们应用程序的入口。让我们创建一个具有单一GET端点的REST控制器:。
@RestController
public class SleuthTraceIdController {
@GetMapping("/traceid")
public String getSleuthTraceId() {
return "Hello from Sleuth";
}
}
Let’s visit our API endpoint at http://localhost:8080/traceid. We should see “Hello from Sleuth” in the response.
让我们访问我们的API端点:http://localhost:8080/traceid。我们应该在响应中看到 “Hello from Sleuth”。
3. Logging
3.记录
Let’s add a log statement to the getSleuthTraceId method. First, we need a Logger for our class. Then we can log the message:
让我们给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";
}
Let’s call our API endpoint again and check the logs. We should find something similar to this:
让我们再次调用我们的API端点并检查日志。我们应该发现与此类似的东西:
INFO [Baeldung Sleuth Tutorial,e48f140a63bb9fbb,e48f140a63bb9fbb] 9208 --- [nio-8080-exec-1] c.b.s.traceid.SleuthTraceIdController : Hello with Sleuth
Notice that the application name is inside the brackets at the beginning. These brackets are added by Sleuth. They represent the application name, trace ID, and span ID.
请注意,应用程序的名称在开头的括号内。这些括号是由Sleuth添加的。它们代表应用程序的名称、跟踪ID和跨度ID。
4. Current Trace and Span
4.电流跟踪和跨度
We can use the above example to debug issues in our application, but it might be challenging to determine what caused it and which trace to follow. That’s why we’ll get the current trace programmatically, and then we can use it for any further investigations.
我们可以用上面的例子来调试我们应用程序中的问题,但要确定是什么原因造成的,以及要遵循哪种跟踪,可能会有难度。这就是为什么我们要以编程方式获得当前的跟踪,然后我们可以用它来进行任何进一步的调查。
In our implementation, we’ll simplify this use case, and we’ll just log the trace IDs to the console.
在我们的实现中,我们将简化这个用例,我们将只是把跟踪ID记录到控制台。
Firstly, we need to get an instance of a Tracer object. Let’s inject it into our controller and get the current span:
首先,我们需要获得一个Tracer对象的实例。让我们把它注入到我们的控制器中,并获得当前的跨度:。
@Autowired
private Tracer tracer;
@GetMapping("/traceid")
public String getSleuthTraceId() {
logger.info("Hello with Sleuth");
Span span = tracer.currentSpan();
return "Hello from Sleuth";
}
Notice that the currentSpan method can return null if there is no active span at the moment. Therefore we have to perform an additional check to see if we can proceed and use this Span object without getting NullPointerException. Let’s implement this check and log the current trace and span IDs:
注意currentSpan方法可以返回null,如果目前没有活动的span。因此,我们必须执行额外的检查,看看我们是否可以继续并使用这个Span对象而不获得NullPointerException。让我们来实现这个检查并记录当前的跟踪和跨度ID。
Span span = tracer.currentSpan();
if (span != null) {
logger.info("Trace ID {}", span.context().traceIdString());
logger.info("Span ID {}", span.context().spanIdString());
}
Let’s run the application and look for these messages when we visit our API endpoint. They should contain the same IDs as the brackets added by Sleuth.
让我们运行应用程序,当我们访问我们的API端点时,寻找这些信息。它们应该包含与Sleuth添加的括号相同的ID。
5. Trace and Span ID as Decimal Numbers
5.跟踪和跨度ID为十进制数字
There is another way to get the span ID with the spanId method instead of spanIdString. The difference between them is that the latter one returns the hexadecimal representation of the value while the first one returns a decimal number. Let’s compare them in action and log the decimal value as well:
还有一种方法可以用spanId方法而不是spanIdString获得span ID。它们之间的区别是,后者返回十六进制表示的值,而前者返回十进制数字。让我们在实际操作中比较一下,也记录一下十进制值。
Span span = tracer.currentSpan();
if (span != null) {
logger.info("Span ID hex {}", span.context().spanIdString());
logger.info("Span ID decimal {}", span.context().spanId());
}
The two values represent the same number, and the output should look similar to this:
这两个值代表同一个数字,输出结果应该与此类似。
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
Similarly, this applies to trace IDs as well. Instead of traceIdString, we can use the traceId method. traceIdString returns a hexadecimal value while traceId returns a decimal value:
类似地,这也适用于跟踪ID。代替traceIdString,我们可以使用traceId方法。traceIdString返回一个十六进制的值,而traceId返回一个十进制的值:
logger.info("Trace ID hex {}", span.context().traceIdString());
logger.info("Trace ID decimal {}", span.context().traceId());
The output is very similar to the previous one. It contains the trace ID in hexadecimal first then in decimal:
其输出结果与之前的非常相似。它首先包含十六进制的跟踪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. Conclusion
6.结论
In this article, we discussed how Spring Cloud Sleuth could help debug and trace events in Spring Boot. First, we used the Tracer object to reference the current span and the TraceContext. After that, we were able to get the ID of the current trace and span. In addition, we saw how different methods return the ID in different number systems.
在这篇文章中,我们讨论了Spring Cloud Sleuth如何帮助调试和跟踪Spring Boot中的事件。首先,我们使用Tracer对象来引用当前span和TraceContext。之后,我们能够获得当前跟踪和跨度的ID。此外,我们看到不同的方法是如何在不同的数字系统中返回ID的。
As always, the source code with these examples is available over on GitHub.
像往常一样,这些例子的源代码可以在GitHub上找到。