[#3594] feature(messaging, extensions/spring): introduce AF5 tracing support#4713
Draft
MateuszNaKodach wants to merge 2 commits into
Draft
[#3594] feature(messaging, extensions/spring): introduce AF5 tracing support#4713MateuszNaKodach wants to merge 2 commits into
MateuszNaKodach wants to merge 2 commits into
Conversation
b8a87b0 to
aa8be01
Compare
MateuszNaKodach
commented
Jul 7, 2026
MateuszNaKodach
commented
Jul 7, 2026
0c7b974 to
888a0c2
Compare
888a0c2 to
f7a94d4
Compare
MateuszNaKodach
commented
Jul 7, 2026
Comment on lines
+113
to
+126
| public MessageStream.Empty<Message> handle(EventMessage event, ProcessingContext context) { | ||
| // Open the batch span once per batch, on the first event -- unless disabled by configuration. Note: the span | ||
| // is started (which mutates the context via putResource) OUTSIDE a computeResourceIfAbsent supplier -- | ||
| // mutating a ProcessingContext from within such a supplier is rejected as a re-entrant ("recursive") update. | ||
| if (!disableBatchTrace && context.getResource(BATCH_SPAN_KEY) == null) { | ||
| context.putResource(BATCH_SPAN_KEY, openBatchSpan(context)); | ||
| } | ||
| String spanName = PROCESS_SPAN + " " + event.type().qualifiedName().name(); | ||
| Span handlerSpan = continuesPublisherTrace(event) | ||
| ? spanFactory.createHandlerSpan(spanName, event, context) | ||
| : spanFactory.createDisconnectedHandlerSpan(spanName, event, context); | ||
| handlerSpan.start(context); | ||
| return delegate.handle(event, context); | ||
| } |
Contributor
Author
There was a problem hiding this comment.
TODO:
investigate that and how it works.
MateuszNaKodach
commented
Jul 7, 2026
| * Decides whether the per-event handler span continues the publisher's trace: only when | ||
| * {@code distributedInSameTrace} is enabled AND the event is younger than | ||
| * {@code distributedInSameTraceTimeLimit}. Stale events -- typically replays -- get a disconnected span (new trace | ||
| * linked back to the publisher) so they do not stretch a long-finished trace (AF4 parity). |
Contributor
Author
There was a problem hiding this comment.
TODO: remove af4 references.
MateuszNaKodach
commented
Jul 7, 2026
Comment on lines
+145
to
147
| if (Segment.fromContext(context).isEmpty()) { | ||
| return NoOpSpanFactory.INSTANCE.createRootSpan(BATCH_SPAN, context); | ||
| } |
Contributor
Author
There was a problem hiding this comment.
Why is it needed?
MateuszNaKodach
commented
Jul 7, 2026
| * Each subscribed {@link QueryHandler} is wrapped so that handling opens a handler span -- parented on the dispatch span | ||
| * via the propagated context -- bound to the handling {@link ProcessingContext}'s lifecycle. | ||
| * <p> | ||
| * Update emission (the AF4 {@code QueryUpdateEmitter} concern) is traced here too: AF5's |
Contributor
Author
There was a problem hiding this comment.
Remove this AF4 reference.
MateuszNaKodach
commented
Jul 7, 2026
| * <p> | ||
| * This is best-effort: the attribute is present only when a legacy aggregate-based event storage engine populated the | ||
| * resource. It is absent for dynamic-consistency-boundary / entity-based operations and whenever no context is | ||
| * available. This provider intentionally does not reference any Axon Framework 4-era message type. |
Contributor
Author
There was a problem hiding this comment.
Remove Axon Framework 4 references.
MateuszNaKodach
commented
Jul 7, 2026
| * <p> | ||
| * Creating {@link Span spans} is the responsibility of the {@link SpanFactory} which should be implemented by the | ||
| * tracing provider of choice. | ||
| * <b>No {@code ThreadLocal}.</b> Parent/child relationships are never derived from a thread-bound "current span". |
Contributor
Author
There was a problem hiding this comment.
Explanation:
This may change in the future commits in order to support nested with invocations of things like JPA/JDBC/gRPC etc.
94fa15b to
0854a88
Compare
MateuszNaKodach
commented
Jul 7, 2026
| * @param context the active processing context, or {@code null} when none is available | ||
| * @return the created span (not yet started) | ||
| */ | ||
| Span createRootTrace(Supplier<String> operationNameSupplier); |
Contributor
Author
There was a problem hiding this comment.
Explanation:
Suppliers were removed, because now we do not wrap internal invocations, if there is no provided SpanFactory.
Add distributed tracing support to axon-messaging using AF5 component configuration, decorator ordering and ProcessingContext semantics. The core tracing API lives in org.axonframework.messaging.tracing. Command, event and query decorators live in their component-owned tracing packages: - org.axonframework.messaging.commandhandling.tracing - org.axonframework.messaging.eventhandling.tracing - org.axonframework.messaging.queryhandling.tracing Implement the AF5 tracing API: - SpanFactory is the single public span-creation contract. - SpanFactory implementations receive SpanAttributesProvider instances at construction time through SpanAttributesProviderRegistry. - Tracing is disabled by omitting a SpanFactory component; enhancers then leave messaging components undecorated. - Span parent resolution uses ProcessingContext and message metadata, never ThreadLocal state. - NoOpSpanFactory is a test/composition null-object. - MultiSpanFactory and LoggingSpanFactory follow the provider-list construction model. Add messaging tracing configuration: - TracingConfigurationDefaults and TracingConfigurationOrder. - MessagingTracingSettings. - MessagingTracingConfigurationEnhancer. - MessagingSpanAttributesProviderConfigurationEnhancer. - ServiceLoader entries for configuration and handler enhancement. - @RegistrationScope on tracing enhancers to prevent duplicate decorator registration in child component registries. - Near-maximal tracing decorator order so spans wrap inner framework decorators and measure caller-visible operations. Add messaging instrumentation: - TracingCommandBus opens dispatch and handle spans. - TracingEventSink and TracingEventBus trace publish and commit operations while preserving EventSink/EventBus type compatibility. - TracingEventHandlingComponent supports batch spans, distributed-in-same-trace behavior, disconnected handler spans and time-limit settings. - TracingQueryBus covers query, subscription query, update emission and subscription completion operations. - TracingHandlerEnhancerDefinition is contributed through the standard HandlerEnhancerDefinition ServiceLoader entry and wraps command, event and query handling members generically. - MetadataSpanAttributesProvider reads staged correlation data from the ProcessingContext so dispatch spans observe the metadata that interceptors place on outgoing messages. Update the existing tracing surface: - Use the single SpanFactory contract instead of per-component span factory families. - Keep built-in messaging attributes focused on message-id, message-type and metadata. - Add registry-based provider contribution. - Add focused unit coverage for command, event, query, handler and attribute-provider tracing. - Adapt logging-span tests to the messaging module's Log4j test infrastructure. Resolve SpanFactory absence via the ComponentNotFoundException contract only: a Spring-backed Configuration also signals absence through this same exception type, so the extra RuntimeException/getOptionalComponent fallback previously carried here was dead defensive code. Introduce EntityIdSpanAttributesProvider, a plain holder for the generic "axoniq.entity.id" key. AggregateIdentifierSpanAttributesProvider remains the dedicated, legacy-only provider for events sourced through an aggregate-based event storage engine; its javadoc now states this explicitly, and DCB events are tagged by EventTagsSpanAttributesProvider instead. TracingHandlerEnhancerDefinition drops its explicit-SpanFactory constructor: ApplicationContext#component only ever throws ComponentNotFoundException by contract, so the UnsupportedOperationException branch it guarded against (a ProcessingContext with no ApplicationContext at all) never occurs on the real handler-invocation path, only in hand-rolled tests. The constructor existed purely to let tests skip building a StubProcessingContext; tests now do that directly instead. Drop MetadataContextPropagator and its PublicApiSurfaceTest entry: a designed-but-unconsumed extension point with no implementers, no SPI registration, and no caller anywhere in the framework. The actual propagation path is Span#propagateContext(Message), implemented by backend SpanFactory bindings outside this repository.
…racing auto-configuration Add Spring Boot auto-configuration for AF5 messaging tracing, translating the axon.tracing.* properties into the framework's native tracing configuration. - TracingProperties binds the axon.tracing namespace: the master switch and the messaging-owned per-component toggles (command-bus, event-sink, event-processor with batch/distributed sub-toggles, query-bus) plus the message-id, message-type and metadata attribute-provider toggles. - TracingAutoConfiguration registers MessagingTracingSettings via registerIfNotPresent, so a user-defined settings bean or component always wins, and bridges user-declared SpanAttributesProvider beans into the SpanAttributesProviderRegistry. - showEventSourcingHandlers is deliberately not yet exposed as a Spring property here: it is an @EventSourcingHandler concern wired up alongside the eventsourcing tracing auto-configuration, even though the toggle itself lives on this messaging-owned settings record. - The SpanFactory stays an optional backend contribution: without one, the ServiceLoader-discovered tracing enhancers leave every component undecorated, and the whole configuration backs off when axon.tracing.enabled=false. - Register the auto-configuration in AutoConfiguration.imports and add focused ApplicationContextRunner coverage asserting the property translation at the framework-component level.
0854a88 to
9826ace
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WORK IN PROGRESS, DO NOT REVIEW NOW!!!!
This PR assumes that following PR will be merged to main first:
ComponentRegistrycontract #4719Changes from AF4:
What is not covered by this PR: