假设我们有一个微服务架构,其中包括两个服务:用户服务和订单服务。当用户下单时,订单服务会向用户服务发送一个请求,获取用户的信息。此时,我们可以使用Spring Cloud Sleuth来跟踪这个请求的整个调用链路,包括每个服务的处理情况和耗时。具体代码如下:
在用户服务中:
代码语言:javascript复制import org.springframework.cloud.sleuth.Tracer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
...
@RestController
public class UserController {
@Autowired
private Tracer tracer;
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) throws InterruptedException {
Span span = tracer.nextSpan().name("getUser").start();
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
TimeUnit.SECONDS.sleep(1);
User user = new User();
user.setId(id);
user.setName("Alice");
user.setAge(18);
return user;
} finally {
span.finish();
}
}
}
在订单服务中:
代码语言:javascript复制import org.springframework.cloud.sleuth.Tracer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.TimeUnit;
...
@RestController
public class OrderController {
@Autowired
private Tracer tracer;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/orders/{id}")
public Order getOrder(@PathVariable Long id) throws InterruptedException {
Span span = tracer.nextSpan().name("getOrder").start();
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
TimeUnit.SECONDS.sleep(1);
User user = restTemplate.getForObject("http://localhost:8080/users/" id, User.class);
Order order = new Order();
order.setId(id);
order.setUser(user);
return order;
} finally {
span.finish();
}
}
}
在上面的代码中,我们分别在用户服务和订单服务中使用了Tracer接口来记录每个请求的Trace ID和Span ID,并通过注解和标签记录了请求的开始、结束时间和耗时。当我们访问订单服务时,Spring Cloud Sleuth会自动将Trace ID和Span ID传递给用户服务,并
在订单服务中,我们使用RestTemplate调用用户服务的getUser接口,并将返回的User对象作为Order对象的一个字段。在getUser接口中,我们使用了TimeUnit.SECONDS.sleep(1)来模拟请求的处理时间,以便更好地观察调用链路的情况。
当我们在浏览器中访问http://localhost:8081/orders/1时,我们可以在控制台中看到类似以下的输出:
代码语言:javascript复制Span name: getOrder
Span begin: 1649145286467
Span end: 1649145287478
Span annotations: [cs=1649145286467, cr=1649145287478]
Span tags: {http.host=localhost, http.method=GET, http.path=/users/1, http.status_code=200, span.kind=client, http.url=http://localhost:8080/users/1}
Span name: getUser
Span begin: 1649145286467
Span end: 1649145287478
Span annotations: [sr=1649145286467, ss=1649145287477, ss=1649145287477, cr=1649145287477]
Span tags: {http.host=localhost, http.method=GET, http.path=/users/1, http.status_code=200, span.kind=server}
在上面的输出中,我们可以看到getOrder和getUser两个Span的开始时间、结束时间和注解信息。我们还可以看到getUser Span的标签信息,其中包括了用户服务的请求路径、请求方法、响应状态码和Span的类型。通过这些信息,我们可以更好地了解整个请求的调用链路和性能情况,方便我们进行性能优化和故障排查。
除了在控制台中输出调用链路信息,我们还可以将这些信息记录到日志文件中,以便更好地跟踪和分析。在Spring Boot应用中,我们可以使用logback等日志框架来记录日志信息。以下是一个logback.xml文件的示例配置:
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/myapp.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/var/log/myapp.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.cloud.sleuth" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
在上面的配置中,我们将org.springframework.cloud.sleuth包下的日志级别设置为DEBUG,以便记录Sleuth的调用链路信息。我们还将日志输出到控制台和/var/log/myapp.log文件中,并使用TimeBasedRollingPolicy来进行日志滚动,保留最近7天的日志文件。