springCloud项目使用sleuth实现链路追踪功能

springCloud项目使用sleuth实现链路追踪功能

编码文章call10242025-02-24 15:12:5723A+A-

为了实现一个链路追踪功能,并确保所有打印的日志中都包含 traceId,可以使用 Spring Cloud Sleuth。Sleuth 是一个分布式追踪解决方案,它可以帮助你跟踪请求在微服务架构中的流动,并将日志关联到同一个请求中。

以下是实现步骤:

1. 添加依赖

首先,在你的 pom.xml 文件中添加 Spring Cloud Sleuth 和 Zipkin(可选)的依赖。Zipkin 是一个收集和查看追踪数据的工具,如果你需要可视化追踪数据,可以一并引入。

org.springframework.cloudspring-cloud-starter-sleuth
org.springframework.cloudspring-cloud-starter-zipkin

2. 配置应用

在 application.yml 或 application.properties 中进行配置,以启用 Sleuth 和 Zipkin(如果使用)。

spring: 
	sleuth: 
		sampler: 
			probability: 1.0 # 设置采样率为100% 
  zipkin: 
  	base-url: http://localhost:9411 # 如果使用 Zipkin,请指定 Zipkin 服务器地址 

3. 自定义日志格式

为了让所有的日志都包含 traceId,你需要自定义日志格式。可以在 logback-spring.xml 或 logback.xml 中配置日志格式。

%d{yyyy-MM-dd HH:mm:ss} \[%thread\] %-5level %logger{36} - traceId=%X{X-B3-TraceId}, spanId=%X{X-B3-SpanId} - %msg%n

4. 确保线程继承 traceId

默认情况下,Sleuth 已经会为每个请求分配唯一的 traceId 和 spanId,并且这些信息会在同一个线程中传递。但是,如果你的应用中有异步任务或线程池,你需要确保这些线程也能够继承 traceId 和 spanId。

你可以通过以下方式确保线程继承 traceId:

4.1 使用 @Async注解时

如果你使用了 @Async 注解来启动异步任务,默认情况下,Spring 的 TaskExecutor 不会自动传播 traceId。你可以通过配置 TaskDecorator 来解决这个问题。

import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.scheduling.annotation.AsyncConfigurer; 
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 
import brave.propagation.TraceContext; 
import brave.propagation.CurrentTraceContext; 
import brave.spring.web.TracingAsyncUtils;
@Configuration 
public class AsyncConfig implements AsyncConfigurer {
private final CurrentTraceContext currentTraceContext;
public AsyncConfig(CurrentTraceContext currentTraceContext) {
  this.currentTraceContext = currentTraceContext; 
}
@Override public Executor getAsyncExecutor() { 
  ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  executor.setCorePoolSize(7); 
  executor.setMaxPoolSize(42); 
  executor.setQueueCapacity(11); 
  executor.initialize();
// Ensure trace context is propagated to async threads 
  return TracingAsyncUtils.wrap(executor, currentTraceContext);
}
}

4.2 使用线程池时

如果你使用了 ExecutorService 或其他线程池,可以通过 CurrentTraceContext 来确保线程池中的线程也能够继承 traceId。


import brave.propagation.CurrentTraceContext; 
import brave.propagation.TraceContext;
public class TracingRunnable implements Runnable {
  private final CurrentTraceContext currentTraceContext; 
  private final Runnable delegate;
public TracingRunnable(CurrentTraceContext currentTraceContext, Runnable delegate) { 
  this.currentTraceContext = currentTraceContext; 
  this.delegate = delegate; 
}
@Override public void run() { 
  TraceContext context = currentTraceContext.get();
  try (CurrentTraceContext.Scope scope = currentTraceContext.newScope(context)) { 
    delegate.run();
  } 
}
}


// 在创建线程池时使用 
ThreadPoolExecutor executor = new ThreadPoolExecutor(...);
 executor.submit(new TracingRunnable(currentTraceContext, yourRunnable));

5. 测试链路追踪

启动应用后,访问任意接口,检查日志输出。你应该能看到每条日志中都包含了 traceId 和 spanId,并且这些信息在整个请求链路中保持一致。

6. 可视化追踪数据(可选)

如果你启用了 Zipkin,可以通过访问 Zipkin UI (http://localhost:9411) 查看详细的追踪数据,包括请求的时间、调用的服务等。


通过以上步骤,你可以确保所有的日志中都包含 traceId,并且能够完整地追踪一个接口请求的过程,即使是在多线程环境中也能保证追踪信息的传递。

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4