fix(spring-boot-autoconfigure): OpenTelemetry autoconfig to wire Spring-managed OpenTelemetry#4614
Open
MateuszNaKodach wants to merge 2 commits into
Open
fix(spring-boot-autoconfigure): OpenTelemetry autoconfig to wire Spring-managed OpenTelemetry#4614MateuszNaKodach wants to merge 2 commits into
MateuszNaKodach wants to merge 2 commits into
Conversation
… the span factory `OpenTelemetryAutoConfiguration#spanFactory()` built `OpenTelemetrySpanFactory` with no arguments, so its builder fell back to `GlobalOpenTelemetry.getTracer(...)` and `GlobalOpenTelemetry.getPropagators()` for tracer and W3C propagator. With Spring Boot 3 + `micrometer-tracing-bridge-otel` (Spring's recommended path) the `OpenTelemetry` bean is never registered as global, so both defaults resolve to no-ops — `propagateContext()` silently drops the W3C trace context and async Axon handlers (event processors, deadlines, distributed command/query buses) start disconnected root traces. Inject `ObjectProvider<OpenTelemetry>` and, when a Spring-managed bean is available, pass its tracer and `TextMapPropagator` explicitly to the builder. When no bean is available the defaults are kept, preserving compatibility with the OpenTelemetry Java agent and with manual SDK installations that call `OpenTelemetrySdkBuilder#buildAndRegisterGlobal()`. Adds two tests: - `spanFactoryUsesSpringManagedOpenTelemetryWhenAvailable` — verifies the factory's tracer and propagator are the same instances as the Spring-managed bean's, and behaviourally confirms `propagateContext` injects the W3C `traceparent` into message metadata. - `spanFactoryFallsBackToGlobalOpenTelemetryWhenNoBeanAvailable` — guards the legacy Java-agent / `buildAndRegisterGlobal()` path. Adds `opentelemetry-sdk` as a test-scope dependency to allow constructing a real `OpenTelemetry` with a W3C propagator.
…properties for span nesting and propagation timing
aa4e585 to
196f1c8
Compare
|
❌ The last analysis has failed. |
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.
Summary
OpenTelemetryAutoConfigurationcurrently builds theOpenTelemetrySpanFactorywithout passing in the application'sOpenTelemetryinstance:OpenTelemetrySpanFactory.Builder.build()then falls back toGlobalOpenTelemetry:This works for the OpenTelemetry Java agent and for setups that explicitly call
OpenTelemetrySdk.builder()…buildAndRegisterGlobal(). It silently breaks for Spring Boot 3 applications usingmicrometer-tracing-bridge-otel: Spring Boot creates anOpenTelemetrybean (intentionally not registered as global, to avoid hidden static state in the container) and themicrometer-tracing-bridge-oteladapter consumes it via dependency injection. BecauseGlobalOpenTelemetryis never populated, both builder defaults resolve to no-ops —propagateContext()silently drops the W3C trace context across every asynchronous Axon boundary (event processors, deadlines, distributed command/query buses) without any error or warning.The symptoms are subtle: HTTP-side spans render correctly inside one trace, but
StreamingEventProcessor.process(…),EventProcessor.process(…),CommandBus.handleDistributedCommand(…)etc. always start brand-new root traces with no link back to the originator. The framework's documented linking behaviour ("asynchronous invocations are linked to their originating spans") becomes effectively unreachable, because the parent context never makes it into the message metadata in the first place.Fix
Inject
ObjectProvider<OpenTelemetry>and, when a Spring-managedOpenTelemetrybean is available, explicitly wire itsTracerandTextMapPropagatorinto the builder. If no bean is present, the previous default behaviour is preserved:Backwards compatibility
-javaagent:opentelemetry-javaagent.jar)GlobalOpenTelemetry; no SpringOpenTelemetrybean exists → builder defaults pick it upObjectProvider.getIfAvailable()returnsnull→ builder defaults pick upGlobalOpenTelemetrybuildAndRegisterGlobal()(the path the Axon reference guide describes)GlobalOpenTelemetryusedOpenTelemetrybean is not exposed in Spring (the usual case): identical. If it is exposed: the same SDK instance is wired explicitly — observationally identicalmicrometer-tracing-bridge-otelOpenTelemetrywired in; W3C context propagated, span links visible across async boundariesThe legacy fallback to
GlobalOpenTelemetryremains intact for users on the Java agent or manual SDK setups. The@ConditionalOnMissingBean(SpanFactory.class)guard is unchanged, so users with a customSpanFactorybean are unaffected.Notes
micrometer-tracing-bridge-otel+axon-tracing-opentelemetry4.13.1 application: after the fix,propagateContext()injects the W3Ctraceparentinto message metadata (confirmed by inspecting stored event metadata and by the added regression test). Without this fix, message metadata stays empty and async handlers cannot reconstruct the parent context — making the documented span-linking behaviour effectively unreachable, regardless of what other tracing properties (axon.tracing.event-processor.distributed-in-same-trace,…disable-batch-trace, etc.) are configured.