下面看TracingFilter的doFilter:
Span span = handler.handleReceive(extractor, httpRequest);
// Add attributes for explicit access to customization or span context
request.setAttribute(SpanCustomizer.class.getName(), span.customizer());
request.setAttribute(TraceContext.class.getName(), span.context());
Throwable error = null;
Scope scope = currentTraceContext.newScope(span.context());
try {
// any downstream code can see Tracer.currentSpan() or use Tracer.currentSpanCustomizer()
chain.doFilter(httpRequest, httpResponse);
} catch (IOException | ServletException | RuntimeException | Error e) {
error = e;
throw e;
} finally {
scope.close();
if (servlet.isAsync(httpRequest)) { // we don't have the actual response, handle later
servlet.handleAsync(handler, httpRequest, httpResponse, span);
} else { // we have a synchronous response, so we can finish the span
handler.handleSend(ADAPTER.adaptResponse(httpRequest, httpResponse), error, span);
}
}
}
在SleuthLogAutoConfiguration中如果有slfj的包,则注入CurrentTraceContext:
@Configuration
@ConditionalOnClass(MDC.class)
@EnableConfigurationProperties(SleuthSlf4jProperties.class)
protected static class Slf4jConfiguration {
@Bean
@ConditionalOnProperty(value = "spring.sleuth.log.slf4j.enabled", matchIfMissing = true)
@ConditionalOnMissingBean
public CurrentTraceContext slf4jSpanLogger() {
return Slf4jCurrentTraceContext.create();
}
...
}
Slf4jCurrentTraceContext中,delegate就是CurrentTraceContext.Default.inheritable():
public static final class Default extends CurrentTraceContext {
static final ThreadLocal<TraceContext> DEFAULT = new ThreadLocal<>();
// Inheritable as Brave 3's ThreadLocalServerClientAndLocalSpanState was inheritable
static final InheritableThreadLocal<TraceContext> INHERITABLE = new InheritableThreadLocal<>();
final ThreadLocal<TraceContext> local;
//静态方法create,local对象为ThreadLocal类型
/** Uses a non-inheritable static thread local */
public static CurrentTraceContext create() {
return new Default(DEFAULT);
}
//local对象为InheritableThreadLocal类型
//官方文档指出,inheritable方法在线程池的环境中需谨慎使用,可能会取出错误的TraceContext,这样会导致Span等信息会记录并关联到错误的traceId上
/**
* Uses an inheritable static thread local which allows arbitrary calls to {@link
* Thread#start()} to automatically inherit this context. This feature is available as it is was
* the default in Brave 3, because some users couldn't control threads in their applications.
*
* <p>This can be a problem in scenarios such as thread pool expansion, leading to data being
* recorded in the wrong span, or spans with the wrong parent. If you are impacted by this,
* switch to {@link #create()}.
*/
public static CurrentTraceContext inheritable() {
return new Default(INHERITABLE);
}
Default(ThreadLocal<TraceContext> local) {
if (local == null) throw new NullPointerException("local == null");
this.local = local;
}
@Override public TraceContext get() {
return local.get();
}
//替换当前TraceContext,close方法将之前的TraceContext设置回去
//Scope接口继承了Closeable接口,在try中使用会自动调用close方法,为了避免用户忘记close方法,还提供了Runnable,Callable,Executor,ExecutorService包装方法
@Override public Scope newScope(@Nullable TraceContext currentSpan) {
final TraceContext previous = local.get();
local.set(currentSpan);
class DefaultCurrentTraceContextScope implements Scope {
@Override public void close() {
local.set(previous);
}
}
return new DefaultCurrentTraceContextScope();
}
}










