diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/IncubatingUtil.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/IncubatingUtil.java index ce700181c93..7596864631f 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/IncubatingUtil.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/IncubatingUtil.java @@ -100,20 +100,32 @@ private static AutoConfiguredOpenTelemetrySdk getOpenTelemetrySdk( Class declarativeConfiguration = Class.forName( "io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration"); + + Class contextClass = + Class.forName( + "io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigContext"); + Method createContext = contextClass.getDeclaredMethod("create", ComponentLoader.class); + createContext.setAccessible(true); + Object context = createContext.invoke(null, componentLoader); + Method create = - declarativeConfiguration.getMethod( - "create", openTelemetryConfiguration, ComponentLoader.class); + declarativeConfiguration.getDeclaredMethod( + "create", openTelemetryConfiguration, contextClass); + create.setAccessible(true); + OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model, context); - OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model, componentLoader); - Class sdkConfigProvider = + Class providerClass = Class.forName("io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider"); - Method createFileConfigProvider = - sdkConfigProvider.getMethod("create", openTelemetryConfiguration, ComponentLoader.class); - ConfigProvider configProvider = - (ConfigProvider) createFileConfigProvider.invoke(null, model, componentLoader); - // Note: can't access file configuration resource without reflection so setting a dummy - // resource - return AutoConfiguredOpenTelemetrySdk.create(sdk, Resource.getDefault(), null, configProvider); + Object provider = + providerClass + .getDeclaredMethod("create", openTelemetryConfiguration, ComponentLoader.class) + .invoke(null, model, componentLoader); + + Method getResource = contextClass.getDeclaredMethod("getResource"); + getResource.setAccessible(true); + Resource resource = (Resource) getResource.invoke(context); + + return AutoConfiguredOpenTelemetrySdk.create(sdk, resource, null, provider); } // Visible for testing diff --git a/sdk-extensions/autoconfigure/src/testIncubating/java/io/opentelemetry/sdk/autoconfigure/DeclarativeConfigurationTest.java b/sdk-extensions/autoconfigure/src/testIncubating/java/io/opentelemetry/sdk/autoconfigure/DeclarativeConfigurationTest.java index a062ca30af8..3d04962237a 100644 --- a/sdk-extensions/autoconfigure/src/testIncubating/java/io/opentelemetry/sdk/autoconfigure/DeclarativeConfigurationTest.java +++ b/sdk-extensions/autoconfigure/src/testIncubating/java/io/opentelemetry/sdk/autoconfigure/DeclarativeConfigurationTest.java @@ -7,7 +7,6 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static java.util.Collections.singletonMap; -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; @@ -127,13 +126,13 @@ void configFile_Valid() { cleanup.addCloseable(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk()); OpenTelemetrySdk openTelemetrySdk = autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk(); + Resource resource = Resource.getDefault().toBuilder().put("service.name", "test").build(); ExtendedOpenTelemetrySdk expectedSdk = ExtendedOpenTelemetrySdk.create( OpenTelemetrySdk.builder() .setTracerProvider( SdkTracerProvider.builder() - .setResource( - Resource.getDefault().toBuilder().put("service.name", "test").build()) + .setResource(resource) .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) .build()) .build(), @@ -142,7 +141,7 @@ void configFile_Valid() { assertThat(openTelemetrySdk.toString()).hasToString(expectedSdk.toString()); // AutoConfiguredOpenTelemetrySdk#getResource() is set to a dummy value when configuring from // file - assertThat(autoConfiguredOpenTelemetrySdk.getResource()).isEqualTo(Resource.getDefault()); + assertThat(autoConfiguredOpenTelemetrySdk.getResource()).isEqualTo(resource); verify(builder, times(1)).shutdownHook(autoConfiguredOpenTelemetrySdk.getOpenTelemetrySdk()); assertThat(Runtime.getRuntime().removeShutdownHook(thread)).isTrue(); logCapturer.assertContains("Autoconfiguring from configuration file: " + configFilePath); diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java index 1bb0f4f0900..a53eb1d13c5 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java @@ -8,8 +8,10 @@ import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.common.ComponentLoader; import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; import java.io.Closeable; import java.util.ArrayList; import java.util.Collections; @@ -24,11 +26,17 @@ class DeclarativeConfigContext { private final SpiHelper spiHelper; private final List closeables = new ArrayList<>(); @Nullable private volatile MeterProvider meterProvider; + @Nullable private Resource resource = null; + // Visible for testing DeclarativeConfigContext(SpiHelper spiHelper) { this.spiHelper = spiHelper; } + static DeclarativeConfigContext create(ComponentLoader componentLoader) { + return new DeclarativeConfigContext(SpiHelper.create(componentLoader)); + } + /** * Add the {@code closeable} to the list of closeables to clean up if configuration fails * exceptionally, and return it. @@ -51,6 +59,22 @@ public void setMeterProvider(MeterProvider meterProvider) { this.meterProvider = meterProvider; } + Resource getResource() { + // called via reflection from io.opentelemetry.sdk.autoconfigure.IncubatingUtil + if (resource == null) { + throw new DeclarativeConfigException("Resource has not been configured yet."); + } + return resource; + } + + void setResource(Resource resource) { + this.resource = resource; + } + + SpiHelper getSpiHelper() { + return spiHelper; + } + /** * Find a registered {@link ComponentProvider} with {@link ComponentProvider#getType()} matching * {@code type}, {@link ComponentProvider#getName()} matching {@code name}, and call {@link diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java index 77341981103..7a643630c7b 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java @@ -115,10 +115,14 @@ public static ExtendedOpenTelemetrySdk create( */ public static ExtendedOpenTelemetrySdk create( OpenTelemetryConfigurationModel configurationModel, ComponentLoader componentLoader) { - SpiHelper spiHelper = SpiHelper.create(componentLoader); + return create(configurationModel, DeclarativeConfigContext.create(componentLoader)); + } + private static ExtendedOpenTelemetrySdk create( + OpenTelemetryConfigurationModel configurationModel, DeclarativeConfigContext context) { DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); + SpiHelper spiHelper = context.getSpiHelper(); for (DeclarativeConfigurationCustomizerProvider provider : spiHelper.loadOrdered(DeclarativeConfigurationCustomizerProvider.class)) { provider.customize(builder); @@ -127,7 +131,7 @@ public static ExtendedOpenTelemetrySdk create( ExtendedOpenTelemetrySdk sdk = createAndMaybeCleanup( OpenTelemetryConfigurationFactory.getInstance(), - spiHelper, + context, builder.customizeModel(configurationModel)); callAutoConfigureListeners(spiHelper, sdk); return sdk; @@ -213,7 +217,7 @@ public static Sampler createSampler(DeclarativeConfigProperties genericSamplerMo DeclarativeConfigProperties.toMap(yamlDeclarativeConfigProperties), SamplerModel.class); return createAndMaybeCleanup( SamplerFactory.getInstance(), - SpiHelper.create(yamlDeclarativeConfigProperties.getComponentLoader()), + DeclarativeConfigContext.create(yamlDeclarativeConfigProperties.getComponentLoader()), samplerModel); } @@ -226,8 +230,8 @@ private static YamlDeclarativeConfigProperties requireYamlDeclarativeConfigPrope return (YamlDeclarativeConfigProperties) declarativeConfigProperties; } - static R createAndMaybeCleanup(Factory factory, SpiHelper spiHelper, M model) { - DeclarativeConfigContext context = new DeclarativeConfigContext(spiHelper); + static R createAndMaybeCleanup( + Factory factory, DeclarativeConfigContext context, M model) { try { return factory.create(model, context); } catch (RuntimeException e) { diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java index f00762917b9..ea0ad7ef2a8 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java @@ -55,6 +55,7 @@ public ExtendedOpenTelemetrySdk create( if (model.getResource() != null) { resource = ResourceFactory.getInstance().create(model.getResource(), context); } + context.setResource(resource); if (model.getMeterProvider() != null) { SdkMeterProvider meterProvider = diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java new file mode 100644 index 00000000000..fb78ca28e9a --- /dev/null +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java @@ -0,0 +1,29 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.sdk.resources.Resource; +import org.junit.jupiter.api.Test; + +class DeclarativeConfigContextTest { + + private final DeclarativeConfigContext context = + DeclarativeConfigContext.create( + ComponentLoader.forClassLoader(DeclarativeConfigContextTest.class.getClassLoader())); + + @Test + void resourceMustBeSetBeforeUse() { + assertThatCode(context::getResource).isInstanceOf(DeclarativeConfigException.class); + Resource resource = Resource.empty(); + context.setResource(resource); + assertThat(context.getResource()).isSameAs(resource); + } +}