diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfiguration.java index 8deaf835ff..9be6eca7c3 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfiguration.java @@ -54,12 +54,14 @@ import io.micrometer.tracing.exporter.SpanFilter; import io.micrometer.tracing.exporter.SpanReporter; import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.actuate.autoconfigure.tracing.TracingProperties.Propagation.PropagationType; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 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.boot.context.properties.IncompatibleConfigurationException; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; @@ -71,6 +73,7 @@ import org.springframework.core.env.Environment; * * @author Moritz Halbritter * @author Marcin Grzejszczak + * @author Jonatan Ivanov * @since 3.0.0 */ @AutoConfiguration(before = MicrometerTracingAutoConfiguration.class) @@ -97,14 +100,19 @@ public class BraveAutoConfiguration { @Bean @ConditionalOnMissingBean - public Tracing braveTracing(Environment environment, List spanHandlers, + public Tracing braveTracing(Environment environment, TracingProperties properties, List spanHandlers, List tracingCustomizers, CurrentTraceContext currentTraceContext, Factory propagationFactory, Sampler sampler) { + if (properties.getPropagation().getType() == PropagationType.W3C + && properties.getBrave().isSpanJoiningSupported()) { + throw new IncompatibleConfigurationException("management.tracing.propagation.type", + "management.tracing.brave.span-joining-supported"); + } String applicationName = environment.getProperty("spring.application.name", DEFAULT_APPLICATION_NAME); Builder builder = Tracing.newBuilder() .currentTraceContext(currentTraceContext) .traceId128Bit(true) - .supportsJoin(false) + .supportsJoin(properties.getBrave().isSpanJoiningSupported()) .propagationFactory(propagationFactory) .sampler(sampler) .localServiceName(applicationName); diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java index 88fedf9733..f642ad117d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; * Configuration properties for tracing. * * @author Moritz Halbritter + * @author Jonatan Ivanov * @since 3.0.0 */ @ConfigurationProperties("management.tracing") @@ -50,6 +51,11 @@ public class TracingProperties { */ private final Propagation propagation = new Propagation(); + /** + * Brave configuration. + */ + private final Brave brave = new Brave(); + public boolean isEnabled() { return this.enabled; } @@ -70,6 +76,10 @@ public class TracingProperties { return this.propagation; } + public Brave getBrave() { + return this.brave; + } + public static class Sampling { /** @@ -194,4 +204,23 @@ public class TracingProperties { } + public static class Brave { + + /** + * Whether the propagation type and tracing backend support sharing the span ID + * between client and server spans. Requires B3 propagation and a compatible + * backend. + */ + private boolean spanJoiningSupported = false; + + public boolean isSpanJoiningSupported() { + return this.spanJoiningSupported; + } + + public void setSpanJoiningSupported(boolean spanJoiningSupported) { + this.spanJoiningSupported = spanJoiningSupported; + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java index 0f7d2e547b..ed6fe42054 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/tracing/BraveAutoConfigurationTests.java @@ -43,6 +43,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfigurationTests.SpanHandlerConfiguration.AdditionalSpanHandler; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.context.properties.IncompatibleConfigurationException; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -50,12 +51,14 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.mock; /** * Tests for {@link BraveAutoConfiguration}. * * @author Moritz Halbritter + * @author Jonatan Ivanov */ class BraveAutoConfigurationTests { @@ -216,17 +219,45 @@ class BraveAutoConfigurationTests { } @Test - void shouldNotSupportJoinedSpans() { + void shouldNotSupportJoinedSpansByDefault() { this.contextRunner.run((context) -> { Tracing tracing = context.getBean(Tracing.class); Span parentSpan = tracing.tracer().nextSpan(); Span childSpan = tracing.tracer().joinSpan(parentSpan.context()); - assertThat(parentSpan.context().traceIdString()).isEqualTo(childSpan.context().traceIdString()); - assertThat(parentSpan.context().spanIdString()).isEqualTo(childSpan.context().parentIdString()); - assertThat(parentSpan.context().spanIdString()).isNotEqualTo(childSpan.context().spanIdString()); + assertThat(childSpan.context().traceIdString()).isEqualTo(parentSpan.context().traceIdString()); + assertThat(childSpan.context().spanIdString()).isNotEqualTo(parentSpan.context().spanIdString()); + assertThat(childSpan.context().parentIdString()).isEqualTo(parentSpan.context().spanIdString()); + assertThat(parentSpan.context().parentIdString()).isNull(); }); } + @Test + void shouldSupportJoinedSpansIfB3UsedAndBackendSupportsIt() { + this.contextRunner + .withPropertyValues("management.tracing.propagation.type=B3", + "management.tracing.brave.span-joining-supported=true") + .run((context) -> { + Tracing tracing = context.getBean(Tracing.class); + Span parentSpan = tracing.tracer().nextSpan(); + Span childSpan = tracing.tracer().joinSpan(parentSpan.context()); + assertThat(childSpan.context().traceIdString()).isEqualTo(parentSpan.context().traceIdString()); + assertThat(childSpan.context().spanIdString()).isEqualTo(parentSpan.context().spanIdString()); + assertThat(childSpan.context().parentIdString()).isNull(); + assertThat(parentSpan.context().parentIdString()).isNull(); + }); + } + + @Test + void shouldFailIfSupportJoinedSpansIsEnabledAndW3cIsChosen() { + this.contextRunner + .withPropertyValues("management.tracing.propagation.type=W3C", + "management.tracing.brave.span-joining-supported=true") + .run((context) -> assertThatThrownBy(() -> context.getBean(Tracing.class)).rootCause() + .isExactlyInstanceOf(IncompatibleConfigurationException.class) + .hasMessage( + "The following configuration properties have incompatible values: [management.tracing.propagation.type, management.tracing.brave.span-joining-supported]")); + } + @Test @SuppressWarnings("rawtypes") void compositeSpanHandlerShouldBeFirstSpanHandler() {