diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/logging/LoggingExporterAutoConfiguration.java b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/logging/LoggingExporterAutoConfiguration.java new file mode 100644 index 0000000000..2940a400f6 --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/main/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/logging/LoggingExporterAutoConfiguration.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.logging; + +import static java.util.Collections.emptyList; + +import io.opentelemetry.exporter.logging.LoggingSpanExporter; +import io.opentelemetry.instrumentation.spring.autoconfigure.internal.SdkEnabled; +import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; + +/** + * This class is internal and is hence not for public use. Its APIs are unstable and can change at + * any time. + */ +@Conditional(SdkEnabled.class) +// for forwards compatibility with declarative configuration +@ConditionalOnProperty(name = "otel.debug", havingValue = "true") +@ConditionalOnClass(LoggingSpanExporter.class) +@Configuration +public class LoggingExporterAutoConfiguration { + + @Bean + public AutoConfigurationCustomizerProvider loggingOtelCustomizer() { + return p -> + p.addTracerProviderCustomizer( + (builder, config) -> { + enableLoggingExporter(builder, config); + return builder; + }); + } + + public static void enableLoggingExporter( + SdkTracerProviderBuilder builder, ConfigProperties config) { + // don't install another instance if the user has already explicitly requested it. + if (loggingExporterIsNotAlreadyConfigured(config)) { + builder.addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())); + } + } + + private static boolean loggingExporterIsNotAlreadyConfigured(ConfigProperties config) { + return !config.getList("otel.traces.exporter", emptyList()).contains("logging"); + } +} diff --git a/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/logging/LoggingExporterAutoConfigurationTest.java b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/logging/LoggingExporterAutoConfigurationTest.java new file mode 100644 index 0000000000..42e8a1491d --- /dev/null +++ b/instrumentation/spring/spring-boot-autoconfigure/src/test/java/io/opentelemetry/instrumentation/spring/autoconfigure/internal/instrumentation/logging/LoggingExporterAutoConfigurationTest.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.spring.autoconfigure.internal.instrumentation.logging; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.spring.autoconfigure.OpenTelemetryAutoConfiguration; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import io.opentelemetry.instrumentation.testing.junit.LibraryInstrumentationExtension; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; +import java.util.Collections; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +class LoggingExporterAutoConfigurationTest { + @RegisterExtension + static final InstrumentationExtension testing = LibraryInstrumentationExtension.create(); + + private final ApplicationContextRunner runner = + new ApplicationContextRunner() + .withBean( + ConfigProperties.class, + () -> DefaultConfigProperties.createFromMap(Collections.emptyMap())) + .withConfiguration( + AutoConfigurations.of( + LoggingExporterAutoConfiguration.class, OpenTelemetryAutoConfiguration.class)); + + @Test + void instrumentationEnabled() { + runner + .withPropertyValues("otel.debug=true") + .run( + context -> + assertThat(context.getBean(OpenTelemetry.class).toString()) + .containsOnlyOnce("cntscnt")); + } + + @Test + void instrumentationDisabled() { + runner + .withPropertyValues("otel.debug=false") + .run( + context -> + assertThat(context.getBean(OpenTelemetry.class).toString()) + .doesNotContain("cntscnt")); + } +} diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/provider/TestExporterCustomizerProvider.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/provider/TestExporterCustomizerProvider.java index cc29c93af7..bc4b588a28 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/provider/TestExporterCustomizerProvider.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/provider/TestExporterCustomizerProvider.java @@ -26,6 +26,12 @@ import java.util.Collections; import java.util.List; public class TestExporterCustomizerProvider implements DeclarativeConfigurationCustomizerProvider { + + @Override + public int order() { + return Integer.MIN_VALUE; // run before other customizers that might add exporters + } + @Override public void customize(DeclarativeConfigurationCustomizer customizer) { if (TestSpanExporterComponentProvider.getSpanExporter() == null) {