Polish "Add support for MDC, Context Propagation (via B3 and W3C), and Baggage"

See gh-32480
This commit is contained in:
Andy Wilkinson 2022-09-26 17:27:27 +01:00
parent 52d1436dc6
commit 36a4b36ccb
6 changed files with 235 additions and 212 deletions

View File

@ -24,6 +24,7 @@ import brave.Tracing.Builder;
import brave.TracingCustomizer;
import brave.baggage.BaggageField;
import brave.baggage.BaggagePropagation;
import brave.baggage.BaggagePropagation.FactoryBuilder;
import brave.baggage.BaggagePropagationConfig;
import brave.baggage.BaggagePropagationCustomizer;
import brave.baggage.CorrelationScopeConfig;
@ -42,7 +43,6 @@ import brave.propagation.B3Propagation;
import brave.propagation.CurrentTraceContext;
import brave.propagation.CurrentTraceContext.ScopeDecorator;
import brave.propagation.CurrentTraceContextCustomizer;
import brave.propagation.Propagation;
import brave.propagation.Propagation.Factory;
import brave.propagation.ThreadLocalCurrentTraceContext;
import brave.sampler.Sampler;
@ -53,18 +53,17 @@ import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler;
import io.micrometer.tracing.brave.bridge.BravePropagator;
import io.micrometer.tracing.brave.bridge.BraveTracer;
import io.micrometer.tracing.brave.bridge.W3CPropagation;
import org.slf4j.MDC;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
/**
@ -175,29 +174,17 @@ public class BraveAutoConfiguration {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "management.tracing.baggage.enabled", havingValue = "false", matchIfMissing = true)
@ConditionalOnProperty(value = "management.tracing.baggage.enabled", havingValue = "false")
static class BraveNoBaggageConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "management.tracing.propagation.type", havingValue = "W3C",
matchIfMissing = true)
Factory w3cPropagationNoBaggageFactory() {
return new W3CPropagation(BRAVE_BAGGAGE_MANAGER, List.of()); // TODO: Use
// snapshots
// of
// tracing
// to not
// use
// baggage
// for W3C
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "management.tracing.propagation.type", havingValue = "B3")
Factory b3PropagationNoBaggageFactory() {
return B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
Factory propagationFactory(TracingProperties tracing) {
return switch (tracing.getPropagation().getType()) {
case B3 ->
B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
case W3C -> new W3CPropagation(BRAVE_BAGGAGE_MANAGER, List.of());
};
}
}
@ -206,74 +193,70 @@ public class BraveAutoConfiguration {
@ConditionalOnProperty(value = "management.tracing.baggage.enabled", matchIfMissing = true)
static class BraveBaggageConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "management.tracing.propagation.type", havingValue = "W3C",
matchIfMissing = true)
BaggagePropagation.FactoryBuilder w3cPropagationFactory() {
return BaggagePropagation.newFactoryBuilder(new W3CPropagation(BRAVE_BAGGAGE_MANAGER, List.of()));
private final TracingProperties tracingProperties;
BraveBaggageConfiguration(TracingProperties tracingProperties) {
this.tracingProperties = tracingProperties;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "management.tracing.propagation.type", havingValue = "B3")
BaggagePropagation.FactoryBuilder b3PropagationFactory() {
return BaggagePropagation.newFactoryBuilder(
B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build());
BaggagePropagation.FactoryBuilder propagationFactoryBuilder(
ObjectProvider<BaggagePropagationCustomizer> baggagePropagationCustomizers) {
Factory delegate = switch (this.tracingProperties.getPropagation().getType()) {
case B3 ->
B3Propagation.newFactoryBuilder().injectFormat(B3Propagation.Format.SINGLE_NO_PARENT).build();
case W3C -> new W3CPropagation(BRAVE_BAGGAGE_MANAGER, List.of());
};
FactoryBuilder builder = BaggagePropagation.newFactoryBuilder(delegate);
baggagePropagationCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
return builder;
}
@Bean
@Order(0)
BaggagePropagationCustomizer remoteFieldsBaggagePropagationCustomizer() {
return (builder) -> {
List<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();
for (String fieldName : remoteFields) {
builder.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(fieldName)));
}
};
}
@Bean
@ConditionalOnMissingBean
Propagation.Factory micrometerTracingPropagationWithBaggage(BaggagePropagation.FactoryBuilder factoryBuilder,
TracingProperties tracingProperties,
ObjectProvider<List<BaggagePropagationCustomizer>> baggagePropagationCustomizers) {
List<String> remoteFields = tracingProperties.getBaggage().getRemoteFields();
for (String fieldName : remoteFields) {
factoryBuilder.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(fieldName)));
}
baggagePropagationCustomizers.ifAvailable(
(customizers) -> customizers.forEach((customizer) -> customizer.customize(factoryBuilder)));
Factory propagationFactory(BaggagePropagation.FactoryBuilder factoryBuilder) {
return factoryBuilder.build();
}
@Bean
@ConditionalOnMissingBean(CorrelationScopeDecorator.class)
@ConditionalOnBean(CorrelationScopeDecorator.Builder.class)
@ConditionalOnProperty(value = "management.tracing.baggage.correlation.enabled", matchIfMissing = true)
ScopeDecorator correlationFieldsCorrelationScopeDecorator(TracingProperties properties,
ObjectProvider<List<CorrelationScopeCustomizer>> correlationScopeCustomizers,
CorrelationScopeDecorator.Builder builder) {
List<String> correlationFields = properties.getBaggage().getCorrelation().getFields();
for (String field : correlationFields) {
builder.add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(BaggageField.create(field))
.flushOnUpdate().build());
}
correlationScopeCustomizers
.ifAvailable((customizers) -> customizers.forEach((customizer) -> customizer.customize(builder)));
return builder.build();
}
@Bean
@ConditionalOnMissingBean(CorrelationScopeDecorator.class)
@ConditionalOnBean(CorrelationScopeDecorator.Builder.class)
@ConditionalOnProperty(value = "management.tracing.baggage.correlation.enabled", havingValue = "false")
ScopeDecorator noCorrelationFieldsCorrelationScopeDecorator(CorrelationScopeDecorator.Builder builder,
ObjectProvider<List<CorrelationScopeCustomizer>> correlationScopeCustomizers) {
correlationScopeCustomizers
.ifAvailable((customizers) -> customizers.forEach((customizer) -> customizer.customize(builder)));
return builder.build();
}
}
@Configuration(proxyBeanMethods = false)
static class CorrelationScopeDecoratorConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(MDC.class)
CorrelationScopeDecorator.Builder mdcCorrelationScopeDecoratorBuilder() {
return MDCScopeDecorator.newBuilder();
CorrelationScopeDecorator.Builder mdcCorrelationScopeDecoratorBuilder(
ObjectProvider<CorrelationScopeCustomizer> correlationScopeCustomizers) {
CorrelationScopeDecorator.Builder builder = MDCScopeDecorator.newBuilder();
correlationScopeCustomizers.forEach((customizer) -> customizer.customize(builder));
return builder;
}
@Bean
@Order(0)
@ConditionalOnProperty(prefix = "management.tracing.baggage.correlation", name = "enabled",
matchIfMissing = true)
CorrelationScopeCustomizer correlationFieldsCorrelationScopeCustomizer() {
return (builder) -> {
List<String> correlationFields = this.tracingProperties.getBaggage().getCorrelation().getFields();
for (String field : correlationFields) {
builder.add(CorrelationScopeConfig.SingleCorrelationField.newBuilder(BaggageField.create(field))
.flushOnUpdate().build());
}
};
}
@Bean
@ConditionalOnMissingBean(CorrelationScopeDecorator.class)
ScopeDecorator correlationScopeDecorator(CorrelationScopeDecorator.Builder builder) {
return builder.build();
}
}

View File

@ -53,8 +53,8 @@ import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
import org.slf4j.MDC;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -83,6 +83,12 @@ public class OpenTelemetryAutoConfiguration {
*/
private static final String DEFAULT_APPLICATION_NAME = "application";
private final TracingProperties tracingProperties;
OpenTelemetryAutoConfiguration(TracingProperties tracingProperties) {
this.tracingProperties = tracingProperties;
}
@Bean
@ConditionalOnMissingBean
OpenTelemetry openTelemetry(SdkTracerProvider sdkTracerProvider, ContextPropagators contextPropagators) {
@ -92,32 +98,31 @@ public class OpenTelemetryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
SdkTracerProvider otelSdkTracerProvider(Environment environment, List<SpanProcessor> spanProcessors,
SdkTracerProvider otelSdkTracerProvider(Environment environment, ObjectProvider<SpanProcessor> spanProcessors,
Sampler sampler) {
String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME);
SdkTracerProviderBuilder builder = SdkTracerProvider.builder().setSampler(sampler)
.setResource(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName)));
for (SpanProcessor spanProcessor : spanProcessors) {
builder.addSpanProcessor(spanProcessor);
}
spanProcessors.orderedStream().forEach(builder::addSpanProcessor);
return builder.build();
}
@Bean
@ConditionalOnMissingBean
ContextPropagators otelContextPropagators(List<TextMapPropagator> textMapPropagators) {
return ContextPropagators.create(TextMapPropagator.composite(textMapPropagators));
ContextPropagators otelContextPropagators(ObjectProvider<TextMapPropagator> textMapPropagators) {
return ContextPropagators
.create(TextMapPropagator.composite(textMapPropagators.orderedStream().collect(Collectors.toList())));
}
@Bean
@ConditionalOnMissingBean
Sampler otelSampler(TracingProperties properties) {
return Sampler.traceIdRatioBased(properties.getSampling().getProbability());
Sampler otelSampler() {
return Sampler.traceIdRatioBased(this.tracingProperties.getSampling().getProbability());
}
@Bean
SpanProcessor otelSpanProcessor(List<SpanExporter> spanExporter) {
return SpanProcessor.composite(spanExporter.stream()
SpanProcessor otelSpanProcessor(ObjectProvider<SpanExporter> spanExporters) {
return SpanProcessor.composite(spanExporters.orderedStream()
.map((exporter) -> BatchSpanProcessor.builder(exporter).build()).collect(Collectors.toList()));
}
@ -130,9 +135,9 @@ public class OpenTelemetryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
OtelTracer micrometerOtelTracer(Tracer tracer, EventPublisher eventPublisher,
OtelCurrentTraceContext otelCurrentTraceContext, TracingProperties properties) {
return new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher,
new OtelBaggageManager(otelCurrentTraceContext, properties.getBaggage().getRemoteFields(), List.of()));
OtelCurrentTraceContext otelCurrentTraceContext) {
return new OtelTracer(tracer, otelCurrentTraceContext, eventPublisher, new OtelBaggageManager(
otelCurrentTraceContext, this.tracingProperties.getBaggage().getRemoteFields(), List.of()));
}
@Bean
@ -168,93 +173,65 @@ public class OpenTelemetryAutoConfiguration {
new DefaultHttpServerAttributesExtractor());
}
@Configuration(proxyBeanMethods = false)
static class PropagationConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(B3Propagator.class)
static class B3NoBaggagePropagatorConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "management.tracing.propagation.type", havingValue = "B3")
B3Propagator b3TextMapPropagator() {
return B3Propagator.injectingSingleHeader();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "management.tracing.baggage.enabled", havingValue = "false")
static class W3CNoBaggagePropagatorConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "management.tracing.propagation.type", havingValue = "W3C",
matchIfMissing = true)
W3CTraceContextPropagator w3cTextMapPropagatorWithoutBaggage() {
return W3CTraceContextPropagator.getInstance();
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "management.tracing.baggage.enabled", matchIfMissing = true)
static class W3CBaggagePropagatorConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "management.tracing.propagation.type", havingValue = "W3C",
matchIfMissing = true)
TextMapPropagator w3cTextMapPropagatorWithBaggage() {
return TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(),
W3CBaggagePropagator.getInstance());
}
}
@Bean
@ConditionalOnMissingBean
Slf4JEventListener otelSlf4JEventListener() {
return new Slf4JEventListener();
}
@Configuration(proxyBeanMethods = false)
static class MicrometerTracingPropagationConfiguration {
@ConditionalOnProperty(prefix = "management.tracing.baggage", name = "enabled", matchIfMissing = true)
static class BaggageConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "management.tracing.baggage.enabled", matchIfMissing = true)
static class BaggagePropagatorConfiguration {
@Bean
@ConditionalOnProperty(value = "management.tracing.propagation.type", havingValue = "B3")
BaggageTextMapPropagator b3BaggageTextMapPropagator(TracingProperties properties,
OtelCurrentTraceContext otelCurrentTraceContext) {
return new BaggageTextMapPropagator(properties.getBaggage().getRemoteFields(), new OtelBaggageManager(
otelCurrentTraceContext, properties.getBaggage().getRemoteFields(), List.of()));
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MDC.class)
static class Slf4jConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "management.tracing.baggage.correlation.enabled", matchIfMissing = true)
Slf4JBaggageEventListener otelSlf4JBaggageEventListener(TracingProperties tracingProperties) {
return new Slf4JBaggageEventListener(tracingProperties.getBaggage().getCorrelation().getFields());
}
}
private final TracingProperties tracingProperties;
BaggageConfiguration(TracingProperties tracingProperties) {
this.tracingProperties = tracingProperties;
}
}
@Bean
@ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "W3C",
matchIfMissing = true)
TextMapPropagator w3cTextMapPropagatorWithBaggage() {
return TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(),
W3CBaggagePropagator.getInstance());
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MDC.class)
static class Slf4jConfiguration {
@Bean
@ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "B3")
TextMapPropagator b3BaggageTextMapPropagator(OtelCurrentTraceContext otelCurrentTraceContext) {
List<String> remoteFields = this.tracingProperties.getBaggage().getRemoteFields();
return TextMapPropagator.composite(B3Propagator.injectingSingleHeader(), new BaggageTextMapPropagator(
remoteFields, new OtelBaggageManager(otelCurrentTraceContext, remoteFields, List.of())));
}
@Bean
@ConditionalOnMissingBean
Slf4JEventListener otelSlf4JEventListener() {
return new Slf4JEventListener();
@ConditionalOnProperty(prefix = "management.tracing.baggage.correlation", name = "enabled",
matchIfMissing = true)
Slf4JBaggageEventListener otelSlf4JBaggageEventListener() {
return new Slf4JBaggageEventListener(this.tracingProperties.getBaggage().getCorrelation().getFields());
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "management.tracing.baggage", name = "enabled", havingValue = "false")
static class NoBaggageConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "B3")
B3Propagator b3TextMapPropagator() {
return B3Propagator.injectingSingleHeader();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "management.tracing.propagation", name = "type", havingValue = "W3C",
matchIfMissing = true)
W3CTraceContextPropagator w3cTextMapPropagatorWithoutBaggage() {
return W3CTraceContextPropagator.getInstance();
}
}

View File

@ -79,7 +79,7 @@ public class TracingProperties {
/**
* Whether to enable Micrometer Tracing baggage propagation.
*/
private boolean enabled;
private boolean enabled = true;
/**
* Correlation configuration.

View File

@ -36,11 +36,12 @@ import org.springframework.context.ApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for Baggage configuration.
* Tests for Baggage propagation with Brave and OpenTelemetry using W3C and B3 propagation
* formats.
*
* @author Marcin Grzejszczak
*/
class BaggageAutoConfigurationTests {
class BaggagePropagationIntegrationTests {
static final String COUNTRY_CODE = "country-code";
static final String BUSINESS_PROCESS = "bp";

View File

@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.tracing;
import brave.Tracer;
import brave.Tracing;
import brave.baggage.BaggagePropagation;
import brave.baggage.CorrelationScopeConfig.SingleCorrelationField;
import brave.http.HttpClientHandler;
import brave.http.HttpClientRequest;
import brave.http.HttpClientResponse;
@ -27,6 +28,7 @@ import brave.http.HttpServerRequest;
import brave.http.HttpServerResponse;
import brave.http.HttpTracing;
import brave.propagation.CurrentTraceContext;
import brave.propagation.CurrentTraceContext.ScopeDecorator;
import brave.propagation.Propagation;
import brave.propagation.Propagation.Factory;
import brave.sampler.Sampler;
@ -34,6 +36,8 @@ import io.micrometer.tracing.brave.bridge.BraveBaggageManager;
import io.micrometer.tracing.brave.bridge.BraveHttpClientHandler;
import io.micrometer.tracing.brave.bridge.BraveHttpServerHandler;
import io.micrometer.tracing.brave.bridge.BraveTracer;
import io.micrometer.tracing.brave.bridge.W3CPropagation;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.mockito.Answers;
@ -59,6 +63,7 @@ class BraveAutoConfigurationTests {
@Test
void shouldSupplyDefaultBeans() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(BraveAutoConfiguration.class);
assertThat(context).hasSingleBean(Tracing.class);
assertThat(context).hasSingleBean(Tracer.class);
assertThat(context).hasSingleBean(CurrentTraceContext.class);
@ -72,6 +77,9 @@ class BraveAutoConfigurationTests {
assertThat(context).hasSingleBean(BraveHttpClientHandler.class);
assertThat(context).hasSingleBean(Propagation.Factory.class);
assertThat(context).hasSingleBean(BaggagePropagation.FactoryBuilder.class);
assertThat(context).hasSingleBean(BraveTracer.class);
assertThat(context).hasSingleBean(BraveHttpServerHandler.class);
assertThat(context).hasSingleBean(BraveHttpClientHandler.class);
});
}
@ -118,6 +126,7 @@ class BraveAutoConfigurationTests {
});
}
@Test
void shouldNotSupplyBeansIfBraveIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("brave"))
.run((context) -> assertThat(context).doesNotHaveBean(BraveAutoConfiguration.class));
@ -125,14 +134,15 @@ class BraveAutoConfigurationTests {
@Test
void shouldNotSupplyBeansIfMicrometerIsMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader("brave"))
this.contextRunner.withClassLoader(new FilteredClassLoader("io.micrometer"))
.run((context) -> assertThat(context).doesNotHaveBean(BraveAutoConfiguration.class));
}
@Test
void shouldSupplyW3CPropagationFactoryByDefault() {
this.contextRunner.run((context) -> {
assertThat(context).hasBean("w3cPropagationFactory");
assertThat(context).hasBean("propagationFactory");
assertThat(context).hasSingleBean(W3CPropagation.class);
assertThat(context).hasSingleBean(BaggagePropagation.FactoryBuilder.class);
});
}
@ -140,7 +150,8 @@ class BraveAutoConfigurationTests {
@Test
void shouldSupplyB3PropagationFactoryViaProperty() {
this.contextRunner.withPropertyValues("management.tracing.propagation.type=B3").run((context) -> {
assertThat(context).hasBean("b3PropagationFactory");
assertThat(context).hasBean("propagationFactory");
assertThat(context.getBean(Factory.class).toString()).isEqualTo("B3Propagation");
assertThat(context).hasSingleBean(BaggagePropagation.FactoryBuilder.class);
});
}
@ -151,14 +162,6 @@ class BraveAutoConfigurationTests {
.run((context) -> assertThat(context).doesNotHaveBean(BraveAutoConfiguration.class));
}
@Test
void shouldNotSupplyMdcCorrelationScopeWhenMdcNotOnClasspath() {
this.contextRunner.withClassLoader(new FilteredClassLoader("org.slf4j")).run((context) -> {
assertThat(context).doesNotHaveBean("mdcCorrelationScopeDecoratorBuilder");
assertThat(context).doesNotHaveBean("correlationScopeDecorator");
});
}
@Test
void shouldNotSupplyCorrelationScopeDecoratorIfBaggageDisabled() {
this.contextRunner.withPropertyValues("management.tracing.baggage.enabled=false")
@ -168,21 +171,38 @@ class BraveAutoConfigurationTests {
@Test
void shouldSupplyW3CWithoutBaggageByDefaultIfBaggageDisabled() {
this.contextRunner.withPropertyValues("management.tracing.baggage.enabled=false")
.run((context) -> assertThat(context).hasBean("w3cPropagationNoBaggageFactory"));
.run((context) -> assertThat(context).hasSingleBean(W3CPropagation.class));
}
@Test
void shouldSupplyB3WithoutBaggageIfBaggageDisabledAndB3Picked() {
this.contextRunner
.withPropertyValues("management.tracing.baggage.enabled=false",
"management.tracing.propagation.type=B3")
.run((context) -> assertThat(context).hasBean("b3PropagationNoBaggageFactory"));
this.contextRunner.withPropertyValues("management.tracing.baggage.enabled=false",
"management.tracing.propagation.type=B3").run((context) -> {
assertThat(context).hasBean("propagationFactory");
assertThat(context.getBean(Factory.class).toString()).isEqualTo("B3Propagation");
});
}
@Test
void shouldNotSupplyCorrelationScopeDecoratorIfBaggageCorrelationDisabled() {
this.contextRunner.withPropertyValues("management.tracing.baggage.correlation.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean("correlationFieldsCorrelationScopeDecorator"));
void shouldNotApplyCorrelationFieldsIfBaggageCorrelationDisabled() {
this.contextRunner.withPropertyValues("management.tracing.baggage.correlation.enabled=false",
"management.tracing.baggage.correlation.fields=alpha,bravo").run((context) -> {
ScopeDecorator scopeDecorator = context.getBean(ScopeDecorator.class);
assertThat(scopeDecorator)
.extracting("fields", InstanceOfAssertFactories.array(SingleCorrelationField[].class))
.hasSize(2);
});
}
@Test
void shouldNotApplyCorrelationFieldsIfBaggageCorrelationEnabled() {
this.contextRunner.withPropertyValues("management.tracing.baggage.correlation.enabled=true",
"management.tracing.baggage.correlation.fields=alpha,bravo").run((context) -> {
ScopeDecorator scopeDecorator = context.getBean(ScopeDecorator.class);
assertThat(scopeDecorator)
.extracting("fields", InstanceOfAssertFactories.array(SingleCorrelationField[].class))
.hasSize(4);
});
}
@Test

View File

@ -16,9 +16,12 @@
package org.springframework.boot.actuate.autoconfigure.tracing;
import java.util.List;
import io.micrometer.tracing.otel.bridge.OtelCurrentTraceContext;
import io.micrometer.tracing.otel.bridge.OtelHttpClientHandler;
import io.micrometer.tracing.otel.bridge.OtelHttpServerHandler;
import io.micrometer.tracing.otel.bridge.OtelPropagator;
import io.micrometer.tracing.otel.bridge.OtelTracer;
import io.micrometer.tracing.otel.bridge.OtelTracer.EventPublisher;
import io.micrometer.tracing.otel.bridge.Slf4JBaggageEventListener;
@ -70,6 +73,11 @@ class OpenTelemetryAutoConfigurationTests {
assertThat(context).hasSingleBean(ContextPropagators.class);
assertThat(context).hasSingleBean(Sampler.class);
assertThat(context).hasSingleBean(Tracer.class);
assertThat(context).hasSingleBean(Slf4JEventListener.class);
assertThat(context).hasSingleBean(Slf4JBaggageEventListener.class);
assertThat(context).hasSingleBean(SpanProcessor.class);
assertThat(context).hasSingleBean(OtelPropagator.class);
assertThat(context).hasSingleBean(TextMapPropagator.class);
});
}
@ -86,8 +94,12 @@ class OpenTelemetryAutoConfigurationTests {
assertThat(context).doesNotHaveBean(SdkTracerProvider.class);
assertThat(context).doesNotHaveBean(ContextPropagators.class);
assertThat(context).doesNotHaveBean(Sampler.class);
assertThat(context).doesNotHaveBean(SpanProcessor.class);
assertThat(context).doesNotHaveBean(Tracer.class);
assertThat(context).doesNotHaveBean(Slf4JEventListener.class);
assertThat(context).doesNotHaveBean(Slf4JBaggageEventListener.class);
assertThat(context).doesNotHaveBean(SpanProcessor.class);
assertThat(context).doesNotHaveBean(OtelPropagator.class);
assertThat(context).doesNotHaveBean(TextMapPropagator.class);
});
}
@ -112,53 +124,63 @@ class OpenTelemetryAutoConfigurationTests {
assertThat(context).hasSingleBean(ContextPropagators.class);
assertThat(context).hasBean("customSampler");
assertThat(context).hasSingleBean(Sampler.class);
assertThat(context).hasBean("customSpanProcessor");
assertThat(context).hasBean("customTracer");
assertThat(context).hasSingleBean(Tracer.class);
});
}
@Test
void shouldSupplyBaggageAndSlf4jEventListenersWhenMdcOnClasspath() {
this.contextRunner.run((context) -> {
assertThat(context).hasBean("customSlf4jEventListener");
assertThat(context).hasSingleBean(Slf4JEventListener.class);
assertThat(context).hasBean("customSlf4jBaggageEventListener");
assertThat(context).hasSingleBean(Slf4JBaggageEventListener.class);
assertThat(context).hasBean("customOtelPropagator");
assertThat(context).hasSingleBean(OtelPropagator.class);
});
}
@Test
void shouldSupplySlf4jEventListenersWhenMdcOnClasspathAndBaggageCorrelationDisabled() {
this.contextRunner.withPropertyValues("management.tracing.baggage.correlation.enabled=false").run((context) -> {
assertThat(context).hasSingleBean(Slf4JEventListener.class);
assertThat(context).doesNotHaveBean(Slf4JBaggageEventListener.class);
void shouldAllowMultipleSpanProcessors() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context.getBeansOfType(SpanProcessor.class)).hasSize(2);
assertThat(context).hasBean("customSpanProcessor");
});
}
@Test
void shouldSupplySlf4jEventListenersWhenMdcOnClasspathAndBaggageDisabled() {
this.contextRunner.withPropertyValues("management.tracing.baggage.enabled=false").run((context) -> {
assertThat(context).hasSingleBean(Slf4JEventListener.class);
assertThat(context).doesNotHaveBean(Slf4JBaggageEventListener.class);
void shouldAllowMultipleTextMapPropagators() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> {
assertThat(context.getBeansOfType(TextMapPropagator.class)).hasSize(2);
assertThat(context).hasBean("customTextMapPropagator");
});
}
@Test
void shouldNotSupplySlf4jEventListenersWhenMdcNotOnClasspath() {
this.contextRunner.withClassLoader(new FilteredClassLoader("org.slf4j")).run((context) -> {
assertThat(context).doesNotHaveBean(Slf4JEventListener.class);
assertThat(context).doesNotHaveBean(Slf4JBaggageEventListener.class);
});
void shouldNotSupplySlf4jBaggageEventListenerBaggageCorrelationDisabled() {
this.contextRunner.withPropertyValues("management.tracing.baggage.correlation.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(Slf4JBaggageEventListener.class));
}
@Test
void shouldNotSupplySlf4JBaggageEventListenerWhenBaggageDisabled() {
this.contextRunner.withPropertyValues("management.tracing.baggage.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(Slf4JBaggageEventListener.class));
}
@Test
void shouldSupplyB3PropagationIfPropagationPropertySet() {
this.contextRunner.withPropertyValues("management.tracing.propagation.type=B3").run((context) -> {
assertThat(context).hasSingleBean(B3Propagator.class);
assertThat(context).hasBean("b3TextMapPropagator");
assertThat(context).hasBean("b3BaggageTextMapPropagator");
assertThat(context).doesNotHaveBean(W3CTraceContextPropagator.class);
});
}
@Test
void shouldSupplyB3PropagationIfPropagationPropertySetAndBaggageDisabled() {
this.contextRunner.withPropertyValues("management.tracing.propagation.type=B3",
"management.tracing.baggage.enabled=false").run((context) -> {
assertThat(context).hasSingleBean(B3Propagator.class);
assertThat(context).hasBean("b3TextMapPropagator");
assertThat(context).doesNotHaveBean(W3CTraceContextPropagator.class);
});
}
@Test
void shouldSupplyW3CPropagationWithBaggageByDefault() {
this.contextRunner.run((context) -> assertThat(context).hasBean("w3cTextMapPropagatorWithBaggage"));
@ -238,6 +260,26 @@ class OpenTelemetryAutoConfigurationTests {
return mock(Tracer.class);
}
@Bean
Slf4JEventListener customSlf4jEventListener() {
return new Slf4JEventListener();
}
@Bean
Slf4JBaggageEventListener customSlf4jBaggageEventListener() {
return new Slf4JBaggageEventListener(List.of("alpha"));
}
@Bean
OtelPropagator customOtelPropagator(ContextPropagators propagators, Tracer tracer) {
return new OtelPropagator(propagators, tracer);
}
@Bean
TextMapPropagator customTextMapPropagator() {
return mock(TextMapPropagator.class);
}
}
@Configuration(proxyBeanMethods = false)