diff --git a/spring-boot-project/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryProperties.java b/spring-boot-project/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryProperties.java index 228331ff3518..cc6bcee6e578 100644 --- a/spring-boot-project/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryProperties.java +++ b/spring-boot-project/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetryProperties.java @@ -25,16 +25,30 @@ * Configuration properties for OpenTelemetry. * * @author Moritz Halbritter + * @author Yanming Zhou * @since 4.0.0 */ @ConfigurationProperties("management.opentelemetry") public class OpenTelemetryProperties { + /** + * Whether to reuse registered global OpenTelemetry. + */ + private boolean reuseRegisteredGlobal; + /** * Resource attributes. */ private Map resourceAttributes = new HashMap<>(); + public boolean isReuseRegisteredGlobal() { + return this.reuseRegisteredGlobal; + } + + public void setReuseRegisteredGlobal(boolean reuseRegisteredGlobal) { + this.reuseRegisteredGlobal = reuseRegisteredGlobal; + } + public Map getResourceAttributes() { return this.resourceAttributes; } diff --git a/spring-boot-project/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfiguration.java b/spring-boot-project/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfiguration.java index 5d6a09124957..0d703c529ae4 100644 --- a/spring-boot-project/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfiguration.java +++ b/spring-boot-project/spring-boot-opentelemetry/src/main/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.boot.opentelemetry.autoconfigure; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.OpenTelemetrySdk; @@ -33,17 +34,25 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; /** * {@link EnableAutoConfiguration Auto-configuration} for the OpenTelemetry SDK. * * @author Moritz Halbritter + * @author Yanming Zhou * @since 4.0.0 */ @AutoConfiguration @@ -54,6 +63,14 @@ public class OpenTelemetrySdkAutoConfiguration { OpenTelemetrySdkAutoConfiguration() { } + @Bean + @ConditionalOnMissingBean(OpenTelemetry.class) + @ConditionalOnBooleanProperty("management.opentelemetry.reuse-registered-global") + @Conditional(OnRegisteredGlobalOpenTelemetryCondition.class) + OpenTelemetry globalOpenTelemetry() { + return GlobalOpenTelemetry.get(); + } + @Bean @ConditionalOnMissingBean(OpenTelemetry.class) OpenTelemetrySdk openTelemetrySdk(ObjectProvider openTelemetrySdkTracerProvider, @@ -106,4 +123,15 @@ SdkLoggerProvider openTelemetrySdkLoggerProvider(Resource openTelemetryResource, } + static class OnRegisteredGlobalOpenTelemetryCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { + boolean globalOpenTelemetryRegistered = GlobalOpenTelemetry.get() != OpenTelemetry.noop(); + return new ConditionOutcome(globalOpenTelemetryRegistered, ConditionMessage + .of("GlobalOpenTelemetry is" + (globalOpenTelemetryRegistered ? "" : " not") + " registered")); + } + + } + } diff --git a/spring-boot-project/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfigurationTests.java b/spring-boot-project/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfigurationTests.java index af28a1a84b50..0f316b072304 100644 --- a/spring-boot-project/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-opentelemetry/src/test/java/org/springframework/boot/opentelemetry/autoconfigure/OpenTelemetrySdkAutoConfigurationTests.java @@ -19,8 +19,11 @@ import java.util.Collection; import java.util.concurrent.atomic.AtomicInteger; +import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.OpenTelemetrySdk; @@ -49,6 +52,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; /** @@ -57,6 +62,7 @@ * @author Moritz Halbritter * @author Toshiaki Maki * @author Phillip Webb + * @author Yanming Zhou */ class OpenTelemetrySdkAutoConfigurationTests { @@ -240,6 +246,21 @@ void whenHasMultipleSdkLoggerProviderBuilderCustomizersCallsCustomizeMethod() { }); } + @Test + void reuseRegisteredGlobalOpenTelemetry() { + OpenTelemetry openTelemetry = mock(OpenTelemetry.class); + TracerProvider tracerProvider = mock(TracerProvider.class); + Tracer tracer = mock(Tracer.class); + given(tracerProvider.get(eq("org.springframework.boot"))).willReturn(tracer); + given(openTelemetry.getTracerProvider()).willReturn(tracerProvider); + GlobalOpenTelemetry.set(openTelemetry); + this.contextRunner.withPropertyValues("management.opentelemetry.reuse-registered-global=true") + .run((context) -> { + assertThat(context).doesNotHaveBean(OpenTelemetrySdk.class); + assertThat(context.getBean(OpenTelemetry.class).getTracer("org.springframework.boot")).isSameAs(tracer); + }); + } + @Configuration(proxyBeanMethods = false) static class UserConfiguration {