代码结构
spring sleuth 代码大致分为
- dependencies,只定义了依赖jar
- sleuth-zipkin 向zipkin发送span的 能力封装
- starter-zipkin spring boot starter 定义封装,没有具体代码
- strater-sleuth spring boot starter 定义封装,没有具体代码,如果span不是发送给zipkin,使用此starter就可以
- core 核心代码,主要包括 annotation、各种注入(依赖brave)、log输出(主要是依托brave 及日志系统MDC)、propagation
spring-cloud-sleuth-2.1.3.RELEASE 的很多核心实现都依赖以下zipkin的包
- brave-5.7.0
- zipkin-reporter-java
可以说,如果要深入研究sleuth,就需要了解以上两个包
zipkin 的reporter
sleuth zipkin 的reporter主要依托ConditionalOnMissingBean及SpringBootCondition 实现可override及可配置型。
先从tracing 的创建来看,tracing默认创建是在TraceAutoConfiguration类中,具体函数如下
@Bean
@ConditionalOnMissingBean
// NOTE: stable bean name as might be used outside sleuth
Tracing tracing(
@Value("${spring.zipkin.service.name:${spring.application.name:default}}") String serviceName,
Propagation.Factory factory, CurrentTraceContext currentTraceContext,
Sampler sampler, ErrorParser errorParser, SleuthProperties sleuthProperties,
@Nullable List<Reporter<zipkin2.Span>> spanReporters) {
Tracing.Builder builder = Tracing.newBuilder().sampler(sampler)
.errorParser(errorParser)
.localServiceName(StringUtils.isEmpty(serviceName) ? DEFAULT_SERVICE_NAME
: serviceName)
.propagationFactory(factory).currentTraceContext(currentTraceContext)
.spanReporter(new CompositeReporter(this.spanAdjusters,
spanReporters != null ? spanReporters : Collections.emptyList()))
.traceId128Bit(sleuthProperties.isTraceId128())
.supportsJoin(sleuthProperties.isSupportsJoin());
for (FinishedSpanHandler finishedSpanHandlerFactory : this.finishedSpanHandlers) {
builder.addFinishedSpanHandler(finishedSpanHandlerFactory);
}
for (TracingCustomizer customizer : this.tracingCustomizers) {
customizer.customize(builder);
}
return builder.build();
}
先注意函数带有annotation ConditionalOnMissingBean,因此可以自定义一个Tracing bean来override。
其次看参数@Nullable List<Reporter<zipkin2.Span>> spanReporters,因此可以实现多个Reporter<zipkin2.Span> bean来实现一个span向多方报告,比如同时向zipkin kafka及写入logstat 日志。
@Bean
public Reporter<Span> spanReporter() {
return new Reporter<Span>() {
@Override
public void report(Span span) {
logger.info("customer report:" + span);
}
};
}
默认reporter实现在类ZipkinAutoConfiguration中实现,具体代码如下
/**
* Zipkin reporter bean name. Name of the bean matters for supporting multiple tracing
* systems.
*/
public static final String REPORTER_BEAN_NAME = "zipkinReporter";
/**
* Zipkin sender bean name. Name of the bean matters for supporting multiple tracing
* systems.
*/
public static final String SENDER_BEAN_NAME = "zipkinSender";
@Bean(REPORTER_BEAN_NAME)
@ConditionalOnMissingBean(name = REPORTER_BEAN_NAME)
public Reporter<Span> reporter(ReporterMetrics reporterMetrics,
ZipkinProperties zipkin, @Qualifier(SENDER_BEAN_NAME) Sender sender) {
// historical constraint. Note: AsyncReporter supports memory bounds
return AsyncReporter.builder(sender).queuedMaxSpans(1000)
.messageTimeout(zipkin.getMessageTimeout(), TimeUnit.SECONDS)
.metrics(reporterMetrics).build(zipkin.getEncoder());
}
同样使用了ConditionalOnMissingBean,因此也可以通过自定义bean 实现 override,注意下实际实现类默认使BoundedAsyncReporter (来自zipkin reporter jar),具体span发送默认使先进入bounded queue,异步flush 发送。
发送span到bounded queue 或者调用自定义reporter 的report方法在 private static final class ListReporter implements Reporter<zipkin2.Span> 类,这个类在是public class TraceAutoConfiguration的inner 类,具体实现函数如下:
@Override
public void report(Span span) {
for (Reporter<zipkin2.Span> spanReporter : this.spanReporters) {
try {
spanReporter.report(span);
}
catch (Exception ex) {
log.warn("Exception occurred while trying to report the span "
+ span, ex);
}
}
}
最后说下zipkin 三种reporter sender(rest、kafka、rabbitMQ)的实现,相关实现都在package org.springframework.cloud.sleuth.zipkin2.sender下,关键点如下;
- ZipkinKafkaSenderConfiguration,ZipkinRabbitSenderConfiguration,ZipkinRestTemplateSenderConfiguration 都实现@Bean(ZipkinAutoConfiguration.SENDER_BEAN_NAME)
- 如何实现3选一,依托@Conditional(ZipkinSenderCondition.class)来实现,即通过SpringBootCondition模式来实现根据配置项:spring.zipkin.sender.type 选择 bean实现类
本文暂时没有评论,来添加一个吧(●'◡'●)