1. 依赖
<!-- spring cloud sleuth 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
2. 日志配置
日志格式化增加 ${LOG_LEVEL_PATTERN:-%5p} 或者 [${applicationName},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}],如果已有则无需修改配置。
TraceEnvironmentPostProcessor类的postProcessEnvironment 方法会在logging.pattern.level 中增加spring.application.name
、X-B3-TraceId
和X-B3-SpanId
的配置。
参考:https://blog.csdn.net/z69183787/article/details/109321037
配置完之后,遇到一个问题:
输出日志,traceId和spanId都正常,但是applicationName一直是“-”
解决办法:
将application.xml 改成 bootstrap.xml
然后里面配置spring.application.name
3. 异步调用方案
如果是http(包含feign)和@Async 的服务调用,无需额外修改
如果代码中需要使用线程,因为sleuth是基于BeanPostProcessor实现的,所以通过new 创建的实例是无法被sleuth管理的。所以如要在线程中链路中使用链路追踪,需要把线程池通过注入的方式使用。
线程池配置可以参数下面:
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.instrument.async.LazyTraceAsyncCustomizer;
import org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor;
import org.springframework.cloud.sleuth.instrument.async.LazyTraceThreadPoolTaskExecutor;
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 java.util.concurrent.*;
/**
* @Description:
* @data: 2023/4/4 17:37
*/
@Configuration
public class ThreadPoolConfig {
@Autowired
private BeanFactory beanFactory;
/**
* 解决异步线程池,链路跟踪丢失问题
* <p>
* 不通过实现接口的方式配置AsyncConfigurer,而是通过@Configuration 的方式注册一个sleuth中的LazyTraceAsyncCustomizer包装类型的AsyncConfigurer
* <p>
* 需要配置application.yaml spring: sleuth: async: configurer: enabled: false 将sleuth中默认的org.springframework.cloud.sleuth.instrument.async.AsyncDefaultAutoConfiguration.DefaultAsyncConfigurerSupport
* 异步线程池的配置忽略掉。
*
* @return
*/
@Bean
public AsyncConfigurer asyncConfigurer() {
// 在这里返回一个 LazyTraceAsyncCustomizer 类型的AsyncConfigurer
return new LazyTraceAsyncCustomizer(this.beanFactory, new AsyncConfigurer() {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2);
//配置最大线程数
executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 20);
//配置队列大小
executor.setQueueCapacity(500);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("Yk-async-task-");
//配置保存时间
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (throwable, method, obj) -> {
log.error("threadpool error: {}" , throwable);
};
}
});
}
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("Yk-task-");
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.setQueueCapacity(1000);
threadPoolTaskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2);
threadPoolTaskExecutor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 20);
threadPoolTaskExecutor.initialize();
// sleuth 中延时跟踪执行
return new LazyTraceThreadPoolTaskExecutor(beanFactory, threadPoolTaskExecutor);
}
@Bean
public Executor threadpool() {
Executor executor = Executors.newFixedThreadPool(3);
return new LazyTraceExecutor(beanFactory, executor);
}
@Bean
public Executor threadPoolExecutor() {
int coreThreadNum = 3, maxThreadNum = 10;
Executor executor = new ThreadPoolExecutor(coreThreadNum, maxThreadNum,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
return new LazyTraceExecutor(beanFactory, executor);
}
}
配置文件
此步骤非必须,如果配置的线程池无法生效,可尝试。
spring:
sleuth:
async:
configurer:
enabled: false