1 类介绍
1.1 TracingFilter介绍
配置
配置类io.opentracing.contrib.spring.web.starter.ServerTracingAutoConfiguration#tracingFilter
引入Bean。
TraceFilter是普通的servlet filter,filter的引入有三种(我了解的)方式:
1)在web.xml里配置引入
2)在Filter类上面增加@WebFilter
- 通过bean注入
特点是:前两种适合项目通过war包部署,最后适合springboot项目。
功能
从http协议头中获取span信息,如果SERVER_SPAN_CONTEXT为空,则根据头信息创建新的Span。
1.2 Interceptor
通过类io.opentracing.contrib.spring.web.starter.ServerTracingAutoConfiguration#tracingHandlerInterceptor
引入。
它主要处理业务日志,拦截controller等(??)
2 源码解析
Tracer创建
Tracer主要是设置上报的服务器地址,采样率,项目名称等。
io.opentracing.contrib.java.spring.jaeger.starter.JaegerAutoConfiguration#tracer
调用io.jaegertracing.internal.JaegerTracer.Builder
新建Tracer对象。
private ScopeManager scopeManager = new ThreadLocalScopeManager();
private BaggageRestrictionManager baggageRestrictionManager = new DefaultBaggageRestrictionManager();
private boolean expandExceptionLogs;
private final JaegerObjectFactory objectFactory;
private boolean useTraceId128Bit;
private boolean manualShutdown;
public Builder(String serviceName) {
this(serviceName, new JaegerObjectFactory());
}
这里有个点需要注意:ScopeManager的具体实现类是ThreadLocalScopeManager,稍后会解释。
注册Tracer对象
io.opentracing.contrib.spring.tracer.configuration.TracerRegisterAutoConfiguration#registerToGlobalTracer
可以通过GlobalTracer.get()方法获取对象。
Scope分析(非常重要)
Scope是站在CPU角度激活或者失效Span。ScopeManager管理Scope。
一个Scope里可以有多个span,但是只有一个激活的span。
ThreadLocalScope(ThreadLocalScopeManager scopeManager, Span wrapped, boolean finishOnClose) {
this.scopeManager = scopeManager;
//绑定的span
this.wrapped = wrapped;
this.finishOnClose = finishOnClose;
//暂存之前激活的span
this.toRestore = scopeManager.tlsScope.get();
// 设置当前线程绑定的scope
scopeManager.tlsScope.set(this);
}
@Override
public void close() {
if (scopeManager.tlsScope.get() != this) {
// This shouldn't happen if users call methods in the expected order. Bail out.
return;
}
if (finishOnClose) {
wrapped.finish();
}
// 恢复之前的指向
scopeManager.tlsScope.set(toRestore);
}
在操作当span操作完成(span.finish)时,需要调用scope.close方法,触发关联新的激活span,否则调用链条会出错。
Span创建
final Span span = tracer.buildSpan(httpRequest.getMethod())
.asChildOf(extractedContext)
.withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
.start();
httpRequest.setAttribute(SERVER_SPAN_CONTEXT, span.context());
for (ServletFilterSpanDecorator spanDecorator: spanDecorators) {
spanDecorator.onRequest(httpRequest, span);
}
try (Scope scope = tracer.activateSpan(span)) {
chain.doFilter(servletRequest, servletResponse);
if (!httpRequest.isAsyncStarted()) {
for (ServletFilterSpanDecorator spanDecorator : spanDecorators) {
spanDecorator.onResponse(httpRequest, httpResponse, span);
}
}
// catch all exceptions (e.g. RuntimeException, ServletException...)
} catch (Throwable ex) {
span创建就是生成jaegerspan,并设置parent为从http头获取的span信息。
激活span
tracer.activateSpan是激活span,会触发创建一个ThreadLocalScope。
结果是可以通过tracer.scopeManager.activeSpan();获取span信息。
Span关闭
span.finish会触发span上报。
private void finishWithDuration(long durationMicros) {
synchronized (this) {
if (finished) {
log.warn("Span has already been finished; will not be reported again.");
return;
}
finished = true;
this.durationMicroseconds = durationMicros;
}
if (context.isSampled()) {
tracer.reportSpan(this);
}
}
网友评论