源码入口
直接查看sleuth的starter包,找到spring.factories文件,基于springboot的自动配置机制
# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration,\ # trace的基本配置
org.springframework.cloud.sleuth.metric.TraceMetricsAutoConfiguration,\
org.springframework.cloud.sleuth.log.SleuthLogAutoConfiguration,\ # trace的日志配置
org.springframework.cloud.sleuth.instrument.messaging.TraceSpanMessagingAutoConfiguration,\ # 定义了span的trace信息解析,traceId,parentID之类的
org.springframework.cloud.sleuth.instrument.messaging.TraceSpringIntegrationAutoConfiguration,\ # 定义了和spring-inregration消息集成的管道配置
org.springframework.cloud.sleuth.instrument.messaging.websocket.TraceWebSocketAutoConfiguration,\# websocket配置
org.springframework.cloud.sleuth.instrument.async.AsyncCustomAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.async.AsyncDefaultAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.hystrix.SleuthHystrixAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.scheduling.TraceSchedulingAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.web.TraceHttpAutoConfiguration,\ # http请求过来后,trace信息提取,打tag的对象配置
org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration,\ # 定义了http请求过来后,拦截的filter,拦截器等信息的配置
org.springframework.cloud.sleuth.instrument.web.client.TraceWebClientAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.web.client.TraceWebAsyncClientAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.web.client.feign.TraceFeignClientAutoConfiguration,\
org.springframework.cloud.sleuth.instrument.zuul.TraceZuulAutoConfiguration,\ # 跟网关集成的配置
org.springframework.cloud.sleuth.instrument.rxjava.RxJavaAutoConfiguration,\
org.springframework.cloud.sleuth.annotation.SleuthAnnotationAutoConfiguration # sleuth注解的配置
# Environment Post Processor
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.sleuth.autoconfig.TraceEnvironmentPostProcessor # 环境变量配置
TraceAutoConfiguration
@Configuration
@ConditionalOnProperty(value="spring.sleuth.enabled", matchIfMissing=true)
@EnableConfigurationProperties({TraceKeys.class, SleuthProperties.class})
public class TraceAutoConfiguration {
@Autowired
SleuthProperties properties;
@Bean
@ConditionalOnMissingBean
public Random randomForSpanIds() {
return new Random();
}
@Bean
@ConditionalOnMissingBean
public Sampler defaultTraceSampler() {
return NeverSampler.INSTANCE;
}
@Bean
@ConditionalOnMissingBean(Tracer.class)
public DefaultTracer sleuthTracer(Sampler sampler, Random random,
SpanNamer spanNamer, SpanLogger spanLogger,
SpanReporter spanReporter, TraceKeys traceKeys) {
return new DefaultTracer(sampler, random, spanNamer, spanLogger,
spanReporter, this.properties.isTraceId128(), traceKeys);
}
@Bean
@ConditionalOnMissingBean
public SpanNamer spanNamer() {
return new DefaultSpanNamer();
}
@Bean
@ConditionalOnMissingBean
public SpanReporter defaultSpanReporter() {
return new NoOpSpanReporter();
}
@Bean
@ConditionalOnMissingBean
public SpanAdjuster defaultSpanAdjuster() {
return new NoOpSpanAdjuster();
}
@Bean
@ConditionalOnMissingBean
public ErrorParser defaultErrorParser() {
return new ExceptionMessageErrorParser();
}
}
@ConditionalOnProperty(value=”spring.sleuth.enabled”, matchIfMissing=true) , 匹配spring.sleuth.enabled属性,如果确实,则默认为true。
@EnableConfigurationProperties({TraceKeys.class, SleuthProperties.class}) sleuth的配置文件 , TraceKeys中定义了一系列的tag标签可以,比如http的
,hystrix的,在创建span的tag的时候会使用
defaultTraceSampler() , 当容器中存在这个bean的时候,创建这个bean, 表示是否上报trace信息,默认为NeverSampler.INSTANCE , 一律不上报
sleuthTracer() , 整个系统中的追踪对象,用于创建 span,添加span标签等等。
spanNamer() span名称生成器,这里返回一个DefaultSpanNamer类型的bean,能够实现通过SpanName注解设置span name。
defaultSpanReporter() span的上报器,里面有个report方法, 用于将span信息放入一个阻塞队列里面,之后有一个异步线程去这个队列里面去消费span,然后发送到kafka里面去。 这里默认为NoOpSpanReporter, 即不上报任何信息
defaultSpanAdjuster() span的调整器, 在SpanReporter执行他的report方法的时候,会调用SpanAdjuster的adjust方法 ,默认为NoOpSpanAdjuster , 不做任何调整
@Override
public void report(Span span) {
Span spanToReport = span;
if (spanToReport.isExportable()) {
try {
if (this.environment != null) {
processLogs(spanToReport);
}
// 可以在上报之前对span进行调整
for (SpanAdjuster adjuster : this.spanAdjusters) {
spanToReport = adjuster.adjust(spanToReport);
}
this.queue.add(spanToReport);
} catch (Exception e) {
this.spanMetricReporter.incrementDroppedSpans(1);
if (log.isDebugEnabled()) {
log.debug("The span " + spanToReport + " will not be sent to Zipkin due to [" + e + "]");
}
}
} else {
if (log.isDebugEnabled()) {
log.debug("The span " + spanToReport + " will not be sent to Zipkin due to sampling");
}
}
}
defaultErrorParser() 异常信息解析器
TraceHttpAutoConfiguration
上面讲的TraceAutoConfiguration是sleuth的一些基本配置,大部分都用不到,因为大部分会被扩展。 相信想了解链路追踪系统底层原理的,首先会想到,当一个请求进入我的系统,sleuth是怎么开始处理的, 接下来讲的就是TraceHttpAutoConfiguration , 当http请求进来后,sleuth的一些核心配置,只有有了这些配置,才会更加完善。
@Configuration
@ConditionalOnBean(Tracer.class)
@AutoConfigureAfter(TraceAutoConfiguration.class) // 在TraceAutoConfiguration加载完成之后加载
@EnableConfigurationProperties({ TraceKeys.class, SleuthWebProperties.class })
public class TraceHttpAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public HttpTraceKeysInjector httpTraceKeysInjector(Tracer tracer, TraceKeys traceKeys) {
return new HttpTraceKeysInjector(tracer, traceKeys);
}
@Bean
@ConditionalOnMissingBean
public HttpSpanExtractor httpSpanExtractor(SleuthWebProperties sleuthWebProperties) {
return new ZipkinHttpSpanExtractor(Pattern.compile(sleuthWebProperties.getSkipPattern()));
}
@Bean
@ConditionalOnMissingBean
public HttpSpanInjector httpSpanInjector() {
return new ZipkinHttpSpanInjector();
}
}
httpTraceKeysInjector() , 这个类的作用就是给请求添加tag的类,每个span都有tag,这个类的作用就是打tag的 ,代码如下
public void addRequestTags(String url, String host, String path, String method) {
this.tracer.addTag(this.traceKeys.getHttp().getUrl(), url);
this.tracer.addTag(this.traceKeys.getHttp().getHost(), host);
this.tracer.addTag(this.traceKeys.getHttp().getPath(), path);
this.tracer.addTag(this.traceKeys.getHttp().getMethod(), method);
}
httpSpanExtractor() 负责解析请求头里面的traceId,parentId ,spanId等,根据提取的信息生成span, 如果http请求中不存在trace信息,那么会创建一个新的span 。 比如: 系统A调用系统 B , 请求刚刚进入A系统的时候,请求头里面是不存在trace信息的,这个时候会创建一个纯新的span, 当请求调用到B系统的时候,这个时候就可以解析出来trace信息,可以解析出来traceId,parentId等信息。
httpSpanInjector() 在发送请求到服务端的时候,会把自身的一些信息放入到请求里面去,也就是客户端请求服务端时,客户端在发起请求之前,会调用这个方法,在请求头里面放入一些信息
public void inject(Span span, SpanTextMap map) {
Map<String, String> carrier = TextMapUtil.asMap(map);
this.setHeader(map, carrier, "X-B3-TraceId", span.traceIdString());
this.setIdHeader(map, carrier, "X-B3-SpanId", span.getSpanId());
this.setHeader(map, carrier, "X-B3-Sampled", span.isExportable() ? "1" : "0");
this.setHeader(map, carrier, "X-Span-Name", span.getName());
this.setIdHeader(map, carrier, "X-B3-ParentSpanId", this.getParentId(span));
this.setHeader(map, carrier, "X-Process-Id", span.getProcessId());
Iterator var4 = span.baggageItems().iterator();
while(var4.hasNext()) {
Entry<String, String> entry = (Entry)var4.next();
map.put(this.prefixedKey((String)entry.getKey()), (String)entry.getValue());
}
}
上面讲的三个比较重要的对象,都是对span的解析,tag的生成之类的,真正请求进入系统之后,系统怎么处理的配置在哪里呢 ? 下面讲的就是这个。
TraceWebAutoConfiguration
这个配置类里面代码比较多,这里就不一一列出来了,有几个比较重要的点讲一下
/**
* Nested config that configures Web MVC if it's present (without adding a runtime
* dependency to it)
*/
@Configuration
@ConditionalOnClass(WebMvcConfigurerAdapter.class)
@Import(TraceWebMvcConfigurer.class)
protected static class TraceWebMvcAutoConfiguration {
}
这个空的静态内部类,主要是为了import这个类TraceWebMvcConfigurer 。 这个类继承了WebMvcConfigurerAdapter , 将TraceHandlerInterceptor添加到拦截器列表里面去了
@Bean
public TraceWebAspect traceWebAspect(Tracer tracer, TraceKeys traceKeys,
SpanNamer spanNamer, ErrorParser errorParser) {
return new TraceWebAspect(tracer, spanNamer, traceKeys, errorParser);
}
定义了Trace的切面
@Bean
public FilterRegistrationBean traceWebFilter(TraceFilter traceFilter) {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(
traceFilter);
filterRegistrationBean.setDispatcherTypes(ASYNC, ERROR, FORWARD, INCLUDE,
REQUEST);
filterRegistrationBean.setOrder(TraceFilter.ORDER);
return filterRegistrationBean;
}
@Bean
@ConditionalOnMissingBean
public TraceFilter traceFilter(BeanFactory beanFactory,
SkipPatternProvider skipPatternProvider) {
return new TraceFilter(beanFactory, skipPatternProvider.skipPattern());
}
定义了TraceFilter , 这个过滤器比较重要,整个调用链的开始就从这里开始的,这里面会解析request里面的信息,创建span之类的,SkipPatternProvider这个对象,是用于过滤有些请求不需要追踪,可以放入到这里面来,到时候就不会创建span了。