diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java index ed3d0a1c13..2f5109df54 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkBuilder.java @@ -15,6 +15,7 @@ import io.opentelemetry.sdk.OpenTelemetrySdkBuilder; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer; import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.traces.SdkTracerProviderConfigurer; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.logs.SdkLogEmitterProvider; import io.opentelemetry.sdk.metrics.SdkMeterProvider; @@ -215,6 +216,7 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur public AutoConfiguredOpenTelemetrySdk build() { if (!customized) { customized = true; + mergeSdkTracerProviderConfigurer(); for (AutoConfigurationCustomizerProvider customizer : ServiceLoader.load(AutoConfigurationCustomizerProvider.class, serviceClassLoader)) { customizer.customize(this); @@ -223,23 +225,23 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur SdkTracerProviderBuilder tracerProviderBuilder = SdkTracerProvider.builder(); ConfigProperties config = getConfig(); - tracerProviderBuilder = tracerProviderCustomizer.apply(tracerProviderBuilder, config); Resource resource = ResourceConfiguration.configureResource(config, serviceClassLoader, resourceCustomizer); - tracerProviderBuilder.setResource(resource); SdkMeterProvider meterProvider = MeterProviderConfiguration.configureMeterProvider(resource, config, serviceClassLoader); - SdkTracerProvider tracerProvider = - TracerProviderConfiguration.configureTracerProvider( - tracerProviderBuilder, - config, - serviceClassLoader, - meterProvider, - spanExporterCustomizer, - samplerCustomizer); + tracerProviderBuilder.setResource(resource); + TracerProviderConfiguration.configureTracerProvider( + tracerProviderBuilder, + config, + serviceClassLoader, + meterProvider, + spanExporterCustomizer, + samplerCustomizer); + tracerProviderBuilder = tracerProviderCustomizer.apply(tracerProviderBuilder, config); + SdkTracerProvider tracerProvider = tracerProviderBuilder.build(); SdkLogEmitterProvider logEmitterProvider = LogEmitterProviderConfiguration.configureLogEmitterProvider( @@ -280,6 +282,17 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur return AutoConfiguredOpenTelemetrySdk.create(openTelemetrySdk, resource, config); } + private void mergeSdkTracerProviderConfigurer() { + for (SdkTracerProviderConfigurer configurer : + ServiceLoader.load(SdkTracerProviderConfigurer.class, serviceClassLoader)) { + addTracerProviderCustomizer( + (builder, config) -> { + configurer.configure(builder, config); + return builder; + }); + } + } + private ConfigProperties getConfig() { ConfigProperties config = this.config; if (config == null) { diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/TracerProviderConfiguration.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/TracerProviderConfiguration.java index 1e7f8f6c5d..53f5fd4bd2 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/TracerProviderConfiguration.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/TracerProviderConfiguration.java @@ -9,8 +9,6 @@ import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider; -import io.opentelemetry.sdk.autoconfigure.spi.traces.SdkTracerProviderConfigurer; -import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import io.opentelemetry.sdk.trace.SpanLimits; import io.opentelemetry.sdk.trace.SpanLimitsBuilder; @@ -26,12 +24,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.ServiceLoader; import java.util.function.BiFunction; final class TracerProviderConfiguration { - static SdkTracerProvider configureTracerProvider( + static void configureTracerProvider( SdkTracerProviderBuilder tracerProviderBuilder, ConfigProperties config, ClassLoader serviceClassLoader, @@ -49,21 +46,12 @@ final class TracerProviderConfiguration { tracerProviderBuilder.setSampler( samplerCustomizer.apply(configureSampler(sampler, config, serviceClassLoader), config)); - // Run user configuration before setting exporters from environment to allow user span - // processors to effect export. - for (SdkTracerProviderConfigurer configurer : - ServiceLoader.load(SdkTracerProviderConfigurer.class, serviceClassLoader)) { - configurer.configure(tracerProviderBuilder, config); - } - Map exportersByName = SpanExporterConfiguration.configureSpanExporters( config, serviceClassLoader, meterProvider, spanExporterCustomizer); configureSpanProcessors(config, exportersByName, meterProvider) .forEach(tracerProviderBuilder::addSpanProcessor); - - return tracerProviderBuilder.build(); } static List configureSpanProcessors( diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java index 17302a9191..3f95ad4a74 100644 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java @@ -23,12 +23,16 @@ import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.IdGenerator; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.trace.export.SpanExporter; import io.opentelemetry.sdk.trace.samplers.Sampler; import io.opentelemetry.sdk.trace.samplers.SamplingResult; import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.BeforeEach; @@ -150,4 +154,37 @@ class AutoConfiguredOpenTelemetrySdkTest { // Ensures the export happened. sdk.getSdkTracerProvider().shutdown().join(10, TimeUnit.SECONDS); } + + @Test + void tracerProviderCustomizer() { + InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + AutoConfiguredOpenTelemetrySdkBuilder autoConfiguration = + AutoConfiguredOpenTelemetrySdk.builder() + .addTracerProviderCustomizer( + (tracerProviderBuilder, config) -> { + tracerProviderBuilder.setResource(Resource.builder().put("cat", "meow").build()); + return tracerProviderBuilder.addSpanProcessor( + SimpleSpanProcessor.create(spanExporter)); + }) + .addResourceCustomizer( + (resource, config) -> resource.merge(Resource.builder().put("cow", "moo").build())) + .addPropertiesSupplier(() -> Collections.singletonMap("otel.metrics.exporter", "none")) + .addPropertiesSupplier(() -> Collections.singletonMap("otel.traces.exporter", "none")) + .addPropertiesSupplier(() -> Collections.singletonMap("otel.logs.exporter", "none")) + .setResultAsGlobal(false); + + GlobalOpenTelemetry.set(OpenTelemetry.noop()); + AutoConfiguredOpenTelemetrySdk autoConfigured = autoConfiguration.build(); + assertThat(autoConfigured.getResource().getAttribute(stringKey("cow"))).isEqualTo("moo"); + + OpenTelemetrySdk sdk = autoConfigured.getOpenTelemetrySdk(); + sdk.getTracerProvider().get("test").spanBuilder("test").startSpan().end(); + List spanItems = spanExporter.getFinishedSpanItems(); + assertThat(spanItems.size()).isEqualTo(1); + SpanData spanData = spanItems.get(0); + assertThat(spanData.getResource().getAttribute(stringKey("cat"))).isEqualTo("meow"); + + // Ensures the export happened. + sdk.getSdkTracerProvider().shutdown().join(10, TimeUnit.SECONDS); + } } diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/TracerProviderConfigurationTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/TracerProviderConfigurationTest.java index 417348c8a8..500e9941fc 100644 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/TracerProviderConfigurationTest.java +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/TracerProviderConfigurationTest.java @@ -16,6 +16,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; import io.opentelemetry.sdk.trace.SpanLimits; import io.opentelemetry.sdk.trace.SpanProcessor; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; @@ -61,14 +62,16 @@ class TracerProviderConfigurationTest { Resource resource = Resource.create(Attributes.builder().put("cat", "meow").build()); // We don't have any exporters on classpath for this test so check no-op case. Exporter cases // are verified in other test sets like testFullConfig. - SdkTracerProvider tracerProvider = - TracerProviderConfiguration.configureTracerProvider( - SdkTracerProvider.builder().setResource(resource), - DefaultConfigProperties.createForTest(properties), - TracerProviderConfiguration.class.getClassLoader(), - MeterProvider.noop(), - (a, unused) -> a, - (a, unused) -> a); + SdkTracerProviderBuilder tracerProviderBuilder = + SdkTracerProvider.builder().setResource(resource); + TracerProviderConfiguration.configureTracerProvider( + tracerProviderBuilder, + DefaultConfigProperties.createForTest(properties), + TracerProviderConfiguration.class.getClassLoader(), + MeterProvider.noop(), + (a, unused) -> a, + (a, unused) -> a); + SdkTracerProvider tracerProvider = tracerProviderBuilder.build(); try { assertThat(tracerProvider.getSampler()).isEqualTo(Sampler.alwaysOff());