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 06722b8cb18..030045ea52d 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 @@ -107,8 +107,8 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur private Function configPropertiesCustomizer = Function.identity(); - private SpiHelper spiHelper = - SpiHelper.create(AutoConfiguredOpenTelemetrySdk.class.getClassLoader()); + private ComponentLoader componentLoader = + SpiHelper.serviceComponentLoader(AutoConfiguredOpenTelemetrySdk.class.getClassLoader()); private boolean registerShutdownHook = true; @@ -401,14 +401,14 @@ public AutoConfiguredOpenTelemetrySdkBuilder setResultAsGlobal() { public AutoConfiguredOpenTelemetrySdkBuilder setServiceClassLoader( ClassLoader serviceClassLoader) { requireNonNull(serviceClassLoader, "serviceClassLoader"); - this.spiHelper = SpiHelper.create(serviceClassLoader); + this.componentLoader = SpiHelper.serviceComponentLoader(serviceClassLoader); return this; } /** Sets the {@link ComponentLoader} to be used to load SPI implementations. */ AutoConfiguredOpenTelemetrySdkBuilder setComponentLoader(ComponentLoader componentLoader) { requireNonNull(componentLoader, "componentLoader"); - this.spiHelper = SpiHelper.create(componentLoader); + this.componentLoader = componentLoader; return this; } @@ -417,6 +417,7 @@ AutoConfiguredOpenTelemetrySdkBuilder setComponentLoader(ComponentLoader compone * the settings of this {@link AutoConfiguredOpenTelemetrySdkBuilder}. */ public AutoConfiguredOpenTelemetrySdk build() { + SpiHelper spiHelper = SpiHelper.create(componentLoader); if (!customized) { customized = true; mergeSdkTracerProviderConfigurer(); @@ -428,7 +429,8 @@ public AutoConfiguredOpenTelemetrySdk build() { ConfigProperties config = getConfig(); - AutoConfiguredOpenTelemetrySdk fromFileConfiguration = maybeConfigureFromFile(config); + AutoConfiguredOpenTelemetrySdk fromFileConfiguration = + maybeConfigureFromFile(config, componentLoader); if (fromFileConfiguration != null) { maybeRegisterShutdownHook(fromFileConfiguration.getOpenTelemetrySdk()); maybeSetAsGlobal(fromFileConfiguration.getOpenTelemetrySdk()); @@ -527,7 +529,8 @@ public AutoConfiguredOpenTelemetrySdk build() { } @Nullable - private static AutoConfiguredOpenTelemetrySdk maybeConfigureFromFile(ConfigProperties config) { + private static AutoConfiguredOpenTelemetrySdk maybeConfigureFromFile( + ConfigProperties config, ComponentLoader componentLoader) { String otelConfigFile = config.getString("otel.config.file"); if (otelConfigFile != null && !otelConfigFile.isEmpty()) { logger.warning( @@ -552,8 +555,10 @@ private static AutoConfiguredOpenTelemetrySdk maybeConfigureFromFile(ConfigPrope Class openTelemetryConfiguration = Class.forName( "io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel"); - Method create = configurationFactory.getMethod("create", openTelemetryConfiguration); - OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model); + Method create = + configurationFactory.getMethod( + "create", openTelemetryConfiguration, ComponentLoader.class); + OpenTelemetrySdk sdk = (OpenTelemetrySdk) create.invoke(null, model, componentLoader); Method toConfigProperties = configurationFactory.getMethod("toConfigProperties", openTelemetryConfiguration); StructuredConfigProperties structuredConfigProperties = @@ -608,7 +613,7 @@ void callAutoConfigureListeners(SpiHelper spiHelper, OpenTelemetrySdk openTeleme @SuppressWarnings("deprecation") // Support deprecated SdkTracerProviderConfigurer private void mergeSdkTracerProviderConfigurer() { for (io.opentelemetry.sdk.autoconfigure.spi.traces.SdkTracerProviderConfigurer configurer : - spiHelper.load( + componentLoader.load( io.opentelemetry.sdk.autoconfigure.spi.traces.SdkTracerProviderConfigurer.class)) { addTracerProviderCustomizer( (builder, config) -> { diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/internal/SpiHelper.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/internal/SpiHelper.java index c8c40e63e07..6f3196a6f61 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/internal/SpiHelper.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/internal/SpiHelper.java @@ -41,7 +41,7 @@ private SpiHelper(ComponentLoader componentLoader) { /** Create a {@link SpiHelper} which loads SPIs using the {@code classLoader}. */ public static SpiHelper create(ClassLoader classLoader) { - return new SpiHelper(new ServiceLoaderComponentLoader(classLoader)); + return new SpiHelper(serviceComponentLoader(classLoader)); } /** Create a {@link SpiHelper} which loads SPIs using the {@code componentLoader}. */ @@ -49,6 +49,16 @@ public static SpiHelper create(ComponentLoader componentLoader) { return new SpiHelper(componentLoader); } + /** Create a {@link ComponentLoader} which loads using the {@code classLoader}. */ + public static ComponentLoader serviceComponentLoader(ClassLoader classLoader) { + return new ServiceLoaderComponentLoader(classLoader); + } + + /** Return the backing underlying {@link ComponentLoader}. */ + public ComponentLoader getComponentLoader() { + return componentLoader; + } + /** * Load implementations of an SPI which are configurable (i.e. they accept {@link * ConfigProperties}. diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java index 75fd08858a7..f4c1346dc72 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java @@ -49,7 +49,8 @@ static T requireNonNull(@Nullable T object, String description) { */ static T loadComponent(SpiHelper spiHelper, Class type, String name, Object model) { // Map model to generic structured config properties - StructuredConfigProperties config = FileConfiguration.toConfigProperties(model); + StructuredConfigProperties config = + FileConfiguration.toConfigProperties(model, spiHelper.getComponentLoader()); return spiHelper.loadComponent(type, name, config); } } diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfiguration.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfiguration.java index 06ab3cc755c..5b1b3dd32f0 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfiguration.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfiguration.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.internal.ComponentLoader; import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; @@ -49,6 +50,8 @@ public final class FileConfiguration { private static final Logger logger = Logger.getLogger(FileConfiguration.class.getName()); private static final Pattern ENV_VARIABLE_REFERENCE = Pattern.compile("\\$\\{([a-zA-Z_][a-zA-Z0-9_]*)}"); + private static final ComponentLoader DEFAULT_COMPONENT_LOADER = + SpiHelper.serviceComponentLoader(FileConfiguration.class.getClassLoader()); private static final ObjectMapper MAPPER; @@ -86,9 +89,24 @@ public static OpenTelemetrySdk parseAndCreate(InputStream inputStream) { * @throws ConfigurationException if unable to interpret */ public static OpenTelemetrySdk create(OpenTelemetryConfigurationModel configurationModel) { + return create(configurationModel, DEFAULT_COMPONENT_LOADER); + } + + /** + * Interpret the {@code configurationModel} to create {@link OpenTelemetrySdk} instance + * corresponding to the configuration. + * + * @param configurationModel the configuration model + * @param componentLoader the component loader used to load {@link ComponentProvider} + * implementations + * @return the {@link OpenTelemetrySdk} + * @throws ConfigurationException if unable to interpret + */ + public static OpenTelemetrySdk create( + OpenTelemetryConfigurationModel configurationModel, ComponentLoader componentLoader) { return createAndMaybeCleanup( OpenTelemetryConfigurationFactory.getInstance(), - SpiHelper.create(FileConfiguration.class.getClassLoader()), + SpiHelper.create(componentLoader), configurationModel); } @@ -130,7 +148,7 @@ static Object loadYaml(InputStream inputStream, Map environmentV */ public static StructuredConfigProperties toConfigProperties( OpenTelemetryConfigurationModel model) { - return toConfigProperties((Object) model); + return toConfigProperties(model, DEFAULT_COMPONENT_LOADER); } /** @@ -141,13 +159,14 @@ public static StructuredConfigProperties toConfigProperties( */ public static StructuredConfigProperties toConfigProperties(InputStream configuration) { Object yamlObj = loadYaml(configuration, System.getenv()); - return toConfigProperties(yamlObj); + return toConfigProperties(yamlObj, DEFAULT_COMPONENT_LOADER); } - static StructuredConfigProperties toConfigProperties(Object model) { + static StructuredConfigProperties toConfigProperties( + Object model, ComponentLoader componentLoader) { Map configurationMap = MAPPER.convertValue(model, new TypeReference>() {}); - return YamlStructuredConfigProperties.create(configurationMap); + return YamlStructuredConfigProperties.create(configurationMap, componentLoader); } /** @@ -162,21 +181,27 @@ static StructuredConfigProperties toConfigProperties(Object model) { // ComponentProvider public static io.opentelemetry.sdk.trace.samplers.Sampler createSampler( StructuredConfigProperties genericSamplerModel) { - SamplerModel samplerModel = convertToModel(genericSamplerModel, SamplerModel.class); + YamlStructuredConfigProperties yamlStructuredConfigProperties = + requireYamlStructuredConfigProperties(genericSamplerModel); + SamplerModel samplerModel = convertToModel(yamlStructuredConfigProperties, SamplerModel.class); return createAndMaybeCleanup( SamplerFactory.getInstance(), - SpiHelper.create(FileConfiguration.class.getClassLoader()), + SpiHelper.create(yamlStructuredConfigProperties.getComponentLoader()), samplerModel); } - static T convertToModel( - StructuredConfigProperties structuredConfigProperties, Class modelType) { + private static YamlStructuredConfigProperties requireYamlStructuredConfigProperties( + StructuredConfigProperties structuredConfigProperties) { if (!(structuredConfigProperties instanceof YamlStructuredConfigProperties)) { throw new ConfigurationException( "Only YamlStructuredConfigProperties can be converted to model"); } - return MAPPER.convertValue( - ((YamlStructuredConfigProperties) structuredConfigProperties).toMap(), modelType); + return (YamlStructuredConfigProperties) structuredConfigProperties; + } + + static T convertToModel( + YamlStructuredConfigProperties structuredConfigProperties, Class modelType) { + return MAPPER.convertValue(structuredConfigProperties.toMap(), modelType); } static R createAndMaybeCleanup(Factory factory, SpiHelper spiHelper, M model) { diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java index f2d5da54fc2..bb5540268a8 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java @@ -25,7 +25,9 @@ final class ResourceFactory Resource> { private static final StructuredConfigProperties EMPTY_CONFIG = - FileConfiguration.toConfigProperties(Collections.emptyMap()); + FileConfiguration.toConfigProperties( + Collections.emptyMap(), + SpiHelper.serviceComponentLoader(ResourceFactory.class.getClassLoader())); private static final ResourceFactory INSTANCE = new ResourceFactory(); private ResourceFactory() {} diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlStructuredConfigProperties.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlStructuredConfigProperties.java index 04c432ce8a7..87cbc5f8fc8 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlStructuredConfigProperties.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlStructuredConfigProperties.java @@ -8,6 +8,7 @@ import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; +import io.opentelemetry.sdk.autoconfigure.internal.ComponentLoader; import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.autoconfigure.spi.internal.StructuredConfigProperties; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; @@ -37,14 +38,17 @@ final class YamlStructuredConfigProperties implements StructuredConfigProperties private final Map> listEntries; private final Map mapEntries; + private final ComponentLoader componentLoader; private YamlStructuredConfigProperties( Map simpleEntries, Map> listEntries, - Map mapEntries) { + Map mapEntries, + ComponentLoader componentLoader) { this.simpleEntries = simpleEntries; this.listEntries = listEntries; this.mapEntries = mapEntries; + this.componentLoader = componentLoader; } /** @@ -57,7 +61,8 @@ private YamlStructuredConfigProperties( * @see FileConfiguration#toConfigProperties(OpenTelemetryConfigurationModel) */ @SuppressWarnings("unchecked") - static YamlStructuredConfigProperties create(Map properties) { + static YamlStructuredConfigProperties create( + Map properties, ComponentLoader componentLoader) { Map simpleEntries = new HashMap<>(); Map> listEntries = new HashMap<>(); Map mapEntries = new HashMap<>(); @@ -75,13 +80,15 @@ static YamlStructuredConfigProperties create(Map properties) { if (isListOfMaps(value)) { List list = ((List>) value) - .stream().map(YamlStructuredConfigProperties::create).collect(toList()); + .stream() + .map(map -> YamlStructuredConfigProperties.create(map, componentLoader)) + .collect(toList()); listEntries.put(key, list); continue; } if (isMap(value)) { YamlStructuredConfigProperties configProperties = - YamlStructuredConfigProperties.create((Map) value); + YamlStructuredConfigProperties.create((Map) value, componentLoader); mapEntries.put(key, configProperties); continue; } @@ -91,7 +98,8 @@ static YamlStructuredConfigProperties create(Map properties) { + "\" has unrecognized object type " + value.getClass().getName()); } - return new YamlStructuredConfigProperties(simpleEntries, listEntries, mapEntries); + return new YamlStructuredConfigProperties( + simpleEntries, listEntries, mapEntries, componentLoader); } private static boolean isPrimitiveList(Object object) { @@ -292,4 +300,9 @@ public Map toMap() { mapEntries.forEach((key, value) -> result.put(key, value.toMap())); return Collections.unmodifiableMap(result); } + + /** Return the {@link ComponentLoader}. */ + public ComponentLoader getComponentLoader() { + return componentLoader; + } }