sleuth是spring cloud中日志链(调用链解决方案),自动添加traceId,spanId。
sleuth包也可单独引入,和其它藕合度小。sleuth + zipkin 实现APM管理。
Sleuth 引入文档
从其它文章web压测结果获悉:sleuth在webmvc下没多大损失,在webflux下损失较大。需注意。
参见:Spring Cloud Sleuth 性能测试_Apple_zhl的博客-CSDN博客
MDC写入信息是在Slf4jScopeDecorator中。
MDC会放入以下内容:
final String previousTraceId = MDC.get("traceId");
final String previousParentId = MDC.get("parentId");
final String previousSpanId = MDC.get("spanId");
final String spanExportable = MDC.get("spanExportable");
final String legacyPreviousTraceId = MDC.get(LEGACY_TRACE_ID_NAME);
final String legacyPreviousParentId = MDC.get(LEGACY_PARENT_ID_NAME);
final String legacyPreviousSpanId = MDC.get(LEGACY_SPAN_ID_NAME);
final String legacySpanExportable = MDC.get(LEGACY_EXPORTABLE_NAME);
private static final String LEGACY_EXPORTABLE_NAME = "X-Span-Export";
private static final String LEGACY_PARENT_ID_NAME = "X-B3-ParentSpanId";
private static final String LEGACY_TRACE_ID_NAME = "X-B3-TraceId";
private static final String LEGACY_SPAN_ID_NAME = "X-B3-SpanId";
Web访问:
sleuth通过在web的请求增加TraceFilter来开启一个新的spanId 和 traceId,在离开时调用close方法关闭之前的trace.
参见类:
TraceWebServletAutoConfiguration -> TracingFilter
将TracingFilter增加到Web的Filter中,同时设置Filter的Order级别为Integer.MIN + 5.也即基本为最前。
因 TracingFilter是建立在Server级别的, 因此加载顺序会优先于Spring程序在Interceptor上设置的拦截器。
Scheduler:
sleuth使用AOP切面拦截所有的scheduler,使用TraceSchedulingAspect类控制生成新的traceId
WebClient数据传递:
TraceRestTemplateCustomizer -> TracingClientHttpRequestInterceptor
因此,只要使用RestTemplate.Builder生成的信息,都会默认会执行RestTemplateCustomizer。而自己new RestTemplate出来的对象则没有此功能。
以上都会自动添加。
pom.xml 引入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-core</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
线程和线程池使用:
线程-依托TraceRunnable 或 TraceCallable:
public class ThreadTestController {
@Autowired
private Tracing tracing;
@Autowired
private SpanNamer spanNamer;
@RequestMapping("/thread")
public String starterThread() throws InterruptedException {
log.info("trace parent...");
Runnable runnable = new Runnable() {
@Override
public void run() {
log.info("thread test");
}
};
TraceRunnable traceRunnable = new TraceRunnable(tracing, spanNamer, runnable, "myRunnable");
//TraceCallable
Thread thread = new Thread(traceRunnable);
thread.start();
return"OK";
}
}
线程池依托:
内部调用
@Autowired
private BeanFactory beanFactory;
ThreadPoolExecutor myThreadPool = new ThreadPoolExecutor(2, 2,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
@RequestMapping("/executor2")
public String executor2() throws InterruptedException {
TraceableExecutorService executorService = new TraceableExecutorService(beanFactory, myThreadPool, "1234");
log.info("executor2 parent...");
//TraceCallable
//TraceCallable
for(int i=0;i< 30;i++){
executorService.submit(new SpanRunnable());
}
return"OK";
}
}
bean定义:
@Configuration
@Slf4j
public class BeanConfiguration {
/**
* 切换链接池
* @param beanFactory
* @return
*/
@Bean("myTestExecutor")
public ExecutorService executorService(@Autowired BeanFactory beanFactory){
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 5, 100, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
log.info("poolExecutor:--------------{}",poolExecutor);
TraceableExecutorService executorService = new TraceableExecutorService(beanFactory, poolExecutor, "executePool");
return executorService;
}
}
@Autowired
@Qualifier("myTestExecutor")
private ExecutorService executorService;
/**
*
* @return
* @throws InterruptedException
*/
@RequestMapping("/executor3")
public String executor3() throws InterruptedException {
log.info("executor3 parent...");
log.info("taskExecutor:{}", taskExecutor);
//TraceCallable
//TraceCallable
for(int i=0;i< 30;i++){
executorService.submit(new SpanRunnable());
}
return"OK";
}