Class MicrometerSpanFactory
- All Implemented Interfaces:
DescribableComponent,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 Summary
ConstructorsConstructorDescriptionMicrometerSpanFactory(io.micrometer.tracing.Tracer tracer, io.micrometer.tracing.propagation.Propagator propagator) Initializes the factory against the giventracerandpropagator, without anySpanAttributesProviders.MicrometerSpanFactory(io.micrometer.tracing.Tracer tracer, io.micrometer.tracing.propagation.Propagator propagator, List<SpanAttributesProvider> attributesProviders) Initializes the factory against the giventracerandpropagator, with the givenattributesProviderscontributing attributes to every message-carrying span this factory produces. -
Method Summary
Modifier and TypeMethodDescriptioncreateContextParentHandlerSpan(String operationName, Message message, @Nullable ProcessingContext context) Creates aSpanfor an inbound (handler / consumer) operation that runs inside an independently traced processing context.createDisconnectedHandlerSpan(String operationName, Message message, @Nullable ProcessingContext context) Creates aSpanfor an inbound (handler / consumer) operation that should start a new trace (root) yet remain navigable to the producing trace through a span link.createDispatchSpan(String operationName, Message message, @Nullable ProcessingContext context) createHandlerSpan(String operationName, Message message, @Nullable ProcessingContext context) createInternalSpan(String operationName, @Nullable ProcessingContext context) createLinkedHandlerSpan(String operationName, Message message, Message linkedMessage, @Nullable ProcessingContext context) createRootSpan(String operationName, @Nullable ProcessingContext context) Creates aSpanthat always starts a new trace (a root), ignoring any active span when resolving its own parent.voiddescribeTo(ComponentDescriptor descriptor) Describe the properties ofthis DescribableComponentwith the givendescriptor.
-
Constructor Details
-
MicrometerSpanFactory
public MicrometerSpanFactory(io.micrometer.tracing.Tracer tracer, io.micrometer.tracing.propagation.Propagator propagator) Initializes the factory against the giventracerandpropagator, without anySpanAttributesProviders. Convenience constructor equivalent tonew MicrometerSpanFactory(tracer, propagator, List.of()).- Parameters:
tracer- the Micrometer tracer producing spanspropagator- 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 giventracerandpropagator, with the givenattributesProviderscontributing 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
SpanAttributesProviderRegistrycomponent.- Parameters:
tracer- the Micrometer tracer producing spanspropagator- the Micrometer propagator injecting/extracting trace context to/from message metadataattributesProviders- 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:SpanFactoryCreates aSpanfor an outbound (dispatch / producer) operation on the givenMessage. The parent is the active span oncontext(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 inmessage's metadata, then the implementation's optional ambient fallback, then a new root). Thecontext, when non-null, is also forwarded to everySpanAttributesProviderthe implementation was constructed with.- Specified by:
createDispatchSpanin interfaceSpanFactory- Parameters:
operationName- the span namemessage- the message the operation acts oncontext- the active processing context, ornullwhen 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:SpanFactoryCreates aSpanfor an inbound (handler / consumer) operation on the givenMessage. The parent is the tracing context propagated inmessage's metadata (cross-thread / cross-process); when none is present, the active span oncontext; when neither is present, the implementation's optional ambient fallback applies before a new root (see the class-level parent-resolution notes).- Specified by:
createHandlerSpanin interfaceSpanFactory- Parameters:
operationName- the span namemessage- the message being handledcontext- the active processing context, ornullwhen 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:SpanFactoryCreates aSpanfor an inbound (handler / consumer) operation that runs inside an independently traced processing context. The parent is the active span oncontext; the tracing context propagated inmessage'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
contextover 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 frommessageand attach it as a link; when no link can be extracted, the span is still created and this method never throws.- Specified by:
createContextParentHandlerSpanin interfaceSpanFactory- Parameters:
operationName- the span namemessage- the message being handled -- its metadata supplies the link targetcontext- the processing context supplying the structural parent, ornullwhen 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:SpanFactoryCreates aSpanfor an inbound (handler / consumer) operation on the givenMessage, with an additional link tolinkedMessage'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 fromlinkedMessage'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 inSpanFactory.createHandlerSpan(String, Message, ProcessingContext).- Specified by:
createLinkedHandlerSpanin interfaceSpanFactory- Parameters:
operationName- the span namemessage- the message being handledlinkedMessage- the message whose span context is linked tocontext- the active processing context, ornullwhen none is available- Returns:
- the created span (not yet started)
-
createInternalSpan
Description copied from interface:SpanFactoryCreates aSpanfor an internal operation that is not directly tied to aMessage. The parent is the active span oncontext(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 viaSpan.addAttribute(String, String).- Specified by:
createInternalSpanin interfaceSpanFactory- Parameters:
operationName- the span namecontext- the active processing context, ornullwhen none is available- Returns:
- the created span (not yet started)
-
createRootSpan
Description copied from interface:SpanFactoryCreates aSpanthat 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. Whencontextis 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
contextcarries 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:
createRootSpanin interfaceSpanFactory- Parameters:
operationName- the span namecontext- the processing context the root should become the active span of (and link back to), ornull- Returns:
- the created root span (not yet started)
-
createDisconnectedHandlerSpan
public Span createDisconnectedHandlerSpan(String operationName, Message message, @Nullable ProcessingContext context) Description copied from interface:SpanFactoryCreates aSpanfor 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 inmessage'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:
createDisconnectedHandlerSpanin interfaceSpanFactory- Parameters:
operationName- the span namemessage- the message being handled -- its metadata supplies the link targetcontext- the active processing context, ornullwhen none is available- Returns:
- the created span (not yet started)
-
describeTo
Description copied from interface:DescribableComponentDescribe the properties ofthis DescribableComponentwith the givendescriptor.Components should call the appropriate
describePropertymethods 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
DescribableComponentimplementation 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 thedescribeTomethod, 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:
describeToin interfaceDescribableComponent- Parameters:
descriptor- The component descriptor to describethis DescribableComponentn its properties in.
-