Back off on Propagator in Brave and Otel auto-configurations

This also fixes the bug that both auto-configurations couldn't be used
together.

Closes gh-49183
This commit is contained in:
Moritz Halbritter
2026-02-13 13:48:38 +01:00
parent 6f303032e2
commit cdf8d2e9c8
5 changed files with 66 additions and 4 deletions
@@ -39,6 +39,7 @@ import io.micrometer.tracing.brave.bridge.CompositeSpanHandler;
import io.micrometer.tracing.exporter.SpanExportingPredicate;
import io.micrometer.tracing.exporter.SpanFilter;
import io.micrometer.tracing.exporter.SpanReporter;
import io.micrometer.tracing.propagation.Propagator;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
@@ -166,7 +167,7 @@ public final class BraveAutoConfiguration {
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnMissingBean(Propagator.class)
BravePropagator bravePropagator(Tracing tracing) {
return new BravePropagator(tracing);
}
@@ -39,6 +39,7 @@ import io.micrometer.observation.Observation;
import io.micrometer.observation.Observation.Scope;
import io.micrometer.observation.ObservationRegistry;
import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
import io.micrometer.tracing.brave.bridge.BravePropagator;
import io.micrometer.tracing.brave.bridge.BraveSpanCustomizer;
import io.micrometer.tracing.brave.bridge.BraveTracer;
import io.micrometer.tracing.brave.bridge.CompositeSpanHandler;
@@ -46,6 +47,7 @@ import io.micrometer.tracing.brave.bridge.W3CPropagation;
import io.micrometer.tracing.exporter.SpanExportingPredicate;
import io.micrometer.tracing.exporter.SpanFilter;
import io.micrometer.tracing.exporter.SpanReporter;
import io.micrometer.tracing.propagation.Propagator;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
@@ -126,6 +128,15 @@ class BraveAutoConfigurationTests {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(BraveTracer.class));
}
@Test
void shouldNotSupplyBravePropagatorWhenPropagatorBeanIsPresent() {
this.contextRunner.withUserConfiguration(PropagatorConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(Propagator.class);
assertThat(context).hasBean("customPropagator");
assertThat(context).doesNotHaveBean(BravePropagator.class);
});
}
@Test
void shouldNotSupplyBeansIfBraveIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("brave"))
@@ -535,4 +546,14 @@ class BraveAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
static class PropagatorConfiguration {
@Bean
Propagator customPropagator() {
return mock(Propagator.class);
}
}
}
@@ -49,7 +49,9 @@ dependencies {
dockerTestImplementation("org.testcontainers:testcontainers-junit-jupiter")
testImplementation(project(":core:spring-boot-test"))
testImplementation(project(":module:spring-boot-micrometer-tracing-brave"))
testImplementation(project(":test-support:spring-boot-test-support"))
testImplementation("io.micrometer:micrometer-tracing-bridge-brave")
testImplementation("com.squareup.okhttp3:mockwebserver")
testImplementation("io.micrometer:micrometer-registry-prometheus")
testImplementation("io.opentelemetry:opentelemetry-exporter-common")
@@ -31,6 +31,7 @@ import io.micrometer.tracing.otel.bridge.OtelSpanCustomizer;
import io.micrometer.tracing.otel.bridge.OtelTracer;
import io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;
import io.micrometer.tracing.otel.bridge.Slf4JEventListener;
import io.micrometer.tracing.propagation.Propagator;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.Tracer;
@@ -164,7 +165,7 @@ public final class OpenTelemetryTracingAutoConfiguration {
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnMissingBean(Propagator.class)
OtelPropagator otelPropagator(ContextPropagators contextPropagators, Tracer tracer) {
return new OtelPropagator(contextPropagators, tracer);
}
@@ -27,6 +27,8 @@ import java.util.concurrent.TimeoutException;
import io.micrometer.tracing.SpanCustomizer;
import io.micrometer.tracing.Tracer.SpanInScope;
import io.micrometer.tracing.handler.PropagatingReceiverTracingObservationHandler;
import io.micrometer.tracing.handler.PropagatingSenderTracingObservationHandler;
import io.micrometer.tracing.otel.bridge.EventListener;
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
import io.micrometer.tracing.otel.bridge.OtelPropagator;
@@ -36,6 +38,7 @@ import io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;
import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;
import io.micrometer.tracing.otel.bridge.Slf4JEventListener;
import io.micrometer.tracing.otel.propagation.BaggageTextMapPropagator;
import io.micrometer.tracing.propagation.Propagator;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.MeterProvider;
@@ -63,6 +66,8 @@ import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.micrometer.observation.autoconfigure.ObservationAutoConfiguration;
import org.springframework.boot.micrometer.tracing.autoconfigure.MicrometerTracingAutoConfiguration;
import org.springframework.boot.micrometer.tracing.brave.autoconfigure.BraveAutoConfiguration;
import org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
@@ -89,8 +94,7 @@ import static org.mockito.Mockito.mock;
class OpenTelemetryTracingAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
org.springframework.boot.opentelemetry.autoconfigure.OpenTelemetrySdkAutoConfiguration.class,
.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,
OpenTelemetryTracingAutoConfiguration.class));
@Test
@@ -179,6 +183,29 @@ class OpenTelemetryTracingAutoConfigurationTests {
});
}
@Test
void shouldNotSupplyOtelPropagatorWhenPropagatorBeanIsPresent() {
this.contextRunner.withUserConfiguration(PropagatorConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(Propagator.class);
assertThat(context).hasBean("customPropagator");
assertThat(context).doesNotHaveBean(OtelPropagator.class);
});
}
@Test
void shouldWorkWithBraveAutoConfigurationWhenBothConfigurationsAreOnClasspath() {
new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(OpenTelemetrySdkAutoConfiguration.class,
OpenTelemetryTracingAutoConfiguration.class, BraveAutoConfiguration.class,
ObservationAutoConfiguration.class, MicrometerTracingAutoConfiguration.class))
.run((context) -> {
assertThat(context).hasSingleBean(io.micrometer.tracing.Tracer.class);
assertThat(context).hasSingleBean(Propagator.class);
assertThat(context).hasSingleBean(PropagatingSenderTracingObservationHandler.class);
assertThat(context).hasSingleBean(PropagatingReceiverTracingObservationHandler.class);
});
}
@Test
void shouldSetupDefaultResourceAttributes() {
this.contextRunner
@@ -518,6 +545,16 @@ class OpenTelemetryTracingAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
static class PropagatorConfiguration {
@Bean
Propagator customPropagator() {
return mock(Propagator.class);
}
}
@Configuration(proxyBeanMethods = false)
private static final class SdkTracerProviderCustomizationConfiguration {