Class MicrometerSpanFactory

java.lang.Object
io.axoniq.framework.tracing.micrometer.MicrometerSpanFactory
All Implemented Interfaces:
DescribableComponent, SpanFactory

public final class MicrometerSpanFactory extends Object implements SpanFactory
SpanFactory implementation backed by Micrometer Tracing. It produces spans that delegate to Micrometer's Span, obtained from an application-configured Tracer and Propagator.

No ThreadLocal writes. A span's parent is resolved from (1) the SpanScope carried on the supplied ProcessingContext under the single, framework-generic SpanScope.RESOURCE_KEY (in-process nesting), unwrapped to the Micrometer TraceContext via Span.context(), and (2) the trace context propagated in an inbound Message's metadata (handler spans, via the application Propagator). As the lowest-priority, read-only fallback, the current tracer context is consulted. The current tracer context is the context installed by external instrumentation and exposed through tracer.currentTraceContext().context(). Context is propagated onto outbound messages by Span.propagateContext(Message). This class never writes a ThreadLocal.

There is no no-argument constructor: Micrometer has no GlobalOpenTelemetry equivalent. The host application supplies the Tracer and Propagator (tests use Tracer.NOOP / Propagator.NOOP or a bridge over an in-memory OpenTelemetry SDK).

Since:
5.3.0
Author:
Mateusz Nowak
  • Constructor Details

    • MicrometerSpanFactory

      public MicrometerSpanFactory(io.micrometer.tracing.Tracer tracer, io.micrometer.tracing.propagation.Propagator propagator)
      Initializes the factory against the given tracer and propagator, without any SpanAttributesProviders. Convenience constructor equivalent to new MicrometerSpanFactory(tracer, propagator, List.of()).
      Parameters:
      tracer - the Micrometer tracer producing spans
      propagator - the Micrometer propagator injecting/extracting trace context to/from message metadata
    • MicrometerSpanFactory

      public MicrometerSpanFactory(io.micrometer.tracing.Tracer tracer, io.micrometer.tracing.propagation.Propagator propagator, List<SpanAttributesProvider> attributesProviders)
      Initializes the factory against the given tracer and propagator, with the given attributesProviders contributing attributes to every message-carrying span this factory produces.

      The provider list is the complete set for this factory's lifetime. When the factory is built by the framework configuration, the list is resolved from the SpanAttributesProviderRegistry component.

      Parameters:
      tracer - the Micrometer tracer producing spans
      propagator - the Micrometer propagator injecting/extracting trace context to/from message metadata
      attributesProviders - the providers contributing attributes to every message-carrying span
  • Method Details

    • createDispatchSpan

      public Span createDispatchSpan(String operationName, Message message, @Nullable ProcessingContext context)
      Description copied from interface: SpanFactory
      Creates a Span for an outbound (dispatch / producer) operation on the given Message. The parent is the active span on context (when present), so a message dispatched from within another traced operation nests under it; otherwise resolution continues per the class-level parent-resolution notes (the context propagated in message's metadata, then the implementation's optional ambient fallback, then a new root). The context, when non-null, is also forwarded to every SpanAttributesProvider the implementation was constructed with.
      Specified by:
      createDispatchSpan in interface SpanFactory
      Parameters:
      operationName - the span name
      message - the message the operation acts on
      context - the active processing context, or null when none is available
      Returns:
      the created span (not yet started)
    • createHandlerSpan

      public Span createHandlerSpan(String operationName, Message message, @Nullable ProcessingContext context)
      Description copied from interface: SpanFactory
      Creates a Span for an inbound (handler / consumer) operation on the given Message. The parent is the tracing context propagated in message's metadata (cross-thread / cross-process); when none is present, the active span on context; when neither is present, the implementation's optional ambient fallback applies before a new root (see the class-level parent-resolution notes).
      Specified by:
      createHandlerSpan in interface SpanFactory
      Parameters:
      operationName - the span name
      message - the message being handled
      context - the active processing context, or null when none is available
      Returns:
      the created span (not yet started)
    • createContextParentHandlerSpan

      public Span createContextParentHandlerSpan(String operationName, Message message, @Nullable ProcessingContext context)
      Description copied from interface: SpanFactory
      Creates a Span for an inbound (handler / consumer) operation that runs inside an independently traced processing context. The parent is the active span on context; the tracing context propagated in message's metadata is attached as a span link instead of replacing that parent. This keeps an enclosing operation, such as a streaming-event-processor batch, as the structural parent while preserving navigation to the producer that created the handled message.

      Implementations MUST prefer the active span on context over the propagated message context. When no active context span is available, the implementation's optional ambient fallback applies before a new root. Implementations MUST independently extract the propagated context from message and attach it as a link; when no link can be extracted, the span is still created and this method never throws.

      Specified by:
      createContextParentHandlerSpan in interface SpanFactory
      Parameters:
      operationName - the span name
      message - the message being handled -- its metadata supplies the link target
      context - the processing context supplying the structural parent, or null when unavailable
      Returns:
      the created span (not yet started)
    • createLinkedHandlerSpan

      public Span createLinkedHandlerSpan(String operationName, Message message, Message linkedMessage, @Nullable ProcessingContext context)
      Description copied from interface: SpanFactory
      Creates a Span for an inbound (handler / consumer) operation on the given Message, with an additional link to linkedMessage's span context. The link expresses a relationship between traces without changing the span's parent; tracing backends typically render it as navigation between the linked traces. Implementations MUST extract the propagated context from linkedMessage's metadata and attach it as a span link; when no link can be extracted the span is still created without the link, and this method never throws. Parent resolution is as in SpanFactory.createHandlerSpan(String, Message, ProcessingContext).
      Specified by:
      createLinkedHandlerSpan in interface SpanFactory
      Parameters:
      operationName - the span name
      message - the message being handled
      linkedMessage - the message whose span context is linked to
      context - the active processing context, or null when none is available
      Returns:
      the created span (not yet started)
    • createInternalSpan

      public Span createInternalSpan(String operationName, @Nullable ProcessingContext context)
      Description copied from interface: SpanFactory
      Creates a Span for an internal operation that is not directly tied to a Message. The parent is the active span on context (when present), so the internal span nests under the operation that opened it (for example a handler span); otherwise the implementation's optional ambient fallback applies before a new root (see the class-level parent-resolution notes). Non-message attributes are attached by the calling decorator via Span.addAttribute(String, String).
      Specified by:
      createInternalSpan in interface SpanFactory
      Parameters:
      operationName - the span name
      context - the active processing context, or null when none is available
      Returns:
      the created span (not yet started)
    • createRootSpan

      public Span createRootSpan(String operationName, @Nullable ProcessingContext context)
      Description copied from interface: SpanFactory
      Creates a Span that always starts a new trace (a root), ignoring any active span when resolving its own parent. Use this for operations that legitimately begin their own trace and must not attach to a stale or unrelated active span -- for example an event-processing batch boundary or an out-of-band snapshot operation running on a pooled thread. When context is non-null, starting the span still records it as that context's active span, so spans created next with that context nest under this root.

      When context carries an active span, implementations MUST attach that span as a span link (not as a parent), preserving the relationship to the operation that triggered it without creating a parent-of relationship to that operation.

      Specified by:
      createRootSpan in interface SpanFactory
      Parameters:
      operationName - the span name
      context - the processing context the root should become the active span of (and link back to), or null
      Returns:
      the created root span (not yet started)
    • createDisconnectedHandlerSpan

      public Span createDisconnectedHandlerSpan(String operationName, Message message, @Nullable ProcessingContext context)
      Description copied from interface: SpanFactory
      Creates a Span for an inbound (handler / consumer) operation that should start a new trace (root) yet remain navigable to the producing trace through a span link. The link target is the tracing context propagated in message's metadata.

      This is the "distributed-in-different-trace" handling mode. Use it when joining the publisher's trace would either flood it (long-running consumers, batch processors) or cross trust / lifecycle boundaries, while keeping the consumer's new trace navigable back to the producer through the link.

      Implementations MUST start a new trace (no parent-of relationship to the producer), extract the producer's context from message's metadata and attach it as a span link. When no link can be extracted (e.g. no tracing context on the message), the span is still created without a link and this method never throws.

      Specified by:
      createDisconnectedHandlerSpan in interface SpanFactory
      Parameters:
      operationName - the span name
      message - the message being handled -- its metadata supplies the link target
      context - the active processing context, or null when none is available
      Returns:
      the created span (not yet started)
    • describeTo

      public void describeTo(ComponentDescriptor descriptor)
      Description copied from interface: DescribableComponent
      Describe the properties of this DescribableComponent with the given descriptor.

      Components should call the appropriate describeProperty methods on the descriptor to register their properties. The descriptor is responsible for determining how these properties are formatted and structured in the final output.

      Best Practices: As a general rule, all relevant fields of a DescribableComponent implementation should be described in this method. However, developers have discretion to include only the fields that make sense in the context. Not every field may be meaningful for description purposes, especially internal implementation details. Furthermore, components might want to expose different information based on their current state. The final decision on what properties to include lies with the person implementing the describeTo method, who should focus on providing information that is useful for understanding the component's configuration and state.

      Example implementation:

       public void describeTo(ComponentDescriptor descriptor) {
           descriptor.describeProperty("name", this.name);
           descriptor.describeProperty("enabled", this.enabled);
           descriptor.describeProperty("configuration", this.configuration); // A nested component
           descriptor.describeProperty("handlers", this.eventHandlers);      // A collection
       }
       
      Specified by:
      describeTo in interface DescribableComponent
      Parameters:
      descriptor - The component descriptor to describe this DescribableComponentn its properties in.