Class ThreadLocalSpan
- java.lang.Object
-
- brave.propagation.ThreadLocalSpan
-
public class ThreadLocalSpan extends Object
This type allows you to place a span in scope in one method and access it in another without using an explicit request parameter.Many libraries expose a callback model as opposed to an interceptor one. When creating new instrumentation, you may find places where you need to place a span in scope in one callback (like `onStart()`) and end the scope in another callback (like `onFinish()`).
Provided the library guarantees these run on the same thread, you can simply propagate the result of
Tracer.startScopedSpan(String)orTracer.withSpanInScope(Span)from the starting callback to the closing one. This is typically done with a request-scoped attribute. Here's an example:class MyFilter extends Filter { public void onStart(Request request, Attributes attributes) { // Assume you have code to start the span and add relevant tags... // We now set the span in scope so that any code between here and // the end of the request can see it with Tracer.currentSpan() SpanInScope spanInScope = tracer.withSpanInScope(span); // We don't want to leak the scope, so we place it somewhere we can // lookup later attributes.put(SpanInScope.class, spanInScope); } public void onFinish(Response response, Attributes attributes) { // as long as we are on the same thread, we can read the span started above Span span = tracer.currentSpan(); // Assume you have code to complete the span // We now remove the scope (which implicitly detaches it from the span) attributes.remove(SpanInScope.class).close(); } }Sometimes you have to instrument a library where There's no attribute namespace shared across request and response. For this scenario, you can use
ThreadLocalSpanto temporarily store the span between callbacks. Here's an example:class MyFilter extends Filter { final ThreadLocalSpan threadLocalSpan; public void onStart(Request request) { // Allocates a span and places it in scope so that code between here and onFinish can see it Span span = threadLocalSpan.next(); if (span == null || span.isNoop()) return; // skip below logic on noop // Assume you have code to start the span and add relevant tags... } public void onFinish(Response response, Attributes attributes) { // as long as we are on the same thread, we can read the span started above Span span = threadLocalSpan.remove(); if (span == null || span.isNoop()) return; // skip below logic on noop // Assume you have code to complete the span } }
-
-
Field Summary
Fields Modifier and Type Field Description static ThreadLocalSpanCURRENT_TRACERThis uses theTracing.currentTracer(), which means calls tonext()may return null.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description static ThreadLocalSpancreate(Tracer tracer)Spannext()Returns theTracer.nextSpan()or null ifCURRENT_TRACERand tracing isn't available.Spannext(TraceContextOrSamplingFlags extracted)Returns theTracer.nextSpan(TraceContextOrSamplingFlags)or null ifCURRENT_TRACERand tracing isn't available.Spanremove()Returns the span set in scope vianext()or null if there was none.
-
-
-
Field Detail
-
CURRENT_TRACER
public static final ThreadLocalSpan CURRENT_TRACER
This uses theTracing.currentTracer(), which means calls tonext()may return null. Use this when you have no other means to get a reference to the tracer. For example, JDBC connections, as they often initialize prior to the tracing component.
-
-
Method Detail
-
create
public static ThreadLocalSpan create(Tracer tracer)
-
next
@Nullable public Span next(TraceContextOrSamplingFlags extracted)
Returns theTracer.nextSpan(TraceContextOrSamplingFlags)or null ifCURRENT_TRACERand tracing isn't available.
-
next
@Nullable public Span next()
Returns theTracer.nextSpan()or null ifCURRENT_TRACERand tracing isn't available.
-
remove
@Nullable public Span remove()
Returns the span set in scope vianext()or null if there was none.When assertions are on, this will throw an assertion error if the span returned was not the one currently in context. This could happen if someone called
Tracer.withSpanInScope(Span)orCurrentTraceContext.newScope(TraceContext)outside a try/finally block.
-
-