Interface SpanScope

All Superinterfaces:
AutoCloseable

public interface SpanScope extends AutoCloseable
The active-span scope returned by Span.start(). Closing the scope ends the underlying Span.

A SpanScope is the neutral, provider-agnostic handle to a span that is active on a context branch. It is carried on a ProcessingContext under RESOURCE_KEY and read back with fromContext(ProcessingContext) -- mirroring the RESOURCE_KEY / addToContext / fromContext convention of Message and TrackingToken. Two distinct carriers exist:

  • Lifecycle-covering spans (a batch span, a per-command/query handler span) are recorded on the root context by Span.coverLifecycle(ProcessingContext), last-writer-wins, exactly like Message.RESOURCE_KEY's "current message".
  • Branch-scoped spans (a per-event handler span, a per-invocation method span) are carried on an immutable branch via addToContext(ProcessingContext, SpanScope): the branch, not the root, is what flows into the operation's own handling, so its children read back exactly this scope while it is open. Once it closes, the branch falls back to the parent scope inherited when it was created. The context tree is therefore the parenting stack, including for a branch retained by deferred lifecycle work.
Both carriers use this same key; a reader never needs to know which flavor produced the scope it reads.
Since:
5.3.0
Author:
Mateusz Nowak
  • Field Details

    • RESOURCE_KEY

      static final Context.ResourceKey<SpanScope> RESOURCE_KEY
      Resource key under which the active SpanScope is carried on a ProcessingContext -- either on the root context (written by Span.coverLifecycle(ProcessingContext)) or on an immutable branch (via addToContext(ProcessingContext, SpanScope)) -- and read with fromContext(ProcessingContext).

      Question it answers: "Which scope is the parent for a span created with this exact context instance, and what is the active span for provider-agnostic access (for example Span.addAttribute(String, String))?"

      Why one key is enough. Precise parent chaining no longer needs a provider-private stack: a branch-scoped span branches the context it hands to its own operation, so every span created with that branch -- however deeply nested, however many other operations start and finish elsewhere on the root in the meantime -- reads back exactly the branch's scope. A lifecycle-covering span instead writes the root directly, matching Message.RESOURCE_KEY's last-writer-wins "current message" semantics, which is correct because such a span is the context's dominant operation for its entire lifetime.

  • Method Details

    • addToContext

      static ProcessingContext addToContext(ProcessingContext context, SpanScope scope)
      Returns a ProcessingContext carrying the given scope as the active span scope under RESOURCE_KEY. Functional helper for callers composing a context; note it returns a (possibly new) context rather than mutating the given one -- Span.coverLifecycle(ProcessingContext) instead mutates the live context so spans created next with that same instance can read the active scope.

      The parent carrier for the closed-scope fallback (see fromContext(ProcessingContext)) is captured from context at this moment. A lifecycle scope that later replaces the root's carrier (last-writer-wins, via Span.coverLifecycle(ProcessingContext)) does not re-target already-created branches: their fallback chain still ends at the scope inherited here.

      Parameters:
      context - the processing context to add the scope to
      scope - the active span scope to add
      Returns:
      the processing context carrying scope under RESOURCE_KEY
    • fromContext

      static @Nullable SpanScope fromContext(ProcessingContext context)
      Retrieves the active SpanScope from the given context under RESOURCE_KEY.
      Parameters:
      context - the processing context to read the active span scope from
      Returns:
      the active span scope, or null when none is present
    • span

      Span span()
      Returns the Span governed by this scope.
      Returns:
      the span this scope governs
    • isClosed

      boolean isClosed()
      Returns whether this scope has closed for context resolution. The result is monotonic and thread-safe: closing must transition it to true before ending the provider span, and once this method returns true, it must never return false again. A scope already observed as closed is skipped during parent resolution; a concurrent resolver that observes it immediately before closure may still select it as a legitimate in-flight parent.
      Returns:
      true after this scope has closed, otherwise false
      Since:
      5.3.0
    • close

      void close()
      Closes this scope, ending the underlying Span. Subsequent calls are no-ops -- implementations MUST be idempotent, so a synchronous throw (which closes the scope explicitly) and a later stream-termination callback (which would otherwise close it again) can safely overlap.
      Specified by:
      close in interface AutoCloseable
    • within

      <T> T within(Supplier<T> operation)
      Executes the given operation within this scope and returns its result. Any scope-bound state an implementation maintains is observable to code running inside the operation and detached again before this method returns. This is the provider extension point the structured Span operations execute through. Implementations MUST be transparent: return the operation's value, let its exceptions propagate unchanged, and never end the span. An implementation without scope-bound state simply executes the operation unchanged.
      Type Parameters:
      T - the operation's result type
      Parameters:
      operation - the operation to execute within this scope
      Returns:
      the value produced by operation
    • within

      default void within(Runnable operation)
      Executes the given void operation within this scope. Convenience overload of within(Supplier) for operations without a result; it routes through within(Supplier), so the same transparency rules apply.
      Parameters:
      operation - the operation to execute within this scope