From 5978fd097086e140c014da73701e960629476b6b Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 9 Apr 2026 10:15:10 +0000 Subject: [PATCH 01/11] Make snakeyaml-engine and jackson-databind optional at runtime Split DeclarativeConfiguration into two classes: - DeclarativeConfiguration: create(model) only, no YAML/jackson-databind deps - DeclarativeConfigurationParser: all parsing (MAPPER static block, parse, loadYaml, parseAndCreate, toConfigProperties, createSampler, env-var substitution, snakeyaml inner classes) Change snakeyaml-engine and jackson-databind from implementation to compileOnly in build.gradle.kts (keeping jackson-annotations as api since the generated model POJOs use @JsonProperty etc. as public API). Remove the unused jackson-dataformat-yaml dependency. Users who only call DeclarativeConfiguration.create(model) for programmatic SDK configuration no longer incur transitive YAML/jackson-databind deps. Users who need YAML parsing add snakeyaml-engine and jackson-databind and call DeclarativeConfigurationParser.parseAndCreate(stream). This also opens the door for merging declarative config into autoconfigure, since the static initializer that caused NoClassDefFoundError when jackson-databind was absent is now isolated in DeclarativeConfigurationParser. Signed-off-by: Gregor Zeitlinger --- .../incubator/ExtendedOpenTelemetryTest.java | 4 +- .../config/InstrumentationConfigUtilTest.java | 4 +- .../InstrumentationConfigUtilTest.java | 6 +- .../graal/IncubatingApiTests.java | 4 +- .../sdk/autoconfigure/IncubatingUtil.java | 3 +- .../TestDeclarativeConfigurationProvider.java | 4 +- sdk-extensions/incubator/build.gradle.kts | 8 +- .../fileconfig/DeclarativeConfiguration.java | 390 +---------------- .../DeclarativeConfigurationParser.java | 413 ++++++++++++++++++ .../incubator/fileconfig/FileConfigUtil.java | 2 +- .../OpenTelemetryConfigurationFactory.java | 2 +- .../DeclarativeConfigurationCreateTest.java | 6 +- .../DeclarativeConfigurationParseTest.java | 22 +- ...OpenTelemetryConfigurationFactoryTest.java | 6 +- .../YamlDeclarativeConfigPropertiesTest.java | 4 +- .../JaegerRemoteSamplerComponentProvider.java | 4 +- 16 files changed, 464 insertions(+), 418 deletions(-) create mode 100644 sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ExtendedOpenTelemetryTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ExtendedOpenTelemetryTest.java index 017e691946d..af171627479 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/ExtendedOpenTelemetryTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/ExtendedOpenTelemetryTest.java @@ -25,7 +25,7 @@ import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser; import io.opentelemetry.sdk.internal.ExtendedOpenTelemetrySdk; import io.opentelemetry.sdk.internal.SdkConfigProvider; import java.io.ByteArrayInputStream; @@ -94,7 +94,7 @@ void instrumentationConfig() { SdkConfigProvider configProvider = SdkConfigProvider.create( - DeclarativeConfiguration.toConfigProperties( + DeclarativeConfigurationParser.toConfigProperties( new ByteArrayInputStream(configYaml.getBytes(StandardCharsets.UTF_8)))); ExtendedOpenTelemetry openTelemetry = ExtendedOpenTelemetrySdk.create(OpenTelemetrySdk.builder().build(), configProvider); diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/config/InstrumentationConfigUtilTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/config/InstrumentationConfigUtilTest.java index 9048d744d36..c4ccd2f30f5 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/config/InstrumentationConfigUtilTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/config/InstrumentationConfigUtilTest.java @@ -8,7 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; import com.google.common.collect.ImmutableMap; -import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser; import io.opentelemetry.sdk.extension.incubator.fileconfig.YamlDeclarativeConfigProperties; import io.opentelemetry.sdk.internal.SdkConfigProvider; import java.io.ByteArrayInputStream; @@ -61,7 +61,7 @@ class InstrumentationConfigUtilTest { private static ConfigProvider toConfigProvider(String configYaml) { return SdkConfigProvider.create( - DeclarativeConfiguration.toConfigProperties( + DeclarativeConfigurationParser.toConfigProperties( new ByteArrayInputStream(configYaml.getBytes(StandardCharsets.UTF_8)))); } diff --git a/api/incubator/src/testConvertToModel/java/io/opentelemetry/api/incubator/InstrumentationConfigUtilTest.java b/api/incubator/src/testConvertToModel/java/io/opentelemetry/api/incubator/InstrumentationConfigUtilTest.java index 3ce2cdd992a..56fe679f78d 100644 --- a/api/incubator/src/testConvertToModel/java/io/opentelemetry/api/incubator/InstrumentationConfigUtilTest.java +++ b/api/incubator/src/testConvertToModel/java/io/opentelemetry/api/incubator/InstrumentationConfigUtilTest.java @@ -14,7 +14,7 @@ import io.opentelemetry.api.incubator.config.ConfigProvider; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; -import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalInstrumentationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationPropertyModel; @@ -54,7 +54,7 @@ void toMap_RoundTrip() throws JsonProcessingException { String mapJson = MAPPER.writeValueAsString(map); DeclarativeConfigProperties properties = - DeclarativeConfiguration.toConfigProperties( + DeclarativeConfigurationParser.toConfigProperties( new ByteArrayInputStream(mapJson.getBytes(StandardCharsets.UTF_8))); assertThat(DeclarativeConfigProperties.toMap(properties)).isEqualTo(map); @@ -131,7 +131,7 @@ private static ConfigProvider withInstrumentationConfig( new ExperimentalLanguageSpecificInstrumentationModel(); javaConfig.setAdditionalProperty(instrumentationName, instrumentationConfig); DeclarativeConfigProperties modelProperties = - DeclarativeConfiguration.toConfigProperties( + DeclarativeConfigurationParser.toConfigProperties( new OpenTelemetryConfigurationModel() .withInstrumentationDevelopment( new ExperimentalInstrumentationModel().withJava(javaConfig))); diff --git a/integration-tests/graal-incubating/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingApiTests.java b/integration-tests/graal-incubating/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingApiTests.java index 209234af3d2..40675fedb08 100644 --- a/integration-tests/graal-incubating/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingApiTests.java +++ b/integration-tests/graal-incubating/src/test/java/io/opentelemetry/integrationtests/graal/IncubatingApiTests.java @@ -23,7 +23,7 @@ import io.opentelemetry.api.metrics.Meter; import io.opentelemetry.api.metrics.MeterProvider; import io.opentelemetry.api.trace.TracerProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser; import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; import io.opentelemetry.sdk.metrics.SdkMeterProvider; @@ -124,7 +124,7 @@ void parseDeclarativeConfiguration() { drop: {} """; // should not throw - DeclarativeConfiguration.parse( + DeclarativeConfigurationParser.parse( new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8))); } } 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 44000040718..c23162eb567 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 @@ -12,6 +12,7 @@ import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigResult; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import java.io.FileInputStream; @@ -35,7 +36,7 @@ static AutoConfiguredOpenTelemetrySdk configureFromFile( Logger logger, String configurationFile, ComponentLoader componentLoader) { logger.fine("Autoconfiguring from configuration file: " + configurationFile); try (FileInputStream fis = new FileInputStream(configurationFile)) { - OpenTelemetryConfigurationModel model = DeclarativeConfiguration.parse(fis); + OpenTelemetryConfigurationModel model = DeclarativeConfigurationParser.parse(fis); return create(model, componentLoader); } catch (DeclarativeConfigException e) { throw toConfigurationException(e); diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfigSpi/java/io/opentelemetry/sdk/autoconfigure/TestDeclarativeConfigurationProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfigSpi/java/io/opentelemetry/sdk/autoconfigure/TestDeclarativeConfigurationProvider.java index d00649f6c94..cf2c5b6fe2e 100644 --- a/sdk-extensions/autoconfigure/src/testDeclarativeConfigSpi/java/io/opentelemetry/sdk/autoconfigure/TestDeclarativeConfigurationProvider.java +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfigSpi/java/io/opentelemetry/sdk/autoconfigure/TestDeclarativeConfigurationProvider.java @@ -5,7 +5,7 @@ package io.opentelemetry.sdk.autoconfigure; -import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import java.io.ByteArrayInputStream; @@ -29,7 +29,7 @@ public OpenTelemetryConfigurationModel getConfigurationModel() { + " exporter:\n" + " console: {}\n"; - return DeclarativeConfiguration.parse( + return DeclarativeConfigurationParser.parse( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); } } diff --git a/sdk-extensions/incubator/build.gradle.kts b/sdk-extensions/incubator/build.gradle.kts index d6b686fb0be..df122d6aa36 100644 --- a/sdk-extensions/incubator/build.gradle.kts +++ b/sdk-extensions/incubator/build.gradle.kts @@ -23,13 +23,15 @@ dependencies { // io.opentelemetry.sdk.extension.incubator.metric.viewconfig implementation(project(":sdk-extensions:autoconfigure-spi")) - implementation("org.snakeyaml:snakeyaml-engine") + compileOnly("org.snakeyaml:snakeyaml-engine") // io.opentelemetry.sdk.extension.incubator.fileconfig api(project(":api:incubator")) - implementation("com.fasterxml.jackson.core:jackson-databind") + compileOnly("com.fasterxml.jackson.core:jackson-databind") api("com.fasterxml.jackson.core:jackson-annotations") - implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml") + + testImplementation("org.snakeyaml:snakeyaml-engine") + testImplementation("com.fasterxml.jackson.core:jackson-databind") testImplementation(project(":sdk:testing")) testImplementation(project(":sdk-extensions:autoconfigure")) 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 51ba03c8e33..13c8710c0b0 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 @@ -5,10 +5,6 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.common.ComponentLoader; @@ -17,117 +13,36 @@ import io.opentelemetry.sdk.autoconfigure.spi.internal.AutoConfigureListener; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; -import io.opentelemetry.sdk.trace.samplers.Sampler; import java.io.Closeable; import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.Map; -import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.annotation.Nullable; -import org.snakeyaml.engine.v2.api.Load; -import org.snakeyaml.engine.v2.api.LoadSettings; -import org.snakeyaml.engine.v2.api.YamlUnicodeReader; -import org.snakeyaml.engine.v2.common.ScalarStyle; -import org.snakeyaml.engine.v2.composer.Composer; -import org.snakeyaml.engine.v2.nodes.MappingNode; -import org.snakeyaml.engine.v2.nodes.Node; -import org.snakeyaml.engine.v2.nodes.ScalarNode; -import org.snakeyaml.engine.v2.nodes.Tag; -import org.snakeyaml.engine.v2.parser.ParserImpl; -import org.snakeyaml.engine.v2.resolver.ScalarResolver; -import org.snakeyaml.engine.v2.scanner.StreamReader; -import org.snakeyaml.engine.v2.schema.CoreSchema; /** * Configure {@link OpenTelemetrySdk} using declarative - * configuration. For most users, this means calling {@link #parseAndCreate(InputStream)} with a - * YAML - * configuration file. - * - *

For Implementers

+ * configuration. * - *

External consumers needing to parse OpenTelemetry YAML configuration files should use the same - * Jackson ObjectMapper configuration for compatibility. This configuration is intentionally not - * exposed as API to avoid coupling. Instead, copy the following setup: + *

This class handles SDK configuration from an already-parsed {@link + * OpenTelemetryConfigurationModel}. It has no dependency on YAML parsing libraries at runtime. * - *

{@code
- * ObjectMapper mapper = new ObjectMapper()
- *     // Create empty object instances for keys which are present but have null values
- *     .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
- * // Boxed primitives which are present but have null values should be set to null,
- * // rather than empty instances
- * mapper.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
- * mapper.configOverride(Integer.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
- * mapper.configOverride(Double.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
- * mapper.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
- * }
- * - *

Why this configuration: + *

For most users, calling {@link + * DeclarativeConfigurationParser#parseAndCreate(java.io.InputStream)} with a YAML + * configuration file is the simplest entry point. * - *

+ *

Use this class directly when building the {@link OpenTelemetryConfigurationModel} + * programmatically, without incurring any dependency on {@code snakeyaml-engine} or {@code + * jackson-databind}. */ public final class DeclarativeConfiguration { private static final Logger logger = Logger.getLogger(DeclarativeConfiguration.class.getName()); - // Matches ${VAR_NAME}, ${env:VAR_NAME}, or ${sys:property.name} with optional :-default - private static final Pattern ENV_VARIABLE_REFERENCE = - Pattern.compile("\\$\\{(?:(env|sys):)?([a-zA-Z_][a-zA-Z0-9_.]*)(?::-([^\\n}]*))?}"); private static final ComponentLoader DEFAULT_COMPONENT_LOADER = ComponentLoader.forClassLoader(DeclarativeConfigProperties.class.getClassLoader()); - /** - * ObjectMapper configured for YAML declarative configuration parsing. - * - *

Configuration: - * - *

- * - *

External consumers needing compatible parsing should copy this configuration. See class - * javadoc for details and code example. - */ - // Visible for testing - static final ObjectMapper MAPPER; - - static { - MAPPER = - new ObjectMapper() - // Create empty object instances for keys which are present but have null values - .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)); - // Boxed primitives which are present but have null values should be set to null, rather than - // empty instances - MAPPER.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); - MAPPER.configOverride(Integer.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); - MAPPER.configOverride(Double.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); - MAPPER.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); - } - private DeclarativeConfiguration() {} - /** - * Combines {@link #parse(InputStream)} and {@link #create(OpenTelemetryConfigurationModel)}. - * - * @throws DeclarativeConfigException if unable to parse or interpret - */ - public static DeclarativeConfigResult parseAndCreate(InputStream inputStream) { - OpenTelemetryConfigurationModel configurationModel = parse(inputStream); - return create(configurationModel); - } - /** * Interpret the {@code configurationModel} to create {@link OpenTelemetrySdk} instance * corresponding to the configuration. @@ -174,105 +89,6 @@ private static DeclarativeConfigResult create( return result; } - /** - * Parse the {@code configuration} YAML and return the {@link OpenTelemetryConfigurationModel}. - * - *

During parsing, environment variable and system property substitution is performed as - * defined in the - * OpenTelemetry Configuration Data Model specification. - * - * @throws DeclarativeConfigException if unable to parse - */ - public static OpenTelemetryConfigurationModel parse(InputStream configuration) { - try { - return parse(configuration, System.getenv(), System.getProperties()); - } catch (RuntimeException e) { - throw new DeclarativeConfigException("Unable to parse configuration input stream", e); - } - } - - // Visible for testing - static OpenTelemetryConfigurationModel parse( - InputStream configuration, - Map environmentVariables, - Map systemProperties) { - Object yamlObj = loadYaml(configuration, environmentVariables, systemProperties); - return MAPPER.convertValue(yamlObj, OpenTelemetryConfigurationModel.class); - } - - // Visible for testing - static Object loadYaml( - InputStream inputStream, - Map environmentVariables, - Map systemProperties) { - LoadSettings settings = LoadSettings.builder().setSchema(new CoreSchema()).build(); - Load yaml = new EnvLoad(settings, environmentVariables, systemProperties); - return yaml.loadFromInputStream(inputStream); - } - - /** - * Convert the {@code model} to a generic {@link DeclarativeConfigProperties}. - * - * @param model the configuration model - * @return a generic {@link DeclarativeConfigProperties} representation of the model - */ - public static DeclarativeConfigProperties toConfigProperties(Object model) { - return toConfigProperties(model, DEFAULT_COMPONENT_LOADER); - } - - /** - * Convert the {@code configuration} YAML to a generic {@link DeclarativeConfigProperties}. - * - * @param configuration configuration YAML - * @return a generic {@link DeclarativeConfigProperties} representation of the model - */ - public static DeclarativeConfigProperties toConfigProperties(InputStream configuration) { - Object yamlObj = loadYaml(configuration, System.getenv(), System.getProperties()); - return toConfigProperties(yamlObj, DEFAULT_COMPONENT_LOADER); - } - - static DeclarativeConfigProperties toConfigProperties( - Object model, ComponentLoader componentLoader) { - Map configurationMap = - MAPPER.convertValue(model, new TypeReference>() {}); - if (configurationMap == null) { - configurationMap = Collections.emptyMap(); - } - return YamlDeclarativeConfigProperties.create(configurationMap, componentLoader); - } - - /** - * Create a {@link SamplerModel} from the {@code samplerModel} representing the sampler config. - * - *

This is used when samplers are composed, with one sampler accepting one or more additional - * samplers as config properties. The {@link ComponentProvider} implementation can call this to - * configure a delegate {@link SamplerModel} from the {@link DeclarativeConfigProperties} - * corresponding to a particular config property. - */ - // TODO(jack-berg): add create methods for all SDK extension components supported by - // ComponentProvider - public static Sampler createSampler(DeclarativeConfigProperties genericSamplerModel) { - YamlDeclarativeConfigProperties yamlDeclarativeConfigProperties = - requireYamlDeclarativeConfigProperties(genericSamplerModel); - SamplerModel samplerModel = - MAPPER.convertValue( - DeclarativeConfigProperties.toMap(yamlDeclarativeConfigProperties), SamplerModel.class); - return createAndMaybeCleanup( - SamplerFactory.getInstance(), - new DeclarativeConfigContext(yamlDeclarativeConfigProperties.getComponentLoader()), - samplerModel); - } - - private static YamlDeclarativeConfigProperties requireYamlDeclarativeConfigProperties( - DeclarativeConfigProperties declarativeConfigProperties) { - if (!(declarativeConfigProperties instanceof YamlDeclarativeConfigProperties)) { - throw new DeclarativeConfigException( - "Only YamlDeclarativeConfigProperties can be converted to model"); - } - return (YamlDeclarativeConfigProperties) declarativeConfigProperties; - } - static R createAndMaybeCleanup( Factory factory, DeclarativeConfigContext context, M model) { try { @@ -295,192 +111,6 @@ static R createAndMaybeCleanup( } } - private static final class EnvLoad extends Load { - - private final LoadSettings settings; - private final Map environmentVariables; - private final Map systemProperties; - - private EnvLoad( - LoadSettings settings, - Map environmentVariables, - Map systemProperties) { - super(settings); - this.settings = settings; - this.environmentVariables = environmentVariables; - this.systemProperties = systemProperties; - } - - @Override - public Object loadFromInputStream(InputStream yamlStream) { - Objects.requireNonNull(yamlStream, "InputStream cannot be null"); - return loadOne( - new EnvComposer( - settings, - new ParserImpl( - settings, new StreamReader(settings, new YamlUnicodeReader(yamlStream))), - environmentVariables, - systemProperties)); - } - } - - /** - * A YAML Composer that performs environment variable and system property substitution according - * to the - * OpenTelemetry Configuration Data Model specification. - * - *

This composer supports: - * - *

- * - *

Substitution only applies to scalar values. Mapping keys are not candidates for - * substitution. Referenced variables that are undefined, null, or empty are replaced with empty - * values unless a default value is provided. - * - *

The {@code $} character serves as an escape sequence where {@code $$} in the input is - * translated to a single {@code $} in the output. This prevents substitution for the escaped - * content. - */ - private static final class EnvComposer extends Composer { - - private final Load load; - private final Map environmentVariables; - private final Map systemProperties; - private final ScalarResolver scalarResolver; - - private static final String ESCAPE_SEQUENCE = "$$"; - private static final int ESCAPE_SEQUENCE_LENGTH = ESCAPE_SEQUENCE.length(); - private static final char ESCAPE_SEQUENCE_REPLACEMENT = '$'; - - private EnvComposer( - LoadSettings settings, - ParserImpl parser, - Map environmentVariables, - Map systemProperties) { - super(settings, parser); - this.load = new Load(settings); - this.environmentVariables = environmentVariables; - this.systemProperties = systemProperties; - this.scalarResolver = settings.getSchema().getScalarResolver(); - } - - @Override - protected Node composeValueNode(MappingNode node) { - Node itemValue = super.composeValueNode(node); - if (!(itemValue instanceof ScalarNode)) { - // Only apply environment variable substitution to ScalarNodes - return itemValue; - } - ScalarNode scalarNode = (ScalarNode) itemValue; - String envSubstitution = envSubstitution(scalarNode.getValue()); - - // If the environment variable substitution does not change the value, do not modify the node - if (envSubstitution.equals(scalarNode.getValue())) { - return itemValue; - } - - Object envSubstitutionObj = load.loadFromString(envSubstitution); - Tag tag = itemValue.getTag(); - ScalarStyle scalarStyle = scalarNode.getScalarStyle(); - - Tag resolvedTag = - envSubstitutionObj == null - ? Tag.NULL - : scalarResolver.resolve(envSubstitutionObj.toString(), true); - - // Only non-quoted substituted scalars can have their tag changed - if (!itemValue.getTag().equals(resolvedTag) - && scalarStyle != ScalarStyle.SINGLE_QUOTED - && scalarStyle != ScalarStyle.DOUBLE_QUOTED) { - tag = resolvedTag; - } - - boolean resolved = true; - return new ScalarNode( - tag, - resolved, - envSubstitution, - scalarStyle, - itemValue.getStartMark(), - itemValue.getEndMark()); - } - - private String envSubstitution(String val) { - // Iterate through val left to right, search for escape sequence "$$" - // For the substring of val between the last escape sequence and the next found, perform - // environment variable substitution - // Add the escape replacement character '$' in place of each escape sequence found - - int lastEscapeIndexEnd = 0; - StringBuilder newVal = null; - while (true) { - int escapeIndex = val.indexOf(ESCAPE_SEQUENCE, lastEscapeIndexEnd); - int substitutionEndIndex = escapeIndex == -1 ? val.length() : escapeIndex; - newVal = envVarSubstitution(newVal, val, lastEscapeIndexEnd, substitutionEndIndex); - if (escapeIndex == -1) { - break; - } else { - newVal.append(ESCAPE_SEQUENCE_REPLACEMENT); - } - lastEscapeIndexEnd = escapeIndex + ESCAPE_SEQUENCE_LENGTH; - if (lastEscapeIndexEnd >= val.length()) { - break; - } - } - - return newVal.toString(); - } - - private StringBuilder envVarSubstitution( - @Nullable StringBuilder newVal, String source, int startIndex, int endIndex) { - String val = source.substring(startIndex, endIndex); - Matcher matcher = ENV_VARIABLE_REFERENCE.matcher(val); - - if (!matcher.find()) { - return newVal == null ? new StringBuilder(val) : newVal.append(val); - } - - if (newVal == null) { - newVal = new StringBuilder(); - } - - int offset = 0; - do { - MatchResult matchResult = matcher.toMatchResult(); - String prefix = matcher.group(1); // "env", "sys", or null - String key = matcher.group(2); // variable/property name - String defaultValue = matcher.group(3); - if (defaultValue == null) { - defaultValue = ""; - } - - String replacement; - if ("sys".equals(prefix)) { - // System property substitution - Object sysProp = systemProperties.get(key); - replacement = sysProp != null ? sysProp.toString() : defaultValue; - } else { - // Environment variable substitution (default or explicit "env:" prefix) - replacement = environmentVariables.getOrDefault(key, defaultValue); - } - - newVal.append(val, offset, matchResult.start()).append(replacement); - offset = matchResult.end(); - } while (matcher.find()); - if (offset != val.length()) { - newVal.append(val, offset, val.length()); - } - - return newVal; - } - } - // Visible for testing static void callAutoConfigureListeners( DeclarativeConfigContext context, OpenTelemetrySdk openTelemetrySdk) { diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java new file mode 100644 index 00000000000..053a30dc391 --- /dev/null +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java @@ -0,0 +1,413 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import java.io.InputStream; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.annotation.Nullable; +import org.snakeyaml.engine.v2.api.Load; +import org.snakeyaml.engine.v2.api.LoadSettings; +import org.snakeyaml.engine.v2.api.YamlUnicodeReader; +import org.snakeyaml.engine.v2.common.ScalarStyle; +import org.snakeyaml.engine.v2.composer.Composer; +import org.snakeyaml.engine.v2.nodes.MappingNode; +import org.snakeyaml.engine.v2.nodes.Node; +import org.snakeyaml.engine.v2.nodes.ScalarNode; +import org.snakeyaml.engine.v2.nodes.Tag; +import org.snakeyaml.engine.v2.parser.ParserImpl; +import org.snakeyaml.engine.v2.resolver.ScalarResolver; +import org.snakeyaml.engine.v2.scanner.StreamReader; +import org.snakeyaml.engine.v2.schema.CoreSchema; + +/** + * Parses YAML + * declarative configuration into an {@link OpenTelemetryConfigurationModel}. + * + *

Requires {@code org.snakeyaml:snakeyaml-engine} and {@code + * com.fasterxml.jackson.core:jackson-databind} on the classpath at runtime. + * + *

For programmatic SDK configuration that does not need YAML parsing, use {@link + * DeclarativeConfiguration#create(OpenTelemetryConfigurationModel)} directly, which has no YAML + * dependencies. + * + *

For Implementers

+ * + *

External consumers needing to parse OpenTelemetry YAML configuration files should use the same + * Jackson ObjectMapper configuration for compatibility. This configuration is intentionally not + * exposed as API to avoid coupling. Instead, copy the following setup: + * + *

{@code
+ * ObjectMapper mapper = new ObjectMapper()
+ *     // Create empty object instances for keys which are present but have null values
+ *     .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
+ * // Boxed primitives which are present but have null values should be set to null,
+ * // rather than empty instances
+ * mapper.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
+ * mapper.configOverride(Integer.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
+ * mapper.configOverride(Double.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
+ * mapper.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
+ * }
+ * + *

Why this configuration: + * + *

+ */ +public final class DeclarativeConfigurationParser { + + // Matches ${VAR_NAME}, ${env:VAR_NAME}, or ${sys:property.name} with optional :-default + private static final Pattern ENV_VARIABLE_REFERENCE = + Pattern.compile("\\$\\{(?:(env|sys):)?([a-zA-Z_][a-zA-Z0-9_.]*)(?::-([^\\n}]*))?}"); + + private static final ComponentLoader DEFAULT_COMPONENT_LOADER = + ComponentLoader.forClassLoader(DeclarativeConfigProperties.class.getClassLoader()); + + /** + * ObjectMapper configured for YAML declarative configuration parsing. + * + *

Configuration: + * + *

+ * + *

External consumers needing compatible parsing should copy this configuration. See class + * javadoc for details and code example. + */ + // Visible for testing + static final ObjectMapper MAPPER; + + static { + MAPPER = + new ObjectMapper() + // Create empty object instances for keys which are present but have null values + .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)); + // Boxed primitives which are present but have null values should be set to null, rather than + // empty instances + MAPPER.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); + MAPPER.configOverride(Integer.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); + MAPPER.configOverride(Double.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); + MAPPER.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); + } + + private DeclarativeConfigurationParser() {} + + /** + * Combines {@link #parse(InputStream)} and {@link + * DeclarativeConfiguration#create(OpenTelemetryConfigurationModel)}. + * + * @throws DeclarativeConfigException if unable to parse or interpret + */ + public static DeclarativeConfigResult parseAndCreate(InputStream inputStream) { + OpenTelemetryConfigurationModel configurationModel = parse(inputStream); + return DeclarativeConfiguration.create(configurationModel); + } + + /** + * Parse the {@code configuration} YAML and return the {@link OpenTelemetryConfigurationModel}. + * + *

During parsing, environment variable and system property substitution is performed as + * defined in the + * OpenTelemetry Configuration Data Model specification. + * + * @throws DeclarativeConfigException if unable to parse + */ + public static OpenTelemetryConfigurationModel parse(InputStream configuration) { + try { + return parse(configuration, System.getenv(), System.getProperties()); + } catch (RuntimeException e) { + throw new DeclarativeConfigException("Unable to parse configuration input stream", e); + } + } + + // Visible for testing + static OpenTelemetryConfigurationModel parse( + InputStream configuration, + Map environmentVariables, + Map systemProperties) { + Object yamlObj = loadYaml(configuration, environmentVariables, systemProperties); + return MAPPER.convertValue(yamlObj, OpenTelemetryConfigurationModel.class); + } + + // Visible for testing + static Object loadYaml( + InputStream inputStream, + Map environmentVariables, + Map systemProperties) { + LoadSettings settings = LoadSettings.builder().setSchema(new CoreSchema()).build(); + Load yaml = new EnvLoad(settings, environmentVariables, systemProperties); + return yaml.loadFromInputStream(inputStream); + } + + /** + * Convert the {@code configuration} YAML to a generic {@link DeclarativeConfigProperties}. + * + * @param configuration configuration YAML + * @return a generic {@link DeclarativeConfigProperties} representation of the model + */ + public static DeclarativeConfigProperties toConfigProperties(InputStream configuration) { + Object yamlObj = loadYaml(configuration, System.getenv(), System.getProperties()); + return toConfigProperties(yamlObj, DEFAULT_COMPONENT_LOADER); + } + + /** + * Convert the {@code model} to a generic {@link DeclarativeConfigProperties}. + * + * @param model the configuration model + * @return a generic {@link DeclarativeConfigProperties} representation of the model + */ + public static DeclarativeConfigProperties toConfigProperties(Object model) { + return toConfigProperties(model, DEFAULT_COMPONENT_LOADER); + } + + static DeclarativeConfigProperties toConfigProperties( + Object model, ComponentLoader componentLoader) { + Map configurationMap = + MAPPER.convertValue(model, new TypeReference>() {}); + if (configurationMap == null) { + configurationMap = Collections.emptyMap(); + } + return YamlDeclarativeConfigProperties.create(configurationMap, componentLoader); + } + + /** + * Create a {@link SamplerModel} from the {@code samplerModel} representing the sampler config. + * + *

This is used when samplers are composed, with one sampler accepting one or more additional + * samplers as config properties. The {@link + * io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider} implementation can call + * this to configure a delegate {@link SamplerModel} from the {@link DeclarativeConfigProperties} + * corresponding to a particular config property. + */ + // TODO(jack-berg): add create methods for all SDK extension components supported by + // ComponentProvider + public static Sampler createSampler(DeclarativeConfigProperties genericSamplerModel) { + YamlDeclarativeConfigProperties yamlDeclarativeConfigProperties = + requireYamlDeclarativeConfigProperties(genericSamplerModel); + SamplerModel samplerModel = + MAPPER.convertValue( + DeclarativeConfigProperties.toMap(yamlDeclarativeConfigProperties), SamplerModel.class); + return DeclarativeConfiguration.createAndMaybeCleanup( + SamplerFactory.getInstance(), + new DeclarativeConfigContext(yamlDeclarativeConfigProperties.getComponentLoader()), + samplerModel); + } + + private static YamlDeclarativeConfigProperties requireYamlDeclarativeConfigProperties( + DeclarativeConfigProperties declarativeConfigProperties) { + if (!(declarativeConfigProperties instanceof YamlDeclarativeConfigProperties)) { + throw new DeclarativeConfigException( + "Only YamlDeclarativeConfigProperties can be converted to model"); + } + return (YamlDeclarativeConfigProperties) declarativeConfigProperties; + } + + private static final class EnvLoad extends Load { + + private final LoadSettings settings; + private final Map environmentVariables; + private final Map systemProperties; + + private EnvLoad( + LoadSettings settings, + Map environmentVariables, + Map systemProperties) { + super(settings); + this.settings = settings; + this.environmentVariables = environmentVariables; + this.systemProperties = systemProperties; + } + + @Override + public Object loadFromInputStream(InputStream yamlStream) { + Objects.requireNonNull(yamlStream, "InputStream cannot be null"); + return loadOne( + new EnvComposer( + settings, + new ParserImpl( + settings, new StreamReader(settings, new YamlUnicodeReader(yamlStream))), + environmentVariables, + systemProperties)); + } + } + + /** + * A YAML Composer that performs environment variable and system property substitution according + * to the + * OpenTelemetry Configuration Data Model specification. + * + *

This composer supports: + * + *

+ * + *

Substitution only applies to scalar values. Mapping keys are not candidates for + * substitution. Referenced variables that are undefined, null, or empty are replaced with empty + * values unless a default value is provided. + * + *

The {@code $} character serves as an escape sequence where {@code $$} in the input is + * translated to a single {@code $} in the output. This prevents substitution for the escaped + * content. + */ + private static final class EnvComposer extends Composer { + + private final Load load; + private final Map environmentVariables; + private final Map systemProperties; + private final ScalarResolver scalarResolver; + + private static final String ESCAPE_SEQUENCE = "$$"; + private static final int ESCAPE_SEQUENCE_LENGTH = ESCAPE_SEQUENCE.length(); + private static final char ESCAPE_SEQUENCE_REPLACEMENT = '$'; + + private EnvComposer( + LoadSettings settings, + ParserImpl parser, + Map environmentVariables, + Map systemProperties) { + super(settings, parser); + this.load = new Load(settings); + this.environmentVariables = environmentVariables; + this.systemProperties = systemProperties; + this.scalarResolver = settings.getSchema().getScalarResolver(); + } + + @Override + protected Node composeValueNode(MappingNode node) { + Node itemValue = super.composeValueNode(node); + if (!(itemValue instanceof ScalarNode)) { + // Only apply environment variable substitution to ScalarNodes + return itemValue; + } + ScalarNode scalarNode = (ScalarNode) itemValue; + String envSubstitution = envSubstitution(scalarNode.getValue()); + + // If the environment variable substitution does not change the value, do not modify the node + if (envSubstitution.equals(scalarNode.getValue())) { + return itemValue; + } + + Object envSubstitutionObj = load.loadFromString(envSubstitution); + Tag tag = itemValue.getTag(); + ScalarStyle scalarStyle = scalarNode.getScalarStyle(); + + Tag resolvedTag = + envSubstitutionObj == null + ? Tag.NULL + : scalarResolver.resolve(envSubstitutionObj.toString(), true); + + // Only non-quoted substituted scalars can have their tag changed + if (!itemValue.getTag().equals(resolvedTag) + && scalarStyle != ScalarStyle.SINGLE_QUOTED + && scalarStyle != ScalarStyle.DOUBLE_QUOTED) { + tag = resolvedTag; + } + + boolean resolved = true; + return new ScalarNode( + tag, + resolved, + envSubstitution, + scalarStyle, + itemValue.getStartMark(), + itemValue.getEndMark()); + } + + private String envSubstitution(String val) { + // Iterate through val left to right, search for escape sequence "$$" + // For the substring of val between the last escape sequence and the next found, perform + // environment variable substitution + // Add the escape replacement character '$' in place of each escape sequence found + + int lastEscapeIndexEnd = 0; + StringBuilder newVal = null; + while (true) { + int escapeIndex = val.indexOf(ESCAPE_SEQUENCE, lastEscapeIndexEnd); + int substitutionEndIndex = escapeIndex == -1 ? val.length() : escapeIndex; + newVal = envVarSubstitution(newVal, val, lastEscapeIndexEnd, substitutionEndIndex); + if (escapeIndex == -1) { + break; + } else { + newVal.append(ESCAPE_SEQUENCE_REPLACEMENT); + } + lastEscapeIndexEnd = escapeIndex + ESCAPE_SEQUENCE_LENGTH; + if (lastEscapeIndexEnd >= val.length()) { + break; + } + } + + return newVal.toString(); + } + + private StringBuilder envVarSubstitution( + @Nullable StringBuilder newVal, String source, int startIndex, int endIndex) { + String val = source.substring(startIndex, endIndex); + Matcher matcher = ENV_VARIABLE_REFERENCE.matcher(val); + + if (!matcher.find()) { + return newVal == null ? new StringBuilder(val) : newVal.append(val); + } + + if (newVal == null) { + newVal = new StringBuilder(); + } + + int offset = 0; + do { + MatchResult matchResult = matcher.toMatchResult(); + String prefix = matcher.group(1); // "env", "sys", or null + String key = matcher.group(2); // variable/property name + String defaultValue = matcher.group(3); + if (defaultValue == null) { + defaultValue = ""; + } + + String replacement; + if ("sys".equals(prefix)) { + // System property substitution + Object sysProp = systemProperties.get(key); + replacement = sysProp != null ? sysProp.toString() : defaultValue; + } else { + // Environment variable substitution (default or explicit "env:" prefix) + replacement = environmentVariables.getOrDefault(key, defaultValue); + } + + newVal.append(val, offset, matchResult.start()).append(replacement); + offset = matchResult.end(); + } while (matcher.find()); + if (offset != val.length()) { + newVal.append(val, offset, val.length()); + } + + return newVal; + } + } +} 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 7496240990f..96a965bc43f 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 @@ -26,7 +26,7 @@ static T requireNonNull(@Nullable T object, String description) { static ConfigKeyValue validateSingleKeyValue( DeclarativeConfigContext context, Object model, String resourceName) { DeclarativeConfigProperties modelConfigProperties = - DeclarativeConfiguration.toConfigProperties(model, context); + DeclarativeConfigurationParser.toConfigProperties(model, context); Set propertyKeys = modelConfigProperties.getPropertyKeys(); if (propertyKeys.size() != 1) { String suffix = 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 a2e9f36bd7f..ace7b3a3cef 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 @@ -43,7 +43,7 @@ static OpenTelemetryConfigurationFactory getInstance() { public DeclarativeConfigResult create( OpenTelemetryConfigurationModel model, DeclarativeConfigContext context) { DeclarativeConfigProperties modelProperties = - DeclarativeConfiguration.toConfigProperties(model, context.getDelegateComponentLoader()); + DeclarativeConfigurationParser.toConfigProperties(model, context.getDelegateComponentLoader()); SdkConfigProvider sdkConfigProvider = SdkConfigProvider.create(modelProperties); context.setConfigProvider(sdkConfigProvider); OpenTelemetrySdkBuilder builder = diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java index f1eb6a2e82b..80b628c1c86 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java @@ -100,7 +100,7 @@ void parseAndCreate_Examples(File example, @TempDir Path tempDir) new ByteArrayInputStream(rewrittenExampleContent.getBytes(StandardCharsets.UTF_8)); // Verify that file can be parsed and interpreted without error - assertThatCode(() -> cleanup.addCloseable(DeclarativeConfiguration.parseAndCreate(is).getSdk())) + assertThatCode(() -> cleanup.addCloseable(DeclarativeConfigurationParser.parseAndCreate(is).getSdk())) .as("Example file: " + example.getName()) .doesNotThrowAnyException(); } @@ -134,7 +134,7 @@ void parseAndCreate_Exception_CleansUpPartials() { assertThatThrownBy( () -> - DeclarativeConfiguration.parseAndCreate( + DeclarativeConfigurationParser.parseAndCreate( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)))) .isInstanceOf(DeclarativeConfigException.class) .hasMessage( @@ -159,7 +159,7 @@ void parseAndCreate_EmptyComponentProviderConfig() { assertThatCode( () -> - DeclarativeConfiguration.parseAndCreate( + DeclarativeConfigurationParser.parseAndCreate( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)))) .doesNotThrowAnyException(); } diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java index aefc81c35a7..6c50081f494 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java @@ -42,7 +42,7 @@ class DeclarativeConfigurationParseTest { void parse_BadInputStream() { assertThatThrownBy( () -> - DeclarativeConfiguration.parseAndCreate( + DeclarativeConfigurationParser.parseAndCreate( new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8)))) .isInstanceOf(DeclarativeConfigException.class) .hasMessage("Unable to parse configuration input stream"); @@ -65,7 +65,7 @@ void parse_nullValuesParsedToEmptyObjects() { + " aggregation:\n" + " drop: {}\n"; OpenTelemetryConfigurationModel objectPlaceholderModel = - DeclarativeConfiguration.parse( + DeclarativeConfigurationParser.parse( new ByteArrayInputStream(objectPlaceholderString.getBytes(StandardCharsets.UTF_8))); String noOjbectPlaceholderString = @@ -83,7 +83,7 @@ void parse_nullValuesParsedToEmptyObjects() { + " aggregation:\n" + " drop:\n"; OpenTelemetryConfigurationModel noObjectPlaceholderModel = - DeclarativeConfiguration.parse( + DeclarativeConfigurationParser.parse( new ByteArrayInputStream(noOjbectPlaceholderString.getBytes(StandardCharsets.UTF_8))); SpanExporterModel exporter = @@ -117,7 +117,7 @@ void parse_nullBoxedPrimitivesParsedToNull() { + " ratio:\n"; // Double OpenTelemetryConfigurationModel model = - DeclarativeConfiguration.parse( + DeclarativeConfigurationParser.parse( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); assertThat(model.getFileFormat()).isNull(); @@ -147,7 +147,7 @@ void parse_quotedInput() { + " value: \"\\\"double\\\"\""; OpenTelemetryConfigurationModel model = - DeclarativeConfiguration.parse( + DeclarativeConfigurationParser.parse( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); Assertions.assertNotNull(model.getResource()); @@ -161,7 +161,7 @@ void parse_quotedInput() { @MethodSource("coreSchemaValuesArgs") void coreSchemaValues(String rawYaml, Object expectedYamlResult) { Object yaml = - DeclarativeConfiguration.loadYaml( + DeclarativeConfigurationParser.loadYaml( new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)), Collections.emptyMap(), Collections.emptyMap()); @@ -192,7 +192,7 @@ void envSubstituteAndLoadYaml(String rawYaml, Object expectedYamlResult) { environmentVariables.put("HEX", "0xdeadbeef"); Object yaml = - DeclarativeConfiguration.loadYaml( + DeclarativeConfigurationParser.loadYaml( new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)), environmentVariables, Collections.emptyMap()); @@ -312,7 +312,7 @@ void sysPropertySubstituteAndLoadYaml(String rawYaml, Object expectedYamlResult) systemProperties.put("hex.prop", "0xdeadbeef"); Object yaml = - DeclarativeConfiguration.loadYaml( + DeclarativeConfigurationParser.loadYaml( new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)), Collections.emptyMap(), systemProperties); @@ -372,7 +372,7 @@ void read_WithEnvironmentVariables() { Map envVars = new HashMap<>(); envVars.put("OTEL_EXPORTER_OTLP_ENDPOINT", "http://collector:4317"); OpenTelemetryConfigurationModel model = - DeclarativeConfiguration.parse( + DeclarativeConfigurationParser.parse( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), envVars, Collections.emptyMap()); @@ -419,7 +419,7 @@ void read_WithSystemProperties() { Map sysProps = new HashMap<>(); sysProps.put("otel.exporter.otlp.endpoint", "http://collector:4318"); OpenTelemetryConfigurationModel model = - DeclarativeConfiguration.parse( + DeclarativeConfigurationParser.parse( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), Collections.emptyMap(), sysProps); @@ -466,7 +466,7 @@ void read_WithMixedEnvVarsAndSystemProperties() { Map sysProps = new HashMap<>(); sysProps.put("app.version", "1.2.3"); OpenTelemetryConfigurationModel model = - DeclarativeConfiguration.parse( + DeclarativeConfigurationParser.parse( new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), envVars, sysProps); assertThat(model) .isEqualTo( diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java index ef0e9fa49de..0b822a4d983 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java @@ -170,7 +170,7 @@ void create_Defaults() { OpenTelemetrySdk expectedSdk = OpenTelemetrySdkBuilderUtil.setConfigProvider( OpenTelemetrySdk.builder(), - SdkConfigProvider.create(DeclarativeConfiguration.toConfigProperties(model))) + SdkConfigProvider.create(DeclarativeConfigurationParser.toConfigProperties(model))) .build(); cleanup.addCloseable(expectedSdk); @@ -203,7 +203,7 @@ void create_Disabled() { OpenTelemetrySdk expectedSdk = OpenTelemetrySdkBuilderUtil.setConfigProvider( OpenTelemetrySdk.builder(), - SdkConfigProvider.create(DeclarativeConfiguration.toConfigProperties(model))) + SdkConfigProvider.create(DeclarativeConfigurationParser.toConfigProperties(model))) .build(); cleanup.addCloseable(expectedSdk); @@ -363,7 +363,7 @@ void create_Configured() throws NoSuchFieldException { InstrumentSelector.builder().setName("instrument-name").build(), View.builder().setName("stream-name").build()) .build()), - SdkConfigProvider.create(DeclarativeConfiguration.toConfigProperties(model))) + SdkConfigProvider.create(DeclarativeConfigurationParser.toConfigProperties(model))) .build(); cleanup.addCloseable(expectedSdk); diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java index e0443cd80b9..c22835f2b5a 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java @@ -68,9 +68,9 @@ class YamlDeclarativeConfigPropertiesTest { @BeforeEach void setup() { OpenTelemetryConfigurationModel configuration = - DeclarativeConfiguration.parse( + DeclarativeConfigurationParser.parse( new ByteArrayInputStream(extendedSchema.getBytes(StandardCharsets.UTF_8))); - structuredConfigProps = DeclarativeConfiguration.toConfigProperties(configuration); + structuredConfigProps = DeclarativeConfigurationParser.toConfigProperties(configuration); } @Test diff --git a/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/internal/JaegerRemoteSamplerComponentProvider.java b/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/internal/JaegerRemoteSamplerComponentProvider.java index d98379eeca5..51a5ab4778c 100644 --- a/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/internal/JaegerRemoteSamplerComponentProvider.java +++ b/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/internal/JaegerRemoteSamplerComponentProvider.java @@ -8,7 +8,7 @@ import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; +import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser; import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler; import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSamplerBuilder; import io.opentelemetry.sdk.trace.samplers.Sampler; @@ -45,7 +45,7 @@ public Sampler create(DeclarativeConfigProperties config) { if (initialSamplerModel == null) { throw new DeclarativeConfigException("jaeger remote sampler initial_sampler is required"); } - builder.setInitialSampler(DeclarativeConfiguration.createSampler(initialSamplerModel)); + builder.setInitialSampler(DeclarativeConfigurationParser.createSampler(initialSamplerModel)); Long pollingIntervalMs = config.getLong("internal"); if (pollingIntervalMs != null) { From 85e644f32729ec393f75785014a56d1e6b14275f Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 9 Apr 2026 10:21:29 +0000 Subject: [PATCH 02/11] Fix javadoc references to methods moved to DeclarativeConfigurationParser Signed-off-by: Gregor Zeitlinger --- .../incubator/fileconfig/YamlDeclarativeConfigProperties.java | 4 ++-- .../sdk/extension/incubator/metric/viewconfig/ViewConfig.java | 2 +- .../incubator/metric/viewconfig/ViewConfigCustomizer.java | 2 +- .../fileconfig/DeclarativeConfigurationCreateTest.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigProperties.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigProperties.java index 99161dc01ba..6481f846e65 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigProperties.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigProperties.java @@ -33,7 +33,7 @@ * * @see #getStructured(String) Accessing nested maps * @see #getStructuredList(String) Accessing lists of maps - * @see DeclarativeConfiguration#toConfigProperties(Object, ComponentLoader) Converting + * @see DeclarativeConfigurationParser#toConfigProperties(Object, ComponentLoader) Converting * configuration model to properties */ public final class YamlDeclarativeConfigProperties implements DeclarativeConfigProperties { @@ -71,7 +71,7 @@ private YamlDeclarativeConfigProperties( * com.fasterxml.jackson.databind.ObjectMapper}), and have values which are scalars, lists of * scalars, lists of maps, and maps. * - * @see DeclarativeConfiguration#toConfigProperties(Object) + * @see DeclarativeConfigurationParser#toConfigProperties(Object) */ @SuppressWarnings("unchecked") public static YamlDeclarativeConfigProperties create( diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfig.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfig.java index 0bb2b360802..30c28d6678d 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfig.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfig.java @@ -78,7 +78,7 @@ * schema at opentelemetry-configuration. * Please uses {@link - * io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration#parseAndCreate(InputStream)} + * io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser#parseAndCreate(InputStream)} * instead. */ @Deprecated diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfigCustomizer.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfigCustomizer.java index 76af81d7c12..f84965034bd 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfigCustomizer.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfigCustomizer.java @@ -24,7 +24,7 @@ * schema at opentelemetry-configuration) * and will be removed after the 1.62.0 release. Please uses {@link - * io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration#parseAndCreate(InputStream)} + * io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser#parseAndCreate(InputStream)} * instead. */ @Deprecated diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java index 80b628c1c86..eace3c6203a 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java @@ -63,7 +63,7 @@ class DeclarativeConfigurationCreateTest { /** * Verify each example in open-telemetry/opentelemetry-configuration/examples - * can pass {@link DeclarativeConfiguration#parseAndCreate(InputStream)}. + * can pass {@link DeclarativeConfigurationParser#parseAndCreate(InputStream)}. */ @ParameterizedTest @MethodSource("exampleFiles") From 757b1ee9384b484e87c0b0396bc16f51b3677a3c Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 9 Apr 2026 11:48:00 +0000 Subject: [PATCH 03/11] Move declarative config (fileconfig) from incubator to autoconfigure module - All fileconfig source files moved from sdk-extensions/incubator to sdk-extensions/autoconfigure, removing the hard dependency on incubator for users who only need autoconfigure - New testDeclarativeConfig test suite in autoconfigure with isolated classpath so existing autoconfigure tests (which check for absent exporters) are not polluted - Updated INCUBATOR_AVAILABLE check to look for api:incubator (DeclarativeConfigException), and added separate PARSER_AVAILABLE check for snakeyaml - New sdk-extensions/autoconfigure-config convenience module that bundles autoconfigure + snakeyaml + jackson-databind for users who want file-based config out of the box - YAML test resources added to incubator/src/test/resources (ViewConfig tests still need them) Signed-off-by: Gregor Zeitlinger --- api/incubator/build.gradle.kts | 3 + ...ntelemetry-sdk-extension-autoconfigure.txt | 84 ++- .../autoconfigure-config/build.gradle.kts | 13 + .../autoconfigure-config/gradle.properties | 1 + sdk-extensions/autoconfigure/build.gradle.kts | 221 ++++++++ ...AutoConfiguredOpenTelemetrySdkBuilder.java | 19 +- .../autoconfigure/EnvironmentResource.java | 9 +- .../fileconfig/AggregationFactory.java | 0 .../fileconfig/AttributeListFactory.java | 0 .../fileconfig/CardinalityLimitsFactory.java | 0 .../ComposableRuleBasedSamplerFactory.java | 0 .../fileconfig/ComposableSamplerFactory.java | 0 .../incubator/fileconfig/ConfigKeyValue.java | 0 .../fileconfig/DeclarativeConfigContext.java | 0 .../fileconfig/DeclarativeConfigResult.java | 0 .../fileconfig/DeclarativeConfiguration.java | 0 .../DeclarativeConfigurationBuilder.java | 0 .../DeclarativeConfigurationCustomizer.java | 0 ...rativeConfigurationCustomizerProvider.java | 0 .../DeclarativeConfigurationParser.java | 4 +- .../DeclarativeConfigurationProvider.java | 0 .../fileconfig/ExemplarFilterFactory.java | 0 .../incubator/fileconfig/Factory.java | 0 .../incubator/fileconfig/FileConfigUtil.java | 0 .../fileconfig/IncludeExcludeFactory.java | 0 .../fileconfig/InstrumentSelectorFactory.java | 0 .../fileconfig/LogLimitsFactory.java | 0 .../fileconfig/LogRecordExporterFactory.java | 0 .../LogRecordLimitsAndAttributeLimits.java | 0 .../fileconfig/LogRecordProcessorFactory.java | 0 .../LoggerProviderAndAttributeLimits.java | 0 .../fileconfig/LoggerProviderFactory.java | 0 .../fileconfig/MeterProviderFactory.java | 0 .../fileconfig/MetricExporterFactory.java | 0 .../MetricReaderAndCardinalityLimits.java | 0 .../fileconfig/MetricReaderFactory.java | 0 .../OpenTelemetryConfigurationFactory.java | 3 +- .../fileconfig/PropagatorFactory.java | 0 .../fileconfig/ResourceDetectorFactory.java | 0 .../incubator/fileconfig/ResourceFactory.java | 4 +- .../incubator/fileconfig/SamplerFactory.java | 0 .../fileconfig/ServiceResourceDetector.java | 0 .../fileconfig/SpanExporterFactory.java | 0 .../SpanLimitsAndAttributeLimits.java | 0 .../fileconfig/SpanLimitsFactory.java | 0 .../fileconfig/SpanProcessorFactory.java | 0 .../fileconfig/TextMapPropagatorAndName.java | 0 .../fileconfig/TextMapPropagatorFactory.java | 0 .../TracerProviderAndAttributeLimits.java | 0 .../fileconfig/TracerProviderFactory.java | 0 .../incubator/fileconfig/ViewFactory.java | 0 .../YamlDeclarativeConfigProperties.java | 0 ...toconfigure.spi.internal.ComponentProvider | 1 + .../DeclarativeConfigurationTest.java | 2 +- .../fileconfig/AggregationFactoryTest.java | 0 .../fileconfig/AttributeListFactoryTest.java | 0 .../fileconfig/CapturingComponentLoader.java | 0 .../CardinalityLimitsFactoryTest.java | 0 ...ComposableRuleBasedSamplerFactoryTest.java | 0 .../DeclarativeConfigContextTest.java | 0 .../DeclarativeConfigurationBuilderTest.java | 0 .../DeclarativeConfigurationCreateTest.java | 0 .../DeclarativeConfigurationParseTest.java | 0 .../fileconfig/ExemplarFilterFactoryTest.java | 0 .../fileconfig/FileConfigTestUtil.java | 0 .../fileconfig/IncludeExcludeFactoryTest.java | 0 .../InstrumentSelectorFactoryTest.java | 0 .../fileconfig/LogLimitsFactoryTest.java | 0 .../LogRecordExporterFactoryTest.java | 0 .../LogRecordProcessorFactoryTest.java | 0 .../fileconfig/LoggerProviderFactoryTest.java | 0 .../fileconfig/MeterProviderFactoryTest.java | 0 .../fileconfig/MetricExporterFactoryTest.java | 0 .../fileconfig/MetricReaderFactoryTest.java | 0 ...OpenTelemetryConfigurationFactoryTest.java | 0 .../fileconfig/PropagatorFactoryTest.java | 0 .../fileconfig/ResourceFactoryTest.java | 0 .../fileconfig/SamplerFactoryTest.java | 0 .../ServiceResourceDetectorTest.java | 0 .../fileconfig/SpanExporterFactoryTest.java | 0 .../fileconfig/SpanLimitsFactoryTest.java | 0 .../fileconfig/SpanProcessorFactoryTest.java | 0 ...rativeConfigurationCustomizerProvider.java | 0 .../fileconfig/TracerProviderFactoryTest.java | 0 .../incubator/fileconfig/ViewFactoryTest.java | 0 .../YamlDeclarativeConfigPropertiesTest.java | 0 .../component/ContainerResourceProvider.java | 0 .../component/HostResourceProvider.java | 0 .../LogRecordExporterComponentProvider.java | 0 .../LogRecordProcessorComponentProvider.java | 0 .../MetricExporterComponentProvider.java | 0 .../component/OsResourceProvider.java | 0 .../component/ProcessResourceProvider.java | 0 .../component/ResourceComponentProvider.java | 0 .../ResourceFirstComponentProvider.java | 0 .../ResourceSecondComponentProvider.java | 0 .../component/SamplerComponentProvider.java | 0 .../SpanExporterComponentProvider.java | 0 .../SpanProcessorComponentProvider.java | 0 .../TextMapPropagatorComponentProvider.java | 0 ...toconfigure.spi.internal.ComponentProvider | 0 ...DeclarativeConfigurationCustomizerProvider | 0 .../src/test/resources/aggregation-args.yaml | 21 + .../test/resources/empty-selector-config.yaml | 5 + .../src/test/resources/empty-view-config.yaml | 8 + .../src/test/resources/full-config.yaml | 28 + .../view-config-customizer-test.yaml | 6 + .../fileconfig/AggregationFactoryTest.java | 134 +++++ .../fileconfig/AttributeListFactoryTest.java | 138 +++++ .../fileconfig/CapturingComponentLoader.java | 76 +++ .../CardinalityLimitsFactoryTest.java | 78 +++ ...ComposableRuleBasedSamplerFactoryTest.java | 294 +++++++++++ .../DeclarativeConfigContextTest.java | 55 ++ .../DeclarativeConfigurationBuilderTest.java | 116 +++++ .../DeclarativeConfigurationCreateTest.java | 212 ++++++++ .../DeclarativeConfigurationParseTest.java | 489 ++++++++++++++++++ .../fileconfig/ExemplarFilterFactoryTest.java | 34 ++ .../fileconfig/FileConfigTestUtil.java | 22 + .../InstrumentSelectorFactoryTest.java | 53 ++ .../fileconfig/LogLimitsFactoryTest.java | 53 ++ .../LogRecordExporterFactoryTest.java | 421 +++++++++++++++ .../LogRecordProcessorFactoryTest.java | 186 +++++++ .../fileconfig/LoggerProviderFactoryTest.java | 165 ++++++ .../fileconfig/MeterProviderFactoryTest.java | 119 +++++ .../fileconfig/MetricExporterFactoryTest.java | 474 +++++++++++++++++ .../fileconfig/MetricReaderFactoryTest.java | 252 +++++++++ ...OpenTelemetryConfigurationFactoryTest.java | 404 +++++++++++++++ .../fileconfig/PropagatorFactoryTest.java | 132 +++++ .../fileconfig/ResourceFactoryTest.java | 196 +++++++ .../fileconfig/SamplerFactoryTest.java | 236 +++++++++ .../ServiceResourceDetectorTest.java | 64 +++ .../fileconfig/SpanExporterFactoryTest.java | 437 ++++++++++++++++ .../fileconfig/SpanLimitsFactoryTest.java | 62 +++ .../fileconfig/SpanProcessorFactoryTest.java | 180 +++++++ ...rativeConfigurationCustomizerProvider.java | 43 ++ .../fileconfig/TracerProviderFactoryTest.java | 141 +++++ .../incubator/fileconfig/ViewFactoryTest.java | 73 +++ .../YamlDeclarativeConfigPropertiesTest.java | 300 +++++++++++ .../component/ContainerResourceProvider.java | 30 ++ .../component/HostResourceProvider.java | 30 ++ .../LogRecordExporterComponentProvider.java | 54 ++ .../LogRecordProcessorComponentProvider.java | 47 ++ .../MetricExporterComponentProvider.java | 63 +++ .../component/OsResourceProvider.java | 30 ++ .../component/ProcessResourceProvider.java | 30 ++ .../component/ResourceComponentProvider.java | 27 + .../ResourceFirstComponentProvider.java | 27 + .../ResourceSecondComponentProvider.java | 27 + .../component/SamplerComponentProvider.java | 58 +++ .../SpanExporterComponentProvider.java | 54 ++ .../SpanProcessorComponentProvider.java | 61 +++ .../TextMapPropagatorComponentProvider.java | 60 +++ ...toconfigure.spi.internal.ComponentProvider | 14 + ...DeclarativeConfigurationCustomizerProvider | 1 + .../resources/aggregation-args.yaml | 21 + .../resources/empty-selector-config.yaml | 5 + .../resources/empty-view-config.yaml | 8 + .../resources/full-config.yaml | 28 + .../view-config-customizer-test.yaml | 6 + sdk-extensions/incubator/build.gradle.kts | 232 +-------- settings.gradle.kts | 1 + 161 files changed, 6740 insertions(+), 245 deletions(-) create mode 100644 sdk-extensions/autoconfigure-config/build.gradle.kts create mode 100644 sdk-extensions/autoconfigure-config/gradle.properties rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ConfigKeyValue.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigResult.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilder.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizer.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizerProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java (99%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/Factory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordLimitsAndAttributeLimits.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderAndAttributeLimits.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderAndCardinalityLimits.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java (97%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceDetectorFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java (93%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetector.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsAndAttributeLimits.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorAndName.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderAndAttributeLimits.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactory.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigProperties.java (100%) create mode 100644 sdk-extensions/autoconfigure/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider (100%) rename sdk-extensions/{incubator => autoconfigure}/src/test/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider (100%) create mode 100644 sdk-extensions/autoconfigure/src/test/resources/aggregation-args.yaml create mode 100644 sdk-extensions/autoconfigure/src/test/resources/empty-selector-config.yaml create mode 100644 sdk-extensions/autoconfigure/src/test/resources/empty-view-config.yaml create mode 100644 sdk-extensions/autoconfigure/src/test/resources/full-config.yaml create mode 100644 sdk-extensions/autoconfigure/src/test/resources/view-config-customizer-test.yaml create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/aggregation-args.yaml create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/empty-selector-config.yaml create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/empty-view-config.yaml create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/full-config.yaml create mode 100644 sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/view-config-customizer-test.yaml diff --git a/api/incubator/build.gradle.kts b/api/incubator/build.gradle.kts index 6bd0669222d..0c31d7c66e7 100644 --- a/api/incubator/build.gradle.kts +++ b/api/incubator/build.gradle.kts @@ -19,6 +19,9 @@ dependencies { // To use parsed config file as input for InstrumentationConfigUtilTest testImplementation(project(":sdk-extensions:incubator")) + testImplementation(project(":sdk-extensions:autoconfigure")) + testImplementation("org.snakeyaml:snakeyaml-engine") + testImplementation("com.fasterxml.jackson.core:jackson-databind") testImplementation(project(":sdk:testing")) testImplementation(project(":api:testing-internal")) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-extension-autoconfigure.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-extension-autoconfigure.txt index 4125dc70f37..55b9ef0fe07 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-extension-autoconfigure.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-extension-autoconfigure.txt @@ -1,2 +1,84 @@ Comparing source compatibility of opentelemetry-sdk-extension-autoconfigure-1.62.0-SNAPSHOT.jar against opentelemetry-sdk-extension-autoconfigure-1.61.0.jar -No changes. \ No newline at end of file ++++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigResult (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.resources.Resource getResource() + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.internal.ExtendedOpenTelemetrySdk getSdk() ++++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigResult create(io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigResult create(io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel, io.opentelemetry.common.ComponentLoader) ++++ NEW CLASS: PUBLIC(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationBuilder (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW INTERFACE: io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW CONSTRUCTOR: PUBLIC(+) DeclarativeConfigurationBuilder() + +++ NEW METHOD: PUBLIC(+) void addLogRecordExporterCustomizer(java.lang.Class, java.util.function.BiFunction) + GENERIC TEMPLATES: +++ T:io.opentelemetry.sdk.logs.export.LogRecordExporter + +++ NEW METHOD: PUBLIC(+) void addMetricExporterCustomizer(java.lang.Class, java.util.function.BiFunction) + GENERIC TEMPLATES: +++ T:io.opentelemetry.sdk.metrics.export.MetricExporter + +++ NEW METHOD: PUBLIC(+) void addModelCustomizer(java.util.function.Function) + +++ NEW METHOD: PUBLIC(+) void addSpanExporterCustomizer(java.lang.Class, java.util.function.BiFunction) + GENERIC TEMPLATES: +++ T:io.opentelemetry.sdk.trace.export.SpanExporter + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel customizeModel(io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel) ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void addLogRecordExporterCustomizer(java.lang.Class, java.util.function.BiFunction) + GENERIC TEMPLATES: +++ T:io.opentelemetry.sdk.logs.export.LogRecordExporter + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void addMetricExporterCustomizer(java.lang.Class, java.util.function.BiFunction) + GENERIC TEMPLATES: +++ T:io.opentelemetry.sdk.metrics.export.MetricExporter + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void addModelCustomizer(java.util.function.Function) + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void addSpanExporterCustomizer(java.lang.Class, java.util.function.BiFunction) + GENERIC TEMPLATES: +++ T:io.opentelemetry.sdk.trace.export.SpanExporter ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW INTERFACE: io.opentelemetry.sdk.autoconfigure.spi.Ordered + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) void customize(io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizer) ++++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.samplers.Sampler createSampler(io.opentelemetry.api.incubator.config.DeclarativeConfigProperties) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel parse(java.io.InputStream) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigResult parseAndCreate(java.io.InputStream) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.incubator.config.DeclarativeConfigProperties toConfigProperties(java.io.InputStream) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.incubator.config.DeclarativeConfigProperties toConfigProperties(java.lang.Object) ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationProvider (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel getConfigurationModel() + +++ NEW ANNOTATION: javax.annotation.Nullable ++++ NEW CLASS: PUBLIC(+) io.opentelemetry.sdk.extension.incubator.fileconfig.ServiceResourceDetector (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW INTERFACE: io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW CONSTRUCTOR: PUBLIC(+) ServiceResourceDetector() + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.resources.Resource create(io.opentelemetry.api.incubator.config.DeclarativeConfigProperties) + +++ NEW METHOD: PUBLIC(+) java.lang.String getName() + +++ NEW METHOD: PUBLIC(+) java.lang.Class getType() ++++ NEW CLASS: PUBLIC(+) FINAL(+) io.opentelemetry.sdk.extension.incubator.fileconfig.YamlDeclarativeConfigProperties (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.extension.incubator.fileconfig.YamlDeclarativeConfigProperties create(java.util.Map, io.opentelemetry.common.ComponentLoader) + +++ NEW METHOD: PUBLIC(+) java.lang.Boolean getBoolean(java.lang.String) + +++ NEW ANNOTATION: javax.annotation.Nullable + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.common.ComponentLoader getComponentLoader() + +++ NEW METHOD: PUBLIC(+) java.lang.Double getDouble(java.lang.String) + +++ NEW ANNOTATION: javax.annotation.Nullable + +++ NEW METHOD: PUBLIC(+) java.lang.Integer getInt(java.lang.String) + +++ NEW ANNOTATION: javax.annotation.Nullable + +++ NEW METHOD: PUBLIC(+) java.lang.Long getLong(java.lang.String) + +++ NEW ANNOTATION: javax.annotation.Nullable + +++ NEW METHOD: PUBLIC(+) java.util.Set getPropertyKeys() + +++ NEW METHOD: PUBLIC(+) java.util.List getScalarList(java.lang.String, java.lang.Class) + +++ NEW ANNOTATION: javax.annotation.Nullable + GENERIC TEMPLATES: +++ T:java.lang.Object + +++ NEW METHOD: PUBLIC(+) java.lang.String getString(java.lang.String) + +++ NEW ANNOTATION: javax.annotation.Nullable + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.incubator.config.DeclarativeConfigProperties getStructured(java.lang.String) + +++ NEW ANNOTATION: javax.annotation.Nullable + +++ NEW METHOD: PUBLIC(+) java.util.List getStructuredList(java.lang.String) + +++ NEW ANNOTATION: javax.annotation.Nullable + +++ NEW METHOD: PUBLIC(+) java.lang.String toString() diff --git a/sdk-extensions/autoconfigure-config/build.gradle.kts b/sdk-extensions/autoconfigure-config/build.gradle.kts new file mode 100644 index 00000000000..442fbcf27cc --- /dev/null +++ b/sdk-extensions/autoconfigure-config/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("otel.java-conventions") + id("otel.publish-conventions") +} + +description = "OpenTelemetry SDK Autoconfigure with YAML configuration support" +otelJava.moduleName.set("io.opentelemetry.sdk.extension.autoconfigure.config") + +dependencies { + api(project(":sdk-extensions:autoconfigure")) + runtimeOnly("org.snakeyaml:snakeyaml-engine") + runtimeOnly("com.fasterxml.jackson.core:jackson-databind") +} diff --git a/sdk-extensions/autoconfigure-config/gradle.properties b/sdk-extensions/autoconfigure-config/gradle.properties new file mode 100644 index 00000000000..4476ae57e31 --- /dev/null +++ b/sdk-extensions/autoconfigure-config/gradle.properties @@ -0,0 +1 @@ +otel.release=alpha diff --git a/sdk-extensions/autoconfigure/build.gradle.kts b/sdk-extensions/autoconfigure/build.gradle.kts index 8ef186ee14e..60737cd04bd 100644 --- a/sdk-extensions/autoconfigure/build.gradle.kts +++ b/sdk-extensions/autoconfigure/build.gradle.kts @@ -1,6 +1,12 @@ +import de.undercouch.gradle.tasks.download.Download +import java.io.FileFilter + plugins { id("otel.java-conventions") id("otel.publish-conventions") + + id("de.undercouch.download") + id("org.jsonschema2pojo") } description = "OpenTelemetry SDK Auto-configuration" @@ -15,6 +21,10 @@ dependencies { annotationProcessor("com.google.auto.value:auto-value") + compileOnly("org.snakeyaml:snakeyaml-engine") + compileOnly("com.fasterxml.jackson.core:jackson-databind") + api("com.fasterxml.jackson.core:jackson-annotations") + testImplementation(project(":sdk:trace-shaded-deps")) testImplementation(project(":sdk:testing")) @@ -22,6 +32,187 @@ dependencies { testImplementation("edu.berkeley.cs.jqf:jqf-fuzz") } +// The following tasks download the JSON Schema files from open-telemetry/opentelemetry-configuration and generate classes from the type definitions which are used with jackson-databind to parse JSON / YAML to the configuration schema. +// The sequence of tasks is: +// 1. downloadConfigurationSchema - download configuration schema from open-telemetry/opentelemetry-configuration +// 2. unzipConfigurationSchema - unzip the configuration schema archive contents to $buildDir/configuration/ +// 3. generateJsonSchema2Pojo - generate java POJOs from the configuration schema +// 4. jsonSchema2PojoPostProcessing - perform various post processing on the generated POJOs, e.g. replace javax.annotation.processing.Generated with javax.annotation.Generated, add @SuppressWarning("rawtypes") annotation +// 5. overwriteJs2p - overwrite original generated classes with versions containing updated @Generated annotation +// 6. deleteJs2pTmp - delete tmp directory +// ... proceed with normal sourcesJar, compileJava, etc + +val configurationTag = "1.0.0" +val configurationRef = "refs/tags/v$configurationTag" // Replace with commit SHA to point to experiment with a specific commit +val configurationRepoZip = "https://github.com/open-telemetry/opentelemetry-configuration/archive/$configurationRef.zip" +val buildDirectory = layout.buildDirectory.asFile.get() + +val downloadConfigurationSchema by tasks.registering(Download::class) { + src(configurationRepoZip) + // The version is encoded in the filename so that a configurationTag change results in a new + // path that doesn't yet exist, triggering a fresh download. On subsequent builds with the same + // tag the file already exists and overwrite(false) skips the network request. Note: the + // de.undercouch Download task always reports itself as not up-to-date, so overwrite(false) is + // the intended mechanism for avoiding redundant downloads. + // + // The zip is stored in tmp/ so it is outside the Sync task's output directory (configuration/). + dest("$buildDirectory/tmp/opentelemetry-configuration-v$configurationTag.zip") + overwrite(false) +} + +val unzipConfigurationSchema by tasks.registering(Sync::class) { + // Sync (not Copy) removes stale files from the destination when the source changes, ensuring + // files deleted or renamed between schema versions don't linger in the build dir. + dependsOn(downloadConfigurationSchema) + + from(zipTree(downloadConfigurationSchema.get().dest)) + eachFile(closureOf { + // Remove the top level folder "/opentelemetry-configuration-$configurationRef" + val pathParts = path.split("/") + path = pathParts.subList(1, pathParts.size).joinToString("/") + }) + into("$buildDirectory/configuration/") + includeEmptyDirs = false +} + +jsonSchema2Pojo { + sourceFiles = setOf(file("$buildDirectory/configuration/opentelemetry_configuration.json")) + targetDirectory = file("$buildDirectory/generated/sources/js2p/java/main") + targetPackage = "io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model" + + // Clear old source files to avoid contaminated source dir when updating + removeOldOutput = true + + // Include @Nullable annotation. Note: jsonSchmea2Pojo will not add @Nullable annotations on getters + // so we perform some steps in jsonSchema2PojoPostProcessing to add these. + includeJsr305Annotations = true + + // Prefer builders to setters + includeSetters = false + generateBuilders = true + + // Use title field to generate class name, instead of default which is based on filename / propertynames + useTitleAsClassname = true + + // Force java 9+ @Generated annotation, since java 8 @Generated annotation isn't detected by + // jsonSchema2Pojo and annotation is skipped altogether + targetVersion = "1.9" + + // Append Model as suffix to the generated classes. + classNameSuffix = "Model" +} + +val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo") +generateJsonSchema2Pojo.dependsOn(unzipConfigurationSchema) + +val jsonSchema2PojoPostProcessing by tasks.registering(Copy::class) { + dependsOn(generateJsonSchema2Pojo) + + from("$buildDirectory/generated/sources/js2p") + into("$buildDirectory/generated/sources/js2p-tmp") + filter { + it + // Remove @Nullable annotation so it can be deterministically added later + .replace("import javax.annotation.Nullable;\n", "") + // Replace java 9+ @Generated annotation with java 8 version, add @Nullable annotation + .replace("import javax.annotation.processing.Generated;", "import javax.annotation.Nullable;\nimport javax.annotation.Generated;") + // Add @SuppressWarnings("rawtypes") annotation to address raw types used in jsonschema2pojo builders + .replace("@Generated(\"jsonschema2pojo\")", "@Generated(\"jsonschema2pojo\")\n@SuppressWarnings(\"rawtypes\")") + // Add @Nullable annotations to all getters + .replace("( *)public ([a-zA-Z]*) get([a-zA-Z]*)".toRegex(), "$1@Nullable\n$1public $2 get$3") + } +} +val overwriteJs2p by tasks.registering(Copy::class) { + dependsOn(jsonSchema2PojoPostProcessing) + + from("$buildDirectory/generated/sources/js2p-tmp") + into("$buildDirectory/generated/sources/js2p") +} +val deleteJs2pTmp by tasks.registering(Delete::class) { + dependsOn(overwriteJs2p) + + delete("$buildDirectory/generated/sources/js2p-tmp/") +} + +val buildGraalVmReflectionJson = tasks.register("buildGraalVmReflectionJson") { + val buildDir = buildDirectory + val targetFile = File( + buildDir, + "resources/main/META-INF/native-image/io.opentelemetry/io.opentelemetry.sdk.autoconfigure/reflect-config.json" + ) + val sourcePackage = + "io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model" + val sourcePackagePath = sourcePackage.replace(".", "/") + val classesDir = + File( + buildDir, + "classes/java/main/$sourcePackagePath" + ) + + inputs.dir(classesDir) + outputs.file(targetFile) + + onlyIf { !targetFile.exists() } + + dependsOn("compileJava") + + doLast { + println("Generating GraalVM reflection config at: ${targetFile.absolutePath}") + + val classes = mutableListOf() + classesDir.walkTopDown().filter { it.isFile && it.extension == "class" }.forEach { file -> + val relativePath = file.toRelativeString(classesDir) + val className = relativePath + .removeSuffix(".class") + .replace(File.separatorChar, '.') + classes.add("$sourcePackage.$className") + } + classes.sort() + + targetFile.parentFile.mkdirs() + targetFile.bufferedWriter().use { writer -> + writer.write("[\n") + classes.forEachIndexed { index, className -> + writer.write(" {\n") + writer.write(" \"name\": \"$className\",\n") + writer.write(" \"allDeclaredMethods\": true,\n") + writer.write(" \"allDeclaredFields\": true,\n") + writer.write(" \"allDeclaredConstructors\": true\n") + writer.write(" }") + if (index < classes.size - 1) { + writer.write(",\n") + } else { + writer.write("\n") + } + } + writer.write("]\n") + } + } +} + +tasks.getByName("compileJava").dependsOn(deleteJs2pTmp) +tasks.getByName("sourcesJar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson) +tasks.getByName("jar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson) +tasks.getByName("javadoc").dependsOn(buildGraalVmReflectionJson) +tasks.getByName("compileTestJava").dependsOn(buildGraalVmReflectionJson) + +// Exclude jsonschema2pojo generated sources from checkstyle +tasks.named("checkstyleMain") { + dependsOn(buildGraalVmReflectionJson) + exclude("**/fileconfig/internal/model/**") +} + +tasks { + withType().configureEach { + environment( + mapOf( + // Expose the kitchen sink example file to tests + "CONFIG_REPO_ROOT" to "$buildDirectory/configuration" + ) + ) + } +} + testing { suites { register("testAutoConfigureOrder") { @@ -85,22 +276,52 @@ testing { } register("testIncubating") { dependencies { + implementation(project(":api:incubator")) implementation(project(":sdk-extensions:incubator")) implementation(project(":exporters:logging")) implementation(project(":exporters:otlp:all")) implementation(project(":sdk:testing")) + implementation("org.snakeyaml:snakeyaml-engine") + implementation("com.fasterxml.jackson.core:jackson-databind") + implementation("io.opentelemetry.proto:opentelemetry-proto") implementation("com.linecorp.armeria:armeria-junit5") implementation("com.linecorp.armeria:armeria-grpc") } } + register("testDeclarativeConfig") { + dependencies { + implementation(project(":api:incubator")) + implementation(project(":sdk-extensions:incubator")) + implementation(project(":sdk:testing")) + implementation(project(":sdk:trace-shaded-deps")) + + implementation("org.snakeyaml:snakeyaml-engine") + implementation("com.fasterxml.jackson.core:jackson-databind") + implementation("com.google.guava:guava") + + implementation(project(":sdk-extensions:jaeger-remote-sampler")) + implementation(project(":extensions:trace-propagators")) + implementation("com.linecorp.armeria:armeria-junit5") + implementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator") + + implementation(project(":exporters:logging")) + implementation(project(":exporters:logging-otlp")) + implementation(project(":exporters:otlp:all")) + implementation(project(":exporters:prometheus")) + } + } + register("testDeclarativeConfigSpi") { dependencies { + implementation(project(":api:incubator")) implementation(project(":sdk-extensions:incubator")) implementation(project(":exporters:logging")) implementation(project(":sdk:testing")) + implementation("org.snakeyaml:snakeyaml-engine") + implementation("com.fasterxml.jackson.core:jackson-databind") } } } 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 c4900f6d92a..ac020b6fac3 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 @@ -63,12 +63,13 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur private static final Logger logger = Logger.getLogger(AutoConfiguredOpenTelemetrySdkBuilder.class.getName()); private static final boolean INCUBATOR_AVAILABLE; + private static final boolean PARSER_AVAILABLE; static { boolean incubatorAvailable = false; try { Class.forName( - "io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration", + "io.opentelemetry.api.incubator.config.DeclarativeConfigException", false, AutoConfiguredOpenTelemetrySdkBuilder.class.getClassLoader()); incubatorAvailable = true; @@ -76,6 +77,18 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur // Not available } INCUBATOR_AVAILABLE = incubatorAvailable; + + boolean parserAvailable = false; + try { + Class.forName( + "org.snakeyaml.engine.v2.api.Load", + false, + AutoConfiguredOpenTelemetrySdkBuilder.class.getClassLoader()); + parserAvailable = true; + } catch (ClassNotFoundException e) { + // Not available + } + PARSER_AVAILABLE = parserAvailable; } @Nullable private ConfigProperties config; @@ -591,9 +604,9 @@ private static AutoConfiguredOpenTelemetrySdk maybeConfigureFromFile( return null; } - if (!INCUBATOR_AVAILABLE) { + if (!INCUBATOR_AVAILABLE || !PARSER_AVAILABLE) { throw new ConfigurationException( - "Cannot autoconfigure from config file without opentelemetry-sdk-extension-incubator on the classpath"); + "Cannot autoconfigure from config file without opentelemetry-api-incubator, snakeyaml-engine, and jackson-databind on the classpath"); } return IncubatingUtil.configureFromFile(logger, configurationFile, componentLoader); } diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java index 67372de748b..8ac6cfcdf81 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java @@ -17,15 +17,14 @@ * Creates an OpenTelemetry {@link Resource} from environment configuration. * *

This class is intentionally self-contained (no dependencies on other autoconfigure-internal - * classes) so that it can be copied wholesale into declarative configuration without pulling in - * additional dependencies. Do not add dependencies on non-API, non-SPI classes. + * classes). Do not add dependencies on non-API, non-SPI classes. */ -final class EnvironmentResource { +public final class EnvironmentResource { private static final AttributeKey SERVICE_NAME = AttributeKey.stringKey("service.name"); // Visible for testing - static final String ATTRIBUTE_PROPERTY = "otel.resource.attributes"; + public static final String ATTRIBUTE_PROPERTY = "otel.resource.attributes"; static final String SERVICE_NAME_PROPERTY = "otel.service.name"; /** @@ -37,7 +36,7 @@ final class EnvironmentResource { * @return the resource. */ @SuppressWarnings("JdkObsolete") // Recommended alternative was introduced in java 10 - static Resource createEnvironmentResource(ConfigProperties config) { + public static Resource createEnvironmentResource(ConfigProperties config) { AttributesBuilder resourceAttributes = Attributes.builder(); for (Map.Entry entry : config.getMap(ATTRIBUTE_PROPERTY).entrySet()) { resourceAttributes.put( diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ConfigKeyValue.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ConfigKeyValue.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ConfigKeyValue.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ConfigKeyValue.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContext.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigResult.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigResult.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigResult.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigResult.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilder.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilder.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilder.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilder.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizer.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizer.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizer.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizer.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizerProvider.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizerProvider.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizerProvider.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCustomizerProvider.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java similarity index 99% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java index 053a30dc391..23ac4884d95 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParser.java @@ -198,8 +198,8 @@ static DeclarativeConfigProperties toConfigProperties( * *

This is used when samplers are composed, with one sampler accepting one or more additional * samplers as config properties. The {@link - * io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider} implementation can call - * this to configure a delegate {@link SamplerModel} from the {@link DeclarativeConfigProperties} + * io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider} implementation can call this + * to configure a delegate {@link SamplerModel} from the {@link DeclarativeConfigProperties} * corresponding to a particular config property. */ // TODO(jack-berg): add create methods for all SDK extension components supported by diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationProvider.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationProvider.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationProvider.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationProvider.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/Factory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/Factory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/Factory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/Factory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigUtil.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordLimitsAndAttributeLimits.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordLimitsAndAttributeLimits.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordLimitsAndAttributeLimits.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordLimitsAndAttributeLimits.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderAndAttributeLimits.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderAndAttributeLimits.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderAndAttributeLimits.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderAndAttributeLimits.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderAndCardinalityLimits.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderAndCardinalityLimits.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderAndCardinalityLimits.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderAndCardinalityLimits.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java similarity index 97% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java index ace7b3a3cef..407eefac58e 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactory.java @@ -43,7 +43,8 @@ static OpenTelemetryConfigurationFactory getInstance() { public DeclarativeConfigResult create( OpenTelemetryConfigurationModel model, DeclarativeConfigContext context) { DeclarativeConfigProperties modelProperties = - DeclarativeConfigurationParser.toConfigProperties(model, context.getDelegateComponentLoader()); + DeclarativeConfigurationParser.toConfigProperties( + model, context.getDelegateComponentLoader()); SdkConfigProvider sdkConfigProvider = SdkConfigProvider.create(modelProperties); context.setConfigProvider(sdkConfigProvider); OpenTelemetrySdkBuilder builder = diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceDetectorFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceDetectorFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceDetectorFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceDetectorFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java similarity index 93% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java index 1a46ce5af8a..f9db56d1835 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java @@ -5,8 +5,8 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig; -import static io.opentelemetry.sdk.extension.incubator.fileconfig.EnvironmentResource.ATTRIBUTE_PROPERTY; -import static io.opentelemetry.sdk.extension.incubator.fileconfig.EnvironmentResource.createEnvironmentResource; +import static io.opentelemetry.sdk.autoconfigure.EnvironmentResource.ATTRIBUTE_PROPERTY; +import static io.opentelemetry.sdk.autoconfigure.EnvironmentResource.createEnvironmentResource; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetector.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetector.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetector.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetector.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsAndAttributeLimits.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsAndAttributeLimits.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsAndAttributeLimits.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsAndAttributeLimits.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorAndName.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorAndName.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorAndName.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorAndName.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderAndAttributeLimits.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderAndAttributeLimits.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderAndAttributeLimits.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderAndAttributeLimits.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactory.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactory.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactory.java diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigProperties.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigProperties.java similarity index 100% rename from sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigProperties.java rename to sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigProperties.java diff --git a/sdk-extensions/autoconfigure/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider b/sdk-extensions/autoconfigure/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider new file mode 100644 index 00000000000..a1a361a5f37 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider @@ -0,0 +1 @@ +io.opentelemetry.sdk.extension.incubator.fileconfig.ServiceResourceDetector diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/DeclarativeConfigurationTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/DeclarativeConfigurationTest.java index 1e9ad130c81..366b9c15b8b 100644 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/DeclarativeConfigurationTest.java +++ b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/autoconfigure/DeclarativeConfigurationTest.java @@ -51,7 +51,7 @@ void configFile(@TempDir Path tempDir) throws IOException { assertThatThrownBy(() -> AutoConfiguredOpenTelemetrySdk.builder().setConfig(config).build()) .isInstanceOf(ConfigurationException.class) .hasMessage( - "Cannot autoconfigure from config file without opentelemetry-sdk-extension-incubator on the classpath"); + "Cannot autoconfigure from config file without opentelemetry-api-incubator, snakeyaml-engine, and jackson-databind on the classpath"); } @Test diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/IncludeExcludeFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java similarity index 100% rename from sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java rename to sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java diff --git a/sdk-extensions/incubator/src/test/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider b/sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider similarity index 100% rename from sdk-extensions/incubator/src/test/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider rename to sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider diff --git a/sdk-extensions/incubator/src/test/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider b/sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider similarity index 100% rename from sdk-extensions/incubator/src/test/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider rename to sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider diff --git a/sdk-extensions/autoconfigure/src/test/resources/aggregation-args.yaml b/sdk-extensions/autoconfigure/src/test/resources/aggregation-args.yaml new file mode 100644 index 00000000000..9ddf21b5c8d --- /dev/null +++ b/sdk-extensions/autoconfigure/src/test/resources/aggregation-args.yaml @@ -0,0 +1,21 @@ +- selector: + instrument_type: HISTOGRAM + view: + aggregation: explicit_bucket_histogram + aggregation_args: + bucket_boundaries: [1.0, 2.0, 5.0] +- selector: + instrument_type: HISTOGRAM + view: + aggregation: explicit_bucket_histogram + aggregation_args: + bucket_boundaries: + - 1.0 + - 2.0 + - 5.0 +- selector: + instrument_type: HISTOGRAM + view: + aggregation: exponential_bucket_histogram + aggregation_args: + max_buckets: 20 diff --git a/sdk-extensions/autoconfigure/src/test/resources/empty-selector-config.yaml b/sdk-extensions/autoconfigure/src/test/resources/empty-selector-config.yaml new file mode 100644 index 00000000000..657a53c0f87 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/test/resources/empty-selector-config.yaml @@ -0,0 +1,5 @@ +- selector: + view: + name: name1 + description: description1 + aggregation: sum diff --git a/sdk-extensions/autoconfigure/src/test/resources/empty-view-config.yaml b/sdk-extensions/autoconfigure/src/test/resources/empty-view-config.yaml new file mode 100644 index 00000000000..7b27e1e26a9 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/test/resources/empty-view-config.yaml @@ -0,0 +1,8 @@ +- selector: + instrument_name: name1 + instrument_type: COUNTER + instrument_unit: ms + meter_name: meterName1 + meter_version: 1.0.0 + meter_schema_url: http://example1.com + view: diff --git a/sdk-extensions/autoconfigure/src/test/resources/full-config.yaml b/sdk-extensions/autoconfigure/src/test/resources/full-config.yaml new file mode 100644 index 00000000000..bf968c7e1d6 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/test/resources/full-config.yaml @@ -0,0 +1,28 @@ +- selector: + instrument_name: name1 + instrument_type: COUNTER + instrument_unit: ms + meter_name: meterName1 + meter_version: 1.0.0 + meter_schema_url: http://example1.com + view: + name: name1 + description: description1 + aggregation: sum + attribute_keys: + - foo + - bar +- selector: + instrument_name: name2 + instrument_type: COUNTER + instrument_unit: s + meter_name: meterName2 + meter_version: 2.0.0 + meter_schema_url: http://example2.com + view: + name: name2 + description: description2 + aggregation: last_value + attribute_keys: + - baz + - qux diff --git a/sdk-extensions/autoconfigure/src/test/resources/view-config-customizer-test.yaml b/sdk-extensions/autoconfigure/src/test/resources/view-config-customizer-test.yaml new file mode 100644 index 00000000000..afa6514b62b --- /dev/null +++ b/sdk-extensions/autoconfigure/src/test/resources/view-config-customizer-test.yaml @@ -0,0 +1,6 @@ +- selector: + instrument_type: OBSERVABLE_COUNTER + view: + attribute_keys: + - foo + - bar \ No newline at end of file diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java new file mode 100644 index 00000000000..9b043bf54a7 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java @@ -0,0 +1,134 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.mockito.Mockito.mock; + +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AggregationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Base2ExponentialBucketHistogramAggregationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DropAggregationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExplicitBucketHistogramAggregationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LastValueAggregationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SumAggregationModel; +import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.Base2ExponentialHistogramOptions; +import io.opentelemetry.sdk.metrics.ExplicitBucketHistogramOptions; +import java.util.Arrays; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class AggregationFactoryTest { + + @ParameterizedTest + @MethodSource("createTestCases") + void create(AggregationModel model, Aggregation expectedResult) { + Aggregation aggregation = + AggregationFactory.getInstance().create(model, mock(DeclarativeConfigContext.class)); + assertThat(aggregation.toString()).isEqualTo(expectedResult.toString()); + } + + private static Stream createTestCases() { + return Stream.of( + Arguments.of(new AggregationModel(), Aggregation.defaultAggregation()), + Arguments.of( + new AggregationModel().withDrop(new DropAggregationModel()), Aggregation.drop()), + Arguments.of(new AggregationModel().withSum(new SumAggregationModel()), Aggregation.sum()), + Arguments.of( + new AggregationModel().withLastValue(new LastValueAggregationModel()), + Aggregation.lastValue()), + Arguments.of( + new AggregationModel() + .withBase2ExponentialBucketHistogram( + new Base2ExponentialBucketHistogramAggregationModel()), + Aggregation.base2ExponentialBucketHistogram()), + Arguments.of( + new AggregationModel() + .withBase2ExponentialBucketHistogram( + new Base2ExponentialBucketHistogramAggregationModel() + .withMaxSize(2) + .withMaxScale(2)), + Aggregation.base2ExponentialBucketHistogram( + Base2ExponentialHistogramOptions.builder() + .setMaxBuckets(2) + .setMaxScale(2) + .build())), + Arguments.of( + new AggregationModel() + .withExplicitBucketHistogram( + new ExplicitBucketHistogramAggregationModel().withBoundaries(null)), + Aggregation.explicitBucketHistogram()), + Arguments.of( + new AggregationModel() + .withExplicitBucketHistogram( + new ExplicitBucketHistogramAggregationModel() + .withBoundaries(Arrays.asList(1.0, 2.0))), + Aggregation.explicitBucketHistogram( + ExplicitBucketHistogramOptions.builder() + .setBucketBoundaries(Arrays.asList(1.0, 2.0)) + .build())), + // Test recordMinMax parameter for explicit bucket histogram + Arguments.of( + new AggregationModel() + .withExplicitBucketHistogram( + new ExplicitBucketHistogramAggregationModel() + .withBoundaries(Arrays.asList(1.0, 2.0)) + .withRecordMinMax(true)), + Aggregation.explicitBucketHistogram( + ExplicitBucketHistogramOptions.builder() + .setBucketBoundaries(Arrays.asList(1.0, 2.0)) + .setRecordMinMax(true) + .build())), + Arguments.of( + new AggregationModel() + .withExplicitBucketHistogram( + new ExplicitBucketHistogramAggregationModel() + .withBoundaries(Arrays.asList(1.0, 2.0)) + .withRecordMinMax(false)), + Aggregation.explicitBucketHistogram( + ExplicitBucketHistogramOptions.builder() + .setBucketBoundaries(Arrays.asList(1.0, 2.0)) + .setRecordMinMax(false) + .build())), + Arguments.of( + new AggregationModel() + .withExplicitBucketHistogram( + new ExplicitBucketHistogramAggregationModel() + .withBoundaries(null) + .withRecordMinMax(false)), + Aggregation.explicitBucketHistogram( + ExplicitBucketHistogramOptions.builder().setRecordMinMax(false).build())), + // Test recordMinMax parameter for exponential bucket histogram + Arguments.of( + new AggregationModel() + .withBase2ExponentialBucketHistogram( + new Base2ExponentialBucketHistogramAggregationModel() + .withMaxSize(2) + .withMaxScale(2) + .withRecordMinMax(true)), + Aggregation.base2ExponentialBucketHistogram( + Base2ExponentialHistogramOptions.builder() + .setMaxBuckets(2) + .setMaxScale(2) + .setRecordMinMax(true) + .build())), + Arguments.of( + new AggregationModel() + .withBase2ExponentialBucketHistogram( + new Base2ExponentialBucketHistogramAggregationModel() + .withMaxSize(2) + .withMaxScale(2) + .withRecordMinMax(false)), + Aggregation.base2ExponentialBucketHistogram( + Base2ExponentialHistogramOptions.builder() + .setMaxBuckets(2) + .setMaxScale(2) + .setRecordMinMax(false) + .build()))); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java new file mode 100644 index 00000000000..382fd772f8b --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java @@ -0,0 +1,138 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class AttributeListFactoryTest { + + @ParameterizedTest + @MethodSource("invalidAttributes") + void create_InvalidAttributes(List model, String expectedMessage) { + assertThatThrownBy( + () -> + AttributeListFactory.getInstance() + .create(model, mock(DeclarativeConfigContext.class))) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessageContaining(expectedMessage); + } + + private static Stream invalidAttributes() { + return Stream.of( + Arguments.of( + Collections.singletonList(new AttributeNameValueModel().withName("key")), + "attribute value is required but is null"), + Arguments.of( + Collections.singletonList( + new AttributeNameValueModel().withName("key").withValue(new Object())), + "Error processing attribute with name \"key\": value did not match type STRING"), + Arguments.of( + Collections.singletonList( + new AttributeNameValueModel() + .withName("key") + .withType(AttributeNameValueModel.AttributeType.INT) + .withValue(Arrays.asList(1L, 1))), + "Error processing attribute with name \"key\": value did not match type INT"), + Arguments.of( + Collections.singletonList( + new AttributeNameValueModel() + .withName("key") + .withType(AttributeNameValueModel.AttributeType.INT) + .withValue(true)), + "Error processing attribute with name \"key\": value did not match type INT")); + } + + @Test + void create() { + Attributes expectedAttributes = + Attributes.builder() + .put("service.name", "my-service") + .put("strKey", "val") + .put("longKey", 1L) + .put("intKey", 2) + .put("doubleKey", 1.0d) + .put("floatKey", 2.0f) + .put("boolKey", true) + .put("strArrKey", "val1", "val2") + .put("longArrKey", 1L, 2L) + .put("intArrKey", 1, 2) + .put("doubleArrKey", 1.0d, 2.0d) + .put("floatArrKey", 1.0f, 2.0f) + .put("boolArrKey", true, false) + .build(); + assertThat( + AttributeListFactory.getInstance() + .create( + Arrays.asList( + new AttributeNameValueModel() + .withName("service.name") + .withValue("my-service"), + new AttributeNameValueModel() + .withName("strKey") + .withValue("val") + .withType(AttributeNameValueModel.AttributeType.STRING), + new AttributeNameValueModel() + .withName("longKey") + .withValue(1L) + .withType(AttributeNameValueModel.AttributeType.INT), + new AttributeNameValueModel() + .withName("intKey") + .withValue(2) + .withType(AttributeNameValueModel.AttributeType.INT), + new AttributeNameValueModel() + .withName("doubleKey") + .withValue(1.0d) + .withType(AttributeNameValueModel.AttributeType.DOUBLE), + new AttributeNameValueModel() + .withName("floatKey") + .withValue(2.0f) + .withType(AttributeNameValueModel.AttributeType.DOUBLE), + new AttributeNameValueModel() + .withName("boolKey") + .withValue(true) + .withType(AttributeNameValueModel.AttributeType.BOOL), + new AttributeNameValueModel() + .withName("strArrKey") + .withValue(Arrays.asList("val1", "val2")) + .withType(AttributeNameValueModel.AttributeType.STRING_ARRAY), + new AttributeNameValueModel() + .withName("longArrKey") + .withValue(Arrays.asList(1L, 2L)) + .withType(AttributeNameValueModel.AttributeType.INT_ARRAY), + new AttributeNameValueModel() + .withName("intArrKey") + .withValue(Arrays.asList(1, 2)) + .withType(AttributeNameValueModel.AttributeType.INT_ARRAY), + new AttributeNameValueModel() + .withName("doubleArrKey") + .withValue(Arrays.asList(1.0d, 2.0d)) + .withType(AttributeNameValueModel.AttributeType.DOUBLE_ARRAY), + new AttributeNameValueModel() + .withName("floatArrKey") + .withValue(Arrays.asList(1.0f, 2.0f)) + .withType(AttributeNameValueModel.AttributeType.DOUBLE_ARRAY), + new AttributeNameValueModel() + .withName("boolArrKey") + .withValue(Arrays.asList(true, false)) + .withType(AttributeNameValueModel.AttributeType.BOOL_ARRAY)), + mock(DeclarativeConfigContext.class))) + .isEqualTo(expectedAttributes); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java new file mode 100644 index 00000000000..ee99e1e1517 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java @@ -0,0 +1,76 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A test utility that captures the configuration passed to component providers during loading. This + * allows tests to verify that component providers receive the expected configuration. + */ +class CapturingComponentLoader implements ComponentLoader { + + private final ComponentLoader delegate; + private final Map capturedConfigs = + new ConcurrentHashMap<>(); + + CapturingComponentLoader() { + delegate = ComponentLoader.forClassLoader(getClass().getClassLoader()); + } + + DeclarativeConfigProperties getCapturedConfig(String name) { + return capturedConfigs.get(name); + } + + @Override + public Iterable load(Class spiClass) { + if (spiClass == ComponentProvider.class) { + return createWrappedComponentProviders(); + } + return delegate.load(spiClass); + } + + @SuppressWarnings("unchecked") + private Iterable createWrappedComponentProviders() { + List wrappedProviders = new ArrayList<>(); + for (ComponentProvider provider : delegate.load(ComponentProvider.class)) { + ComponentProvider wrapped = new CapturingComponentProvider(provider); + wrappedProviders.add((T) wrapped); + } + return wrappedProviders; + } + + private class CapturingComponentProvider implements ComponentProvider { + + private final ComponentProvider delegate; + + CapturingComponentProvider(ComponentProvider delegate) { + this.delegate = delegate; + } + + @Override + public Class getType() { + return delegate.getType(); + } + + @Override + public String getName() { + return delegate.getName(); + } + + @Override + public Object create(DeclarativeConfigProperties config) { + capturedConfigs.put(getName(), config); + return delegate.create(config); + } + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java new file mode 100644 index 00000000000..103abba7ee0 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java @@ -0,0 +1,78 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.mockito.Mockito.mock; + +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.CardinalityLimitsModel; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.export.CardinalityLimitSelector; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class CardinalityLimitsFactoryTest { + + @ParameterizedTest + @MethodSource("createTestCases") + void create(CardinalityLimitsModel model, CardinalityLimitSelector expectedResult) { + CardinalityLimitSelector cardinalityLimitSelector = + CardinalityLimitsFactory.getInstance().create(model, mock(DeclarativeConfigContext.class)); + + for (InstrumentType instrumentType : InstrumentType.values()) { + assertThat(cardinalityLimitSelector.getCardinalityLimit(instrumentType)) + .describedAs(instrumentType.toString()) + .isEqualTo(expectedResult.getCardinalityLimit(instrumentType)); + } + } + + private static Stream createTestCases() { + return Stream.of( + Arguments.of( + new CardinalityLimitsModel(), + CardinalityLimitSelector.defaultCardinalityLimitSelector()), + Arguments.of( + new CardinalityLimitsModel().withDefault(10).withCounter(1), + (CardinalityLimitSelector) + instrumentType -> { + if (instrumentType == InstrumentType.COUNTER) { + return 1; + } + return 10; + }), + Arguments.of( + new CardinalityLimitsModel() + .withCounter(1) + .withUpDownCounter(2) + .withHistogram(3) + .withObservableCounter(4) + .withObservableUpDownCounter(5) + .withObservableGauge(6) + .withGauge(7), + (CardinalityLimitSelector) + instrumentType -> { + switch (instrumentType) { + case COUNTER: + return 1; + case UP_DOWN_COUNTER: + return 2; + case HISTOGRAM: + return 3; + case OBSERVABLE_COUNTER: + return 4; + case OBSERVABLE_UP_DOWN_COUNTER: + return 5; + case OBSERVABLE_GAUGE: + return 6; + case GAUGE: + return 7; + } + return 2000; + })); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java new file mode 100644 index 00000000000..7e0c05e251d --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java @@ -0,0 +1,294 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.api.trace.SpanKind.CLIENT; +import static io.opentelemetry.api.trace.SpanKind.CONSUMER; +import static io.opentelemetry.api.trace.SpanKind.INTERNAL; +import static io.opentelemetry.api.trace.SpanKind.PRODUCER; +import static io.opentelemetry.api.trace.SpanKind.SERVER; +import static io.opentelemetry.sdk.extension.incubator.fileconfig.ComposableRuleBasedSamplerFactory.DeclarativeConfigSamplingPredicate.toSpanParent; +import static java.util.Collections.emptyList; +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.TraceFlags; +import io.opentelemetry.api.trace.TraceState; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; +import io.opentelemetry.sdk.extension.incubator.fileconfig.ComposableRuleBasedSamplerFactory.AttributeMatcher; +import io.opentelemetry.sdk.extension.incubator.fileconfig.ComposableRuleBasedSamplerFactory.DeclarativeConfigSamplingPredicate; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableAlwaysOffSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableAlwaysOnSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableProbabilitySamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerRuleAttributePatternsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerRuleAttributeValuesModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerRuleModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalSpanParent; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanKind; +import io.opentelemetry.sdk.extension.incubator.trace.samplers.ComposableSampler; +import io.opentelemetry.sdk.trace.IdGenerator; +import java.util.Arrays; +import java.util.Collections; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class ComposableRuleBasedSamplerFactoryTest { + + private final DeclarativeConfigContext context = + new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); + + @ParameterizedTest + @MethodSource("createTestCases") + void create(ExperimentalComposableRuleBasedSamplerModel model, ComposableSampler expectedResult) { + ComposableSampler composableSampler = + ComposableRuleBasedSamplerFactory.getInstance().create(model, context); + assertThat(composableSampler.toString()).isEqualTo(expectedResult.toString()); + } + + private static Stream createTestCases() { + return Stream.of( + Arguments.of( + new ExperimentalComposableRuleBasedSamplerModel(), + ComposableSampler.ruleBasedBuilder().build()), + // Recreate example + Arguments.of( + new ExperimentalComposableRuleBasedSamplerModel() + .withRules( + Arrays.asList( + new ExperimentalComposableRuleBasedSamplerRuleModel() + .withAttributeValues( + new ExperimentalComposableRuleBasedSamplerRuleAttributeValuesModel() + .withKey("http.route") + .withValues(Arrays.asList("/healthz", "/livez"))) + .withSampler( + new ExperimentalComposableSamplerModel() + .withAlwaysOff( + new ExperimentalComposableAlwaysOffSamplerModel())), + new ExperimentalComposableRuleBasedSamplerRuleModel() + .withAttributePatterns( + new ExperimentalComposableRuleBasedSamplerRuleAttributePatternsModel() + .withKey("http.path") + .withIncluded(Collections.singletonList("/internal/*")) + .withExcluded(Collections.singletonList("/internal/special/*"))) + .withSampler( + new ExperimentalComposableSamplerModel() + .withAlwaysOn( + new ExperimentalComposableAlwaysOnSamplerModel())), + new ExperimentalComposableRuleBasedSamplerRuleModel() + .withParent(Collections.singletonList(ExperimentalSpanParent.NONE)) + .withSpanKinds(Collections.singletonList(SpanKind.CLIENT)) + .withSampler( + new ExperimentalComposableSamplerModel() + .withProbability( + new ExperimentalComposableProbabilitySamplerModel() + .withRatio(0.05))), + new ExperimentalComposableRuleBasedSamplerRuleModel() + .withSampler( + new ExperimentalComposableSamplerModel() + .withProbability( + new ExperimentalComposableProbabilitySamplerModel() + .withRatio(0.05))))), + ComposableSampler.ruleBasedBuilder() + .add( + new DeclarativeConfigSamplingPredicate( + new AttributeMatcher( + "http.route", + IncludeExcludePredicate.createExactMatching( + Arrays.asList("/healthz", "/livez"), null)), + null, + null, + null), + ComposableSampler.alwaysOff()) + .add( + new DeclarativeConfigSamplingPredicate( + null, + new AttributeMatcher( + "http.path", + IncludeExcludePredicate.createPatternMatching( + Collections.singletonList("/internal/*"), + Collections.singletonList("/internal/special/*"))), + null, + null), + ComposableSampler.alwaysOn()) + .add( + new DeclarativeConfigSamplingPredicate( + null, + null, + Collections.singleton(ExperimentalSpanParent.NONE), + Collections.singleton(CLIENT)), + ComposableSampler.probability(0.05)) + .add( + new DeclarativeConfigSamplingPredicate(null, null, null, null), + ComposableSampler.probability(0.05)) + .build())); + } + + private static final Context noParent = Context.current(); + private static final Context localParent = + Context.root() + .with( + Span.wrap( + SpanContext.create( + IdGenerator.random().generateTraceId(), + IdGenerator.random().generateSpanId(), + TraceFlags.getDefault(), + TraceState.getDefault()))); + private static final Context remoteParent = + Context.root() + .with( + Span.wrap( + SpanContext.createFromRemoteParent( + IdGenerator.random().generateTraceId(), + IdGenerator.random().generateSpanId(), + TraceFlags.getDefault(), + TraceState.getDefault()))); + private static final String tid = IdGenerator.random().generateTraceId(); + private static final String sn = "name"; + private static final io.opentelemetry.api.trace.SpanKind sk = CLIENT; + private static final AttributeKey HTTP_ROUTE = AttributeKey.stringKey("http.route"); + private static final AttributeKey HTTP_PATH = AttributeKey.stringKey("http.path"); + + @ParameterizedTest + @MethodSource("declarativeConfigSamplingPredicateArgs") + void declarativeConfigSamplingPredicate( + DeclarativeConfigSamplingPredicate predicate, + Context context, + io.opentelemetry.api.trace.SpanKind spanKind, + Attributes attributes, + boolean expectedResult) { + assertThat(predicate.matches(context, tid, sn, spanKind, attributes, emptyList())) + .isEqualTo(expectedResult); + } + + @SuppressWarnings("unused") + private static Stream declarativeConfigSamplingPredicateArgs() { + DeclarativeConfigSamplingPredicate matchAll = + new DeclarativeConfigSamplingPredicate(null, null, null, null); + DeclarativeConfigSamplingPredicate valuesMatcher = + new DeclarativeConfigSamplingPredicate( + new AttributeMatcher( + "http.route", + IncludeExcludePredicate.createExactMatching( + Arrays.asList("/healthz", "/livez"), null)), + null, + null, + null); + DeclarativeConfigSamplingPredicate patternsMatcher = + new DeclarativeConfigSamplingPredicate( + null, + new AttributeMatcher( + "http.path", + IncludeExcludePredicate.createPatternMatching( + Collections.singletonList("/internal/*"), + Collections.singletonList("/internal/special/*"))), + null, + null); + DeclarativeConfigSamplingPredicate parentMatcher = + new DeclarativeConfigSamplingPredicate( + null, null, Collections.singleton(ExperimentalSpanParent.NONE), null); + DeclarativeConfigSamplingPredicate spanKindMatcher = + new DeclarativeConfigSamplingPredicate(null, null, null, Collections.singleton(CLIENT)); + DeclarativeConfigSamplingPredicate multiMatcher = + new DeclarativeConfigSamplingPredicate( + new AttributeMatcher( + "http.route", + IncludeExcludePredicate.createExactMatching( + Arrays.asList("/healthz", "/livez"), null)), + new AttributeMatcher( + "http.path", + IncludeExcludePredicate.createPatternMatching( + Collections.singletonList("/internal/*"), + Collections.singletonList("/internal/special/*"))), + Collections.singleton(ExperimentalSpanParent.NONE), + Collections.singleton(CLIENT)); + + return Stream.of( + // match all + Arguments.of(matchAll, noParent, sk, Attributes.empty(), true), + Arguments.of(matchAll, noParent, sk, Attributes.of(HTTP_ROUTE, "/healthz"), true), + Arguments.of( + matchAll, noParent, sk, Attributes.of(HTTP_PATH, "/internal/admin/users"), true), + Arguments.of(matchAll, noParent, SERVER, Attributes.empty(), true), + Arguments.of(matchAll, remoteParent, sk, Attributes.empty(), true), + // value matcher + Arguments.of(valuesMatcher, noParent, sk, Attributes.of(HTTP_ROUTE, "/healthz"), true), + Arguments.of(valuesMatcher, noParent, sk, Attributes.of(HTTP_ROUTE, "/livez"), true), + Arguments.of(valuesMatcher, noParent, sk, Attributes.of(HTTP_ROUTE, "/foo"), false), + Arguments.of(valuesMatcher, noParent, sk, Attributes.empty(), false), + // pattern matcher + Arguments.of( + patternsMatcher, noParent, sk, Attributes.of(HTTP_PATH, "/internal/admin/users"), true), + Arguments.of( + patternsMatcher, + noParent, + sk, + Attributes.of(HTTP_PATH, "/internal/management/config"), + true), + Arguments.of( + patternsMatcher, noParent, sk, Attributes.of(HTTP_PATH, "/users/profile/123"), false), + Arguments.of( + patternsMatcher, + noParent, + sk, + Attributes.of(HTTP_PATH, "/internal/special/foo"), + false), + // parent matcher + Arguments.of(parentMatcher, noParent, sk, Attributes.empty(), true), + Arguments.of(parentMatcher, localParent, sk, Attributes.empty(), false), + Arguments.of(parentMatcher, remoteParent, sk, Attributes.empty(), false), + // span kind matcher + Arguments.of(spanKindMatcher, noParent, CLIENT, Attributes.empty(), true), + Arguments.of(spanKindMatcher, noParent, SERVER, Attributes.empty(), false), + Arguments.of(spanKindMatcher, noParent, INTERNAL, Attributes.empty(), false), + Arguments.of(spanKindMatcher, noParent, PRODUCER, Attributes.empty(), false), + Arguments.of(spanKindMatcher, noParent, CONSUMER, Attributes.empty(), false), + // multi matcher + Arguments.of( + multiMatcher, + noParent, + CLIENT, + Attributes.of(HTTP_ROUTE, "/livez", HTTP_PATH, "/internal/admin/users"), + true), + Arguments.of(multiMatcher, noParent, CLIENT, Attributes.of(HTTP_ROUTE, "/livez"), false), + Arguments.of( + multiMatcher, + noParent, + CLIENT, + Attributes.of(HTTP_PATH, "/internal/admin/users"), + false), + Arguments.of( + multiMatcher, + noParent, + SERVER, + Attributes.of(HTTP_ROUTE, "/livez", HTTP_PATH, "/internal/admin/users"), + false), + Arguments.of( + multiMatcher, + localParent, + CLIENT, + Attributes.of(HTTP_ROUTE, "/livez", HTTP_PATH, "/internal/admin/users"), + false)); + } + + @Test + void toSpanParent_Valid() { + assertThat(toSpanParent(SpanContext.getInvalid())).isEqualTo(ExperimentalSpanParent.NONE); + assertThat(toSpanParent(Span.fromContext(localParent).getSpanContext())) + .isEqualTo(ExperimentalSpanParent.LOCAL); + assertThat(toSpanParent(Span.fromContext(remoteParent).getSpanContext())) + .isEqualTo(ExperimentalSpanParent.REMOTE); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java new file mode 100644 index 00000000000..71b9df870df --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; +import java.util.Collections; +import org.junit.jupiter.api.Test; + +class DeclarativeConfigContextTest { + + private final ComponentLoader componentLoader = + spy(ComponentLoader.forClassLoader(getClass().getClassLoader())); + private final DeclarativeConfigContext context = new DeclarativeConfigContext(componentLoader); + + @Test + void componentProvidersCached() { + // First loadComponent call should load providers + assertThatThrownBy( + () -> + context.loadComponent( + Resource.class, + ConfigKeyValue.of( + "nonexistent", + YamlDeclarativeConfigProperties.create( + Collections.emptyMap(), componentLoader)))) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessageContaining("No component provider detected"); + + // Second loadComponent call should use cached providers, not reload + assertThatThrownBy( + () -> + context.loadComponent( + Resource.class, + ConfigKeyValue.of( + "another", + YamlDeclarativeConfigProperties.create( + Collections.emptyMap(), componentLoader)))) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessageContaining("No component provider detected"); + + // Verify spiHelper.load() was only called once + verify(componentLoader, times(1)).load(ComponentProvider.class); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java new file mode 100644 index 00000000000..d1abd33fcd9 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java @@ -0,0 +1,116 @@ +/* + * 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.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import org.junit.jupiter.api.Test; + +class DeclarativeConfigurationBuilderTest { + + @Test + void spanExporterCustomizer_Single() { + DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); + + builder.addSpanExporterCustomizer( + SpanExporter.class, (exporter, properties) -> mock(SpanExporter.class)); + + assertThat(builder.getSpanExporterCustomizers()).hasSize(1); + } + + @Test + void spanExporterCustomizer_Multiple_Compose() { + DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); + + builder.addSpanExporterCustomizer( + SpanExporter.class, (exporter, properties) -> mock(SpanExporter.class)); + builder.addSpanExporterCustomizer( + SpanExporter.class, (exporter, properties) -> mock(SpanExporter.class)); + + assertThat(builder.getSpanExporterCustomizers()).hasSize(2); + } + + @Test + void metricExporterCustomizer_Single() { + DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); + + builder.addMetricExporterCustomizer( + MetricExporter.class, (exporter, properties) -> mock(MetricExporter.class)); + + assertThat(builder.getMetricExporterCustomizers()).hasSize(1); + } + + @Test + void metricExporterCustomizer_Multiple_Compose() { + DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); + + builder.addMetricExporterCustomizer( + MetricExporter.class, (exporter, properties) -> mock(MetricExporter.class)); + builder.addMetricExporterCustomizer( + MetricExporter.class, (exporter, properties) -> mock(MetricExporter.class)); + + assertThat(builder.getMetricExporterCustomizers()).hasSize(2); + } + + @Test + void logRecordExporterCustomizer_Single() { + DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); + + builder.addLogRecordExporterCustomizer( + LogRecordExporter.class, (exporter, properties) -> mock(LogRecordExporter.class)); + + assertThat(builder.getLogRecordExporterCustomizers()).hasSize(1); + } + + @Test + void logRecordExporterCustomizer_Multiple_Compose() { + DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); + + builder.addLogRecordExporterCustomizer( + LogRecordExporter.class, (exporter, properties) -> mock(LogRecordExporter.class)); + builder.addLogRecordExporterCustomizer( + LogRecordExporter.class, (exporter, properties) -> mock(LogRecordExporter.class)); + + assertThat(builder.getLogRecordExporterCustomizers()).hasSize(2); + } + + @Test + void customizer_ClosesOriginalWhenReplaced() throws Exception { + SpanExporter original = mock(SpanExporter.class); + SpanExporter replacement = mock(SpanExporter.class); + DeclarativeConfigProperties props = mock(DeclarativeConfigProperties.class); + + DeclarativeConfigurationBuilder.Customizer customizer = + new DeclarativeConfigurationBuilder.Customizer<>( + SpanExporter.class, (exporter, properties) -> replacement); + + SpanExporter result = customizer.maybeCustomize(original, "test", props); + + assertThat(result).isSameAs(replacement); + verify(original).close(); + } + + @Test + void customizer_DoesNotCloseWhenSameInstance() throws Exception { + SpanExporter exporter = mock(SpanExporter.class); + DeclarativeConfigProperties props = mock(DeclarativeConfigProperties.class); + + DeclarativeConfigurationBuilder.Customizer customizer = + new DeclarativeConfigurationBuilder.Customizer<>(SpanExporter.class, (e, properties) -> e); + + SpanExporter result = customizer.maybeCustomize(exporter, "test", props); + + assertThat(result).isSameAs(exporter); + verify(exporter, never()).close(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java new file mode 100644 index 00000000000..4fee06d72eb --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java @@ -0,0 +1,212 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent; +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.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; +import io.github.netmikey.logunit.api.LogCapturer; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.internal.testing.slf4j.SuppressLogger; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; +import io.opentelemetry.sdk.internal.ExtendedOpenTelemetrySdk; +import io.opentelemetry.sdk.trace.samplers.ParentBasedSamplerBuilder; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.cert.CertificateEncodingException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.slf4j.event.Level; + +class DeclarativeConfigurationCreateTest { + + @RegisterExtension + static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension(); + + @RegisterExtension + static final SelfSignedCertificateExtension clientTls = new SelfSignedCertificateExtension(); + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + @RegisterExtension + LogCapturer logCapturer = + LogCapturer.create().captureForLogger(DeclarativeConfiguration.class.getName(), Level.TRACE); + + /** + * Verify each example in open-telemetry/opentelemetry-configuration/examples + * can pass {@link DeclarativeConfigurationParser#parseAndCreate(InputStream)}. + */ + @ParameterizedTest + @MethodSource("exampleFiles") + @SuppressLogger(ParentBasedSamplerBuilder.class) + void parseAndCreate_Examples(File example, @TempDir Path tempDir) + throws IOException, CertificateEncodingException { + // Write certificates to temp files + String certificatePath = + createTempFileWithContent( + tempDir, "certificate.cert", serverTls.certificate().getEncoded()); + String clientKeyPath = + createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); + String clientCertificatePath = + createTempFileWithContent( + tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); + + // Rewrite references to cert files in examples + String exampleContent = + new String(Files.readAllBytes(example.toPath()), StandardCharsets.UTF_8); + String rewrittenExampleContent = + exampleContent + .replaceAll( + "ca_file: .*\n", + "ca_file: " + certificatePath.replace("\\", "\\\\") + System.lineSeparator()) + .replaceAll( + "key_file: .*\n", + "key_file: " + clientKeyPath.replace("\\", "\\\\") + System.lineSeparator()) + .replaceAll( + "cert_file: .*\n", + "cert_file: " + + clientCertificatePath.replace("\\", "\\\\") + + System.lineSeparator()); + InputStream is = + new ByteArrayInputStream(rewrittenExampleContent.getBytes(StandardCharsets.UTF_8)); + + // Verify that file can be parsed and interpreted without error + assertThatCode( + () -> cleanup.addCloseable(DeclarativeConfigurationParser.parseAndCreate(is).getSdk())) + .as("Example file: " + example.getName()) + .doesNotThrowAnyException(); + } + + private static Stream exampleFiles() { + File configRepoRoot = new File(System.getenv("CONFIG_REPO_ROOT")); + File examplesDir = new File(configRepoRoot + "/examples/"); + File snippetsDir = new File(configRepoRoot + "/snippets/"); + List examples = new ArrayList<>(); + examples.addAll(Arrays.asList(Objects.requireNonNull(examplesDir.listFiles()))); + examples.addAll(Arrays.asList(Objects.requireNonNull(snippetsDir.listFiles()))); + + return examples.stream().map(file -> Arguments.argumentSet(file.getName(), file)); + } + + @Test + void parseAndCreate_Exception_CleansUpPartials() { + // Trigger an exception after some components have been configured by adding a valid batch + // exporter with OTLP exporter, following by invalid batch exporter which references invalid + // exporter "foo". + String yaml = + "file_format: \"1.0\"\n" + + "logger_provider:\n" + + " processors:\n" + + " - batch:\n" + + " exporter:\n" + + " otlp_http: {}\n" + + " - batch:\n" + + " exporter:\n" + + " foo: {}\n"; + + assertThatThrownBy( + () -> + DeclarativeConfigurationParser.parseAndCreate( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)))) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage( + "No component provider detected for io.opentelemetry.sdk.logs.export.LogRecordExporter with name \"foo\"."); + logCapturer.assertContains( + "Error encountered interpreting model. Closing partially configured components."); + logCapturer.assertContains( + "Closing io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter"); + logCapturer.assertContains("Closing io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor"); + } + + @Test + void parseAndCreate_EmptyComponentProviderConfig() { + String yaml = + "file_format: \"1.0\"\n" + + "logger_provider:\n" + + " processors:\n" + + " - test:\n" + + "tracer_provider:\n" + + " processors:\n" + + " - test:\n"; + + assertThatCode( + () -> + DeclarativeConfigurationParser.parseAndCreate( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)))) + .doesNotThrowAnyException(); + } + + @Test + void create_ModelCustomizer() { + OpenTelemetryConfigurationModel model = new OpenTelemetryConfigurationModel(); + model.withFileFormat("1.0"); + model.withTracerProvider( + new TracerProviderModel() + .withProcessors( + Collections.singletonList( + new SpanProcessorModel().withAdditionalProperty("test", null)))); + ExtendedOpenTelemetrySdk sdk = + DeclarativeConfiguration.create( + model, + // customizer is TestDeclarativeConfigurationCustomizerProvider + ComponentLoader.forClassLoader( + DeclarativeConfigurationCreateTest.class.getClassLoader())) + .getSdk(); + assertThat(sdk.toString()) + .contains( + "resource=Resource{schemaUrl=null, attributes={" + + "color=\"blue\", " + + "foo=\"bar\", " + + "service.name=\"unknown_service:java\", " + + "telemetry.sdk.language=\"java\", " + + "telemetry.sdk.name=\"opentelemetry\", " + + "telemetry.sdk.version=\""); + } + + @Test + @SuppressLogger(DeclarativeConfiguration.class) + void callAutoConfigureListeners_exceptionIsCaught() { + DeclarativeConfigContext context = mock(DeclarativeConfigContext.class); + when(context.getListeners()) + .thenReturn( + Collections.singleton( + sdk -> { + throw new RuntimeException("Test exception from AutoConfigureListener"); + })); + + assertThatCode( + () -> + DeclarativeConfiguration.callAutoConfigureListeners( + context, OpenTelemetrySdk.builder().build())) + .doesNotThrowAnyException(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java new file mode 100644 index 00000000000..6c50081f494 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java @@ -0,0 +1,489 @@ +/* + * 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.assertThatThrownBy; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AggregationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TraceIdRatioBasedSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; +import javax.annotation.Nullable; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class DeclarativeConfigurationParseTest { + + @Test + void parse_BadInputStream() { + assertThatThrownBy( + () -> + DeclarativeConfigurationParser.parseAndCreate( + new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8)))) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage("Unable to parse configuration input stream"); + } + + @Test + void parse_nullValuesParsedToEmptyObjects() { + String objectPlaceholderString = + "file_format: \"1.0\"\n" + + "tracer_provider:\n" + + " processors:\n" + + " - batch:\n" + + " exporter:\n" + + " console: {}\n" + + "meter_provider:\n" + + " views:\n" + + " - selector:\n" + + " instrument_type: histogram\n" + + " stream:\n" + + " aggregation:\n" + + " drop: {}\n"; + OpenTelemetryConfigurationModel objectPlaceholderModel = + DeclarativeConfigurationParser.parse( + new ByteArrayInputStream(objectPlaceholderString.getBytes(StandardCharsets.UTF_8))); + + String noOjbectPlaceholderString = + "file_format: \"1.0\"\n" + + "tracer_provider:\n" + + " processors:\n" + + " - batch:\n" + + " exporter:\n" + + " console:\n" + + "meter_provider:\n" + + " views:\n" + + " - selector:\n" + + " instrument_type: histogram\n" + + " stream:\n" + + " aggregation:\n" + + " drop:\n"; + OpenTelemetryConfigurationModel noObjectPlaceholderModel = + DeclarativeConfigurationParser.parse( + new ByteArrayInputStream(noOjbectPlaceholderString.getBytes(StandardCharsets.UTF_8))); + + SpanExporterModel exporter = + noObjectPlaceholderModel + .getTracerProvider() + .getProcessors() + .get(0) + .getBatch() + .getExporter(); + assertThat(exporter.getConsole()).isNotNull(); + assertThat(exporter.getOtlpHttp()).isNull(); + + AggregationModel aggregation = + noObjectPlaceholderModel.getMeterProvider().getViews().get(0).getStream().getAggregation(); + assertThat(aggregation.getDrop()).isNotNull(); + assertThat(aggregation.getSum()).isNull(); + + assertThat(objectPlaceholderModel).isEqualTo(noObjectPlaceholderModel); + } + + @Test + void parse_nullBoxedPrimitivesParsedToNull() { + String yaml = + "file_format:\n" // String + + "disabled:\n" // Boolean + + "attribute_limits:\n" + + " attribute_value_length_limit:\n" // Integer + + "tracer_provider:\n" + + " sampler:\n" + + " trace_id_ratio_based:\n" + + " ratio:\n"; // Double + + OpenTelemetryConfigurationModel model = + DeclarativeConfigurationParser.parse( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + + assertThat(model.getFileFormat()).isNull(); + assertThat(model.getDisabled()).isNull(); + assertThat(model.getAttributeLimits().getAttributeValueLengthLimit()).isNull(); + assertThat(model.getTracerProvider().getSampler().getTraceIdRatioBased().getRatio()).isNull(); + + assertThat(model) + .isEqualTo( + new OpenTelemetryConfigurationModel() + .withAttributeLimits(new AttributeLimitsModel()) + .withTracerProvider( + new TracerProviderModel() + .withSampler( + new SamplerModel() + .withTraceIdRatioBased(new TraceIdRatioBasedSamplerModel())))); + } + + @Test + void parse_quotedInput() { + String yaml = + "resource:\n" + + " attributes:\n" + + " - name: single_quote\n" + + " value: '\"single\"'\n" + + " - name: double_quote\n" + + " value: \"\\\"double\\\"\""; + + OpenTelemetryConfigurationModel model = + DeclarativeConfigurationParser.parse( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); + + Assertions.assertNotNull(model.getResource()); + assertThat(model.getResource().getAttributes()) + .containsExactly( + new AttributeNameValueModel().withName("single_quote").withValue("\"single\""), + new AttributeNameValueModel().withName("double_quote").withValue("\"double\"")); + } + + @ParameterizedTest + @MethodSource("coreSchemaValuesArgs") + void coreSchemaValues(String rawYaml, Object expectedYamlResult) { + Object yaml = + DeclarativeConfigurationParser.loadYaml( + new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)), + Collections.emptyMap(), + Collections.emptyMap()); + assertThat(yaml).isEqualTo(expectedYamlResult); + } + + @SuppressWarnings("unchecked") + private static Stream coreSchemaValuesArgs() { + return Stream.of( + Arguments.of("key1: 0o123\n", mapOf(entry("key1", 83))), + Arguments.of("key1: 0123\n", mapOf(entry("key1", 123))), + Arguments.of("key1: 0xdeadbeef\n", mapOf(entry("key1", 3735928559L))), + Arguments.of("key1: \"0xdeadbeef\"\n", mapOf(entry("key1", "0xdeadbeef")))); + } + + @ParameterizedTest + @MethodSource("envVarSubstitutionArgs") + void envSubstituteAndLoadYaml(String rawYaml, Object expectedYamlResult) { + Map environmentVariables = new HashMap<>(); + environmentVariables.put("FOO", "BAR"); + environmentVariables.put("STR_1", "value1"); + environmentVariables.put("STR_2", "value2"); + environmentVariables.put("VALUE_WITH_ESCAPE", "value$$"); + environmentVariables.put("EMPTY_STR", ""); + environmentVariables.put("BOOL", "true"); + environmentVariables.put("INT", "1"); + environmentVariables.put("FLOAT", "1.1"); + environmentVariables.put("HEX", "0xdeadbeef"); + + Object yaml = + DeclarativeConfigurationParser.loadYaml( + new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)), + environmentVariables, + Collections.emptyMap()); + assertThat(yaml).isEqualTo(expectedYamlResult); + } + + @SuppressWarnings("unchecked") + private static Stream envVarSubstitutionArgs() { + return Stream.of( + // Simple cases + Arguments.of("key1: ${STR_1}\n", mapOf(entry("key1", "value1"))), + Arguments.of("key1: ${BOOL}\n", mapOf(entry("key1", true))), + Arguments.of("key1: ${INT}\n", mapOf(entry("key1", 1))), + Arguments.of("key1: ${FLOAT}\n", mapOf(entry("key1", 1.1))), + Arguments.of("key1: ${HEX}\n", mapOf(entry("key1", 3735928559L))), + Arguments.of( + "key1: ${STR_1}\n" + "key2: value2\n", + mapOf(entry("key1", "value1"), entry("key2", "value2"))), + Arguments.of( + "key1: ${STR_1} value1\n" + "key2: value2\n", + mapOf(entry("key1", "value1 value1"), entry("key2", "value2"))), + // Default cases + Arguments.of("key1: ${NOT_SET:-value1}\n", mapOf(entry("key1", "value1"))), + Arguments.of("key1: ${NOT_SET:-true}\n", mapOf(entry("key1", true))), + Arguments.of("key1: ${NOT_SET:-1}\n", mapOf(entry("key1", 1))), + Arguments.of("key1: ${NOT_SET:-1.1}\n", mapOf(entry("key1", 1.1))), + Arguments.of("key1: ${NOT_SET:-0xdeadbeef}\n", mapOf(entry("key1", 3735928559L))), + Arguments.of( + "key1: ${NOT_SET:-value1} value2\n" + "key2: value2\n", + mapOf(entry("key1", "value1 value2"), entry("key2", "value2"))), + // Multiple environment variables referenced + Arguments.of("key1: ${STR_1}${STR_2}\n", mapOf(entry("key1", "value1value2"))), + Arguments.of("key1: ${STR_1} ${STR_2}\n", mapOf(entry("key1", "value1 value2"))), + Arguments.of( + "key1: ${STR_1} ${NOT_SET:-default} ${STR_2}\n", + mapOf(entry("key1", "value1 default value2"))), + // Undefined / empty environment variable + Arguments.of("key1: ${EMPTY_STR}\n", mapOf(entry("key1", null))), + Arguments.of("key1: ${STR_3}\n", mapOf(entry("key1", null))), + Arguments.of("key1: ${STR_1} ${STR_3}\n", mapOf(entry("key1", "value1 "))), + // Environment variable keys must match pattern: [a-zA-Z_]+[a-zA-Z0-9_]* + Arguments.of("key1: ${VAR&}\n", mapOf(entry("key1", "${VAR&}"))), + // Environment variable substitution only takes place in scalar values of maps + Arguments.of("${STR_1}: value1\n", mapOf(entry("${STR_1}", "value1"))), + Arguments.of( + "key1:\n ${STR_1}: value1\n", + mapOf(entry("key1", mapOf(entry("${STR_1}", "value1"))))), + Arguments.of( + "key1:\n - ${STR_1}\n", mapOf(entry("key1", Collections.singletonList("${STR_1}")))), + // Double-quoted environment variables + Arguments.of("key1: \"${HEX}\"\n", mapOf(entry("key1", "0xdeadbeef"))), + Arguments.of("key1: \"${STR_1}\"\n", mapOf(entry("key1", "value1"))), + Arguments.of("key1: \"${EMPTY_STR}\"\n", mapOf(entry("key1", ""))), + Arguments.of("key1: \"${BOOL}\"\n", mapOf(entry("key1", "true"))), + Arguments.of("key1: \"${INT}\"\n", mapOf(entry("key1", "1"))), + Arguments.of("key1: \"${FLOAT}\"\n", mapOf(entry("key1", "1.1"))), + Arguments.of( + "key1: \"${HEX} ${BOOL} ${INT}\"\n", mapOf(entry("key1", "0xdeadbeef true 1"))), + // Single-quoted environment variables + Arguments.of("key1: '${HEX}'\n", mapOf(entry("key1", "0xdeadbeef"))), + Arguments.of("key1: '${STR_1}'\n", mapOf(entry("key1", "value1"))), + Arguments.of("key1: '${EMPTY_STR}'\n", mapOf(entry("key1", ""))), + Arguments.of("key1: '${BOOL}'\n", mapOf(entry("key1", "true"))), + Arguments.of("key1: '${INT}'\n", mapOf(entry("key1", "1"))), + Arguments.of("key1: '${FLOAT}'\n", mapOf(entry("key1", "1.1"))), + Arguments.of("key1: '${HEX} ${BOOL} ${INT}'\n", mapOf(entry("key1", "0xdeadbeef true 1"))), + // Escaped + Arguments.of("key1: ${FOO}\n", mapOf(entry("key1", "BAR"))), + Arguments.of("key1: $${FOO}\n", mapOf(entry("key1", "${FOO}"))), + Arguments.of("key1: $$${FOO}\n", mapOf(entry("key1", "$BAR"))), + Arguments.of("key1: $$$${FOO}\n", mapOf(entry("key1", "$${FOO}"))), + Arguments.of("key1: a $$ b\n", mapOf(entry("key1", "a $ b"))), + Arguments.of("key1: $$ b\n", mapOf(entry("key1", "$ b"))), + Arguments.of("key1: a $$\n", mapOf(entry("key1", "a $"))), + Arguments.of("key1: a $ b\n", mapOf(entry("key1", "a $ b"))), + Arguments.of("key1: $${STR_1}\n", mapOf(entry("key1", "${STR_1}"))), + Arguments.of("key1: $${STR_1}$${STR_1}\n", mapOf(entry("key1", "${STR_1}${STR_1}"))), + Arguments.of("key1: $${STR_1}$$\n", mapOf(entry("key1", "${STR_1}$"))), + Arguments.of("key1: $$${STR_1}\n", mapOf(entry("key1", "$value1"))), + Arguments.of("key1: \"$${STR_1}\"\n", mapOf(entry("key1", "${STR_1}"))), + Arguments.of("key1: $${STR_1} ${STR_2}\n", mapOf(entry("key1", "${STR_1} value2"))), + Arguments.of("key1: $${STR_1} $${STR_2}\n", mapOf(entry("key1", "${STR_1} ${STR_2}"))), + Arguments.of("key1: $${NOT_SET:-value1}\n", mapOf(entry("key1", "${NOT_SET:-value1}"))), + Arguments.of("key1: $${STR_1:-fallback}\n", mapOf(entry("key1", "${STR_1:-fallback}"))), + Arguments.of("key1: $${STR_1:-${STR_1}}\n", mapOf(entry("key1", "${STR_1:-value1}"))), + Arguments.of("key1: ${NOT_SET:-${FALLBACK}}\n", mapOf(entry("key1", "${FALLBACK}"))), + Arguments.of( + "key1: ${NOT_SET:-$${FALLBACK}}\n", mapOf(entry("key1", "${NOT_SET:-${FALLBACK}}"))), + Arguments.of("key1: ${VALUE_WITH_ESCAPE}\n", mapOf(entry("key1", "value$$")))); + } + + private static Map.Entry entry(K key, @Nullable V value) { + return new AbstractMap.SimpleEntry<>(key, value); + } + + @SuppressWarnings("unchecked") + private static Map mapOf(Map.Entry... entries) { + Map result = new HashMap<>(); + for (Map.Entry entry : entries) { + result.put(entry.getKey(), entry.getValue()); + } + return result; + } + + @ParameterizedTest + @MethodSource("sysPropertySubstitutionArgs") + void sysPropertySubstituteAndLoadYaml(String rawYaml, Object expectedYamlResult) { + Map systemProperties = new HashMap<>(); + systemProperties.put("foo.bar", "BAR"); + systemProperties.put("str.1", "value1"); + systemProperties.put("str.2", "value2"); + systemProperties.put("value.with.escape", "value$$"); + systemProperties.put("empty.str", ""); + systemProperties.put("bool.prop", "true"); + systemProperties.put("int.prop", "1"); + systemProperties.put("float.prop", "1.1"); + systemProperties.put("hex.prop", "0xdeadbeef"); + + Object yaml = + DeclarativeConfigurationParser.loadYaml( + new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)), + Collections.emptyMap(), + systemProperties); + assertThat(yaml).isEqualTo(expectedYamlResult); + } + + @SuppressWarnings("unchecked") + private static Stream sysPropertySubstitutionArgs() { + return Stream.of( + // Simple cases with sys: prefix + Arguments.of("key1: ${sys:str.1}\n", mapOf(entry("key1", "value1"))), + Arguments.of("key1: ${sys:bool.prop}\n", mapOf(entry("key1", true))), + Arguments.of("key1: ${sys:int.prop}\n", mapOf(entry("key1", 1))), + Arguments.of("key1: ${sys:float.prop}\n", mapOf(entry("key1", 1.1))), + Arguments.of("key1: ${sys:hex.prop}\n", mapOf(entry("key1", 3735928559L))), + // Default values + Arguments.of("key1: ${sys:not.set:-value1}\n", mapOf(entry("key1", "value1"))), + Arguments.of("key1: ${sys:not.set:-true}\n", mapOf(entry("key1", true))), + Arguments.of("key1: ${sys:not.set:-1}\n", mapOf(entry("key1", 1))), + // Multiple property references + Arguments.of("key1: ${sys:str.1}${sys:str.2}\n", mapOf(entry("key1", "value1value2"))), + Arguments.of("key1: ${sys:str.1} ${sys:str.2}\n", mapOf(entry("key1", "value1 value2"))), + Arguments.of( + "key1: ${sys:str.1} ${sys:not.set:-default} ${sys:str.2}\n", + mapOf(entry("key1", "value1 default value2"))), + // Undefined / empty system property + Arguments.of("key1: ${sys:empty.str}\n", mapOf(entry("key1", null))), + Arguments.of("key1: ${sys:str.3}\n", mapOf(entry("key1", null))), + Arguments.of("key1: ${sys:str.1} ${sys:str.3}\n", mapOf(entry("key1", "value1 "))), + // Quoted system properties + Arguments.of("key1: \"${sys:hex.prop}\"\n", mapOf(entry("key1", "0xdeadbeef"))), + Arguments.of("key1: \"${sys:str.1}\"\n", mapOf(entry("key1", "value1"))), + Arguments.of("key1: '${sys:str.1}'\n", mapOf(entry("key1", "value1"))), + // Escaped + Arguments.of("key1: ${sys:foo.bar}\n", mapOf(entry("key1", "BAR"))), + Arguments.of("key1: $${sys:foo.bar}\n", mapOf(entry("key1", "${sys:foo.bar}"))), + Arguments.of("key1: $$${sys:foo.bar}\n", mapOf(entry("key1", "$BAR"))), + Arguments.of("key1: $$$${sys:foo.bar}\n", mapOf(entry("key1", "$${sys:foo.bar}"))), + // Mixed env and sys + Arguments.of("key1: ${sys:value.with.escape}\n", mapOf(entry("key1", "value$$")))); + } + + @Test + void read_WithEnvironmentVariables() { + String yaml = + "file_format: \"1.0\"\n" + + "tracer_provider:\n" + + " processors:\n" + + " - batch:\n" + + " exporter:\n" + + " otlp_http:\n" + + " endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT}\n" + + " - batch:\n" + + " exporter:\n" + + " otlp_http:\n" + + " endpoint: ${UNSET_ENV_VAR}\n"; + Map envVars = new HashMap<>(); + envVars.put("OTEL_EXPORTER_OTLP_ENDPOINT", "http://collector:4317"); + OpenTelemetryConfigurationModel model = + DeclarativeConfigurationParser.parse( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), + envVars, + Collections.emptyMap()); + assertThat(model) + .isEqualTo( + new OpenTelemetryConfigurationModel() + .withFileFormat("1.0") + .withTracerProvider( + new TracerProviderModel() + .withProcessors( + Arrays.asList( + new SpanProcessorModel() + .withBatch( + new BatchSpanProcessorModel() + .withExporter( + new SpanExporterModel() + .withOtlpHttp( + new OtlpHttpExporterModel() + .withEndpoint( + "http://collector:4317")))), + new SpanProcessorModel() + .withBatch( + new BatchSpanProcessorModel() + .withExporter( + new SpanExporterModel() + .withOtlpHttp( + new OtlpHttpExporterModel()))))))); + } + + @Test + void read_WithSystemProperties() { + String yaml = + "file_format: \"1.0\"\n" + + "tracer_provider:\n" + + " processors:\n" + + " - batch:\n" + + " exporter:\n" + + " otlp_http:\n" + + " endpoint: ${sys:otel.exporter.otlp.endpoint}\n" + + " - batch:\n" + + " exporter:\n" + + " otlp_http:\n" + + " endpoint: ${sys:unset.sys.prop}\n"; + Map sysProps = new HashMap<>(); + sysProps.put("otel.exporter.otlp.endpoint", "http://collector:4318"); + OpenTelemetryConfigurationModel model = + DeclarativeConfigurationParser.parse( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), + Collections.emptyMap(), + sysProps); + assertThat(model) + .isEqualTo( + new OpenTelemetryConfigurationModel() + .withFileFormat("1.0") + .withTracerProvider( + new TracerProviderModel() + .withProcessors( + Arrays.asList( + new SpanProcessorModel() + .withBatch( + new BatchSpanProcessorModel() + .withExporter( + new SpanExporterModel() + .withOtlpHttp( + new OtlpHttpExporterModel() + .withEndpoint( + "http://collector:4318")))), + new SpanProcessorModel() + .withBatch( + new BatchSpanProcessorModel() + .withExporter( + new SpanExporterModel() + .withOtlpHttp( + new OtlpHttpExporterModel()))))))); + } + + @Test + void read_WithMixedEnvVarsAndSystemProperties() { + String yaml = + "file_format: \"1.0\"\n" + + "resource:\n" + + " attributes:\n" + + " - name: service.name\n" + + " value: ${SERVICE_NAME}\n" + + " - name: service.version\n" + + " value: ${sys:app.version}\n" + + " - name: deployment.environment\n" + + " value: ${env:DEPLOYMENT_ENV:-production}\n"; + Map envVars = new HashMap<>(); + envVars.put("SERVICE_NAME", "my-service"); + Map sysProps = new HashMap<>(); + sysProps.put("app.version", "1.2.3"); + OpenTelemetryConfigurationModel model = + DeclarativeConfigurationParser.parse( + new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), envVars, sysProps); + assertThat(model) + .isEqualTo( + new OpenTelemetryConfigurationModel() + .withFileFormat("1.0") + .withResource( + new ResourceModel() + .withAttributes( + Arrays.asList( + new AttributeNameValueModel() + .withName("service.name") + .withValue("my-service"), + new AttributeNameValueModel() + .withName("service.version") + .withValue("1.2.3"), + new AttributeNameValueModel() + .withName("deployment.environment") + .withValue("production"))))); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java new file mode 100644 index 00000000000..79fa0bbde45 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java @@ -0,0 +1,34 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.mockito.Mockito.mock; + +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel; +import io.opentelemetry.sdk.metrics.ExemplarFilter; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class ExemplarFilterFactoryTest { + + @ParameterizedTest + @MethodSource("createTestCases") + void create(MeterProviderModel.ExemplarFilter model, ExemplarFilter expectedResult) { + ExemplarFilter exemplarFilter = + ExemplarFilterFactory.getInstance().create(model, mock(DeclarativeConfigContext.class)); + assertThat(exemplarFilter.toString()).isEqualTo(expectedResult.toString()); + } + + private static Stream createTestCases() { + return Stream.of( + Arguments.of(MeterProviderModel.ExemplarFilter.ALWAYS_ON, ExemplarFilter.alwaysOn()), + Arguments.of(MeterProviderModel.ExemplarFilter.ALWAYS_OFF, ExemplarFilter.alwaysOff()), + Arguments.of(MeterProviderModel.ExemplarFilter.TRACE_BASED, ExemplarFilter.traceBased())); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java new file mode 100644 index 00000000000..f98bf6e698c --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +final class FileConfigTestUtil { + + private FileConfigTestUtil() {} + + static String createTempFileWithContent(Path dir, String filename, byte[] content) + throws IOException { + Path path = dir.resolve(filename); + Files.write(path, content); + return path.toString(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java new file mode 100644 index 00000000000..d0362c5e242 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java @@ -0,0 +1,53 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewSelectorModel; +import io.opentelemetry.sdk.metrics.InstrumentSelector; +import io.opentelemetry.sdk.metrics.InstrumentType; +import org.junit.jupiter.api.Test; + +class InstrumentSelectorFactoryTest { + + @Test + void create_Defaults() { + assertThatThrownBy( + () -> + InstrumentSelectorFactory.getInstance() + .create(new ViewSelectorModel(), mock(DeclarativeConfigContext.class))) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage("Invalid selector"); + } + + @Test + void create() { + assertThat( + InstrumentSelectorFactory.getInstance() + .create( + new ViewSelectorModel() + .withInstrumentName("instrument-name") + .withInstrumentType(ViewSelectorModel.InstrumentType.COUNTER) + .withUnit("ms") + .withMeterName("meter-name") + .withMeterSchemaUrl("https://opentelemetry.io/schemas/1.16.0") + .withMeterVersion("1.0.0"), + mock(DeclarativeConfigContext.class))) + .isEqualTo( + InstrumentSelector.builder() + .setName("instrument-name") + .setType(InstrumentType.COUNTER) + .setUnit("ms") + .setMeterName("meter-name") + .setMeterSchemaUrl("https://opentelemetry.io/schemas/1.16.0") + .setMeterVersion("1.0.0") + .build()); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java new file mode 100644 index 00000000000..5fab6df6d11 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java @@ -0,0 +1,53 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.mockito.Mockito.mock; + +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordLimitsModel; +import io.opentelemetry.sdk.logs.LogLimits; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class LogLimitsFactoryTest { + + @ParameterizedTest + @MethodSource("createArguments") + void create(LogRecordLimitsAndAttributeLimits model, LogLimits expectedLogLimits) { + assertThat(LogLimitsFactory.getInstance().create(model, mock(DeclarativeConfigContext.class))) + .isEqualTo(expectedLogLimits); + } + + private static Stream createArguments() { + return Stream.of( + Arguments.of( + LogRecordLimitsAndAttributeLimits.create(null, null), LogLimits.builder().build()), + Arguments.of( + LogRecordLimitsAndAttributeLimits.create( + new AttributeLimitsModel(), new LogRecordLimitsModel()), + LogLimits.builder().build()), + Arguments.of( + LogRecordLimitsAndAttributeLimits.create( + new AttributeLimitsModel() + .withAttributeValueLengthLimit(1) + .withAttributeCountLimit(2), + new LogRecordLimitsModel()), + LogLimits.builder().setMaxAttributeValueLength(1).setMaxNumberOfAttributes(2).build()), + Arguments.of( + LogRecordLimitsAndAttributeLimits.create( + new AttributeLimitsModel() + .withAttributeValueLengthLimit(1) + .withAttributeCountLimit(2), + new LogRecordLimitsModel() + .withAttributeValueLengthLimit(3) + .withAttributeCountLimit(4)), + LogLimits.builder().setMaxAttributeValueLength(3).setMaxNumberOfAttributes(4).build())); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java new file mode 100644 index 00000000000..d9e67056f06 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java @@ -0,0 +1,421 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter; +import io.opentelemetry.exporter.logging.otlp.internal.logs.OtlpStdoutLogRecordExporter; +import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; +import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordExporterComponentProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalOtlpFileExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.GrpcTlsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HttpTlsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterPropertyModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpGrpcExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Path; +import java.security.cert.CertificateEncodingException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.io.TempDir; + +class LogRecordExporterFactoryTest { + + @RegisterExtension + static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension(); + + @RegisterExtension + static final SelfSignedCertificateExtension clientTls = new SelfSignedCertificateExtension(); + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + private CapturingComponentLoader capturingComponentLoader; + private DeclarativeConfigContext context; + + @BeforeEach + void setup() { + capturingComponentLoader = new CapturingComponentLoader(); + context = new DeclarativeConfigContext(capturingComponentLoader); + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @Test + void create_OtlpHttpDefaults() { + List closeables = new ArrayList<>(); + OtlpHttpLogRecordExporter expectedExporter = + OtlpHttpLogRecordExporter.getDefault().toBuilder() + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + LogRecordExporter exporter = + LogRecordExporterFactory.getInstance() + .create( + new LogRecordExporterModel().withOtlpHttp(new OtlpHttpExporterModel()), context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_http"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("protocol")).isNull(); + assertThat(configProperties.getString("endpoint")).isNull(); + assertThat(configProperties.getStructured("headers")).isNull(); + assertThat(configProperties.getString("compression")).isNull(); + assertThat(configProperties.getInt("timeout")).isNull(); + assertThat(configProperties.getString("certificate_file")).isNull(); + assertThat(configProperties.getString("client_key_file")).isNull(); + assertThat(configProperties.getString("client_certificate_file")).isNull(); + } + + @Test + void create_OtlpHttpConfigured(@TempDir Path tempDir) + throws CertificateEncodingException, IOException { + List closeables = new ArrayList<>(); + OtlpHttpLogRecordExporter expectedExporter = + OtlpHttpLogRecordExporter.builder() + .setEndpoint("http://example:4318/v1/logs") + .addHeader("key1", "value1") + .addHeader("key2", "value2") + .setTimeout(Duration.ofSeconds(15)) + .setCompression("gzip") + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + // Write certificates to temp files + String certificatePath = + createTempFileWithContent( + tempDir, "certificate.cert", serverTls.certificate().getEncoded()); + String clientKeyPath = + createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); + String clientCertificatePath = + createTempFileWithContent( + tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); + + LogRecordExporter exporter = + LogRecordExporterFactory.getInstance() + .create( + new LogRecordExporterModel() + .withOtlpHttp( + new OtlpHttpExporterModel() + .withEndpoint("http://example:4318/v1/logs") + .withHeaders( + Arrays.asList( + new NameStringValuePairModel() + .withName("key1") + .withValue("value1"), + new NameStringValuePairModel() + .withName("key2") + .withValue("value2"))) + .withCompression("gzip") + .withTimeout(15_000) + .withTls( + new HttpTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath))), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_http"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/logs"); + List headers = configProperties.getStructuredList("headers"); + assertThat(headers) + .isNotNull() + .satisfiesExactly( + header -> { + assertThat(header.getString("name")).isEqualTo("key1"); + assertThat(header.getString("value")).isEqualTo("value1"); + }, + header -> { + assertThat(header.getString("name")).isEqualTo("key2"); + assertThat(header.getString("value")).isEqualTo("value2"); + }); + assertThat(configProperties.getString("compression")).isEqualTo("gzip"); + assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); + DeclarativeConfigProperties tls = configProperties.getStructured("tls"); + assertThat(tls).isNotNull(); + assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); + assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); + assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); + } + + @Test + void create_OtlpGrpcDefaults() { + List closeables = new ArrayList<>(); + OtlpGrpcLogRecordExporter expectedExporter = + OtlpGrpcLogRecordExporter.getDefault().toBuilder() + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + LogRecordExporter exporter = + LogRecordExporterFactory.getInstance() + .create( + new LogRecordExporterModel().withOtlpGrpc(new OtlpGrpcExporterModel()), context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_grpc"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("endpoint")).isNull(); + assertThat(configProperties.getStructured("headers")).isNull(); + assertThat(configProperties.getString("compression")).isNull(); + assertThat(configProperties.getInt("timeout")).isNull(); + assertThat(configProperties.getString("certificate_file")).isNull(); + assertThat(configProperties.getString("client_key_file")).isNull(); + assertThat(configProperties.getString("client_certificate_file")).isNull(); + } + + @Test + void create_OtlpGrpcConfigured(@TempDir Path tempDir) + throws CertificateEncodingException, IOException { + List closeables = new ArrayList<>(); + OtlpGrpcLogRecordExporter expectedExporter = + OtlpGrpcLogRecordExporter.builder() + .setEndpoint("http://example:4317") + .addHeader("key1", "value1") + .addHeader("key2", "value2") + .setTimeout(Duration.ofSeconds(15)) + .setCompression("gzip") + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + // Write certificates to temp files + String certificatePath = + createTempFileWithContent( + tempDir, "certificate.cert", serverTls.certificate().getEncoded()); + String clientKeyPath = + createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); + String clientCertificatePath = + createTempFileWithContent( + tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); + + LogRecordExporter exporter = + LogRecordExporterFactory.getInstance() + .create( + new LogRecordExporterModel() + .withOtlpGrpc( + new OtlpGrpcExporterModel() + .withEndpoint("http://example:4317") + .withHeaders( + Arrays.asList( + new NameStringValuePairModel() + .withName("key1") + .withValue("value1"), + new NameStringValuePairModel() + .withName("key2") + .withValue("value2"))) + .withCompression("gzip") + .withTimeout(15_000) + .withTls( + new GrpcTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath))), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_grpc"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4317"); + List headers = configProperties.getStructuredList("headers"); + assertThat(headers) + .isNotNull() + .satisfiesExactly( + header -> { + assertThat(header.getString("name")).isEqualTo("key1"); + assertThat(header.getString("value")).isEqualTo("value1"); + }, + header -> { + assertThat(header.getString("name")).isEqualTo("key2"); + assertThat(header.getString("value")).isEqualTo("value2"); + }); + assertThat(configProperties.getString("compression")).isEqualTo("gzip"); + assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); + DeclarativeConfigProperties tls = configProperties.getStructured("tls"); + assertThat(tls).isNotNull(); + assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); + assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); + assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); + } + + @Test + void create_OtlpFile() { + List closeables = new ArrayList<>(); + OtlpStdoutLogRecordExporter expectedExporter = OtlpStdoutLogRecordExporter.builder().build(); + cleanup.addCloseable(expectedExporter); + + LogRecordExporter exporter = + LogRecordExporterFactory.getInstance() + .create( + new LogRecordExporterModel() + .withOtlpFileDevelopment(new ExperimentalOtlpFileExporterModel()), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_file/development"); + assertThat(configProperties).isNotNull(); + } + + @Test + void create_SpiExporter_Unknown() { + List closeables = new ArrayList<>(); + + assertThatThrownBy( + () -> + LogRecordExporterFactory.getInstance() + .create( + new LogRecordExporterModel() + .withAdditionalProperty( + "unknown_key", + new LogRecordExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage( + "No component provider detected for io.opentelemetry.sdk.logs.export.LogRecordExporter with name \"unknown_key\"."); + cleanup.addCloseables(closeables); + } + + @Test + void create_SpiExporter_Valid() { + LogRecordExporter logRecordExporter = + LogRecordExporterFactory.getInstance() + .create( + new LogRecordExporterModel() + .withAdditionalProperty( + "test", + new LogRecordExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), + context); + assertThat(logRecordExporter) + .isInstanceOf(LogRecordExporterComponentProvider.TestLogRecordExporter.class); + assertThat( + ((LogRecordExporterComponentProvider.TestLogRecordExporter) logRecordExporter) + .config.getString("key1")) + .isEqualTo("value1"); + } + + @Test + void create_Customizer() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addLogRecordExporterCustomizer( + LogRecordExporter.class, (exporter, properties) -> SystemOutLogRecordExporter.create()); + + LogRecordExporter result = + LogRecordExporterFactory.getInstance() + .create(new LogRecordExporterModel().withConsole(new ConsoleExporterModel()), context); + cleanup.addCloseable(result); + + assertThat(result).isInstanceOf(SystemOutLogRecordExporter.class); + } + + @Test + void create_Customizer_TypeSafe() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addLogRecordExporterCustomizer( + OtlpGrpcLogRecordExporter.class, + (exporter, properties) -> + exporter.toBuilder().setTimeout(Duration.ofSeconds(42)).build()); + + LogRecordExporter result = + LogRecordExporterFactory.getInstance() + .create( + new LogRecordExporterModel().withOtlpGrpc(new OtlpGrpcExporterModel()), context); + cleanup.addCloseable(result); + + assertThat(result).isInstanceOf(OtlpGrpcLogRecordExporter.class); + assertThat(result.toString()).contains("timeoutNanos=42000000000"); + } + + @Test + void create_Customizer_TypeMismatch() { + AtomicInteger callCount = new AtomicInteger(0); + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addLogRecordExporterCustomizer( + OtlpGrpcLogRecordExporter.class, + (exporter, properties) -> { + callCount.incrementAndGet(); + return exporter; + }); + + LogRecordExporter result = + LogRecordExporterFactory.getInstance() + .create(new LogRecordExporterModel().withConsole(new ConsoleExporterModel()), context); + cleanup.addCloseable(result); + + assertThat(callCount.get()).isEqualTo(0); + } + + @Test + void create_Customizer_ReturnsNull() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addLogRecordExporterCustomizer(LogRecordExporter.class, (exporter, properties) -> null); + + assertThatThrownBy( + () -> + LogRecordExporterFactory.getInstance() + .create( + new LogRecordExporterModel().withConsole(new ConsoleExporterModel()), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessageContaining("Customizer returned null for LogRecordExporter: console"); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java new file mode 100644 index 00000000000..8a863f238f7 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java @@ -0,0 +1,186 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordProcessorComponentProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorPropertyModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleLogRecordProcessorModel; +import io.opentelemetry.sdk.logs.LogRecordProcessor; +import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; +import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; +import java.io.Closeable; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class LogRecordProcessorFactoryTest { + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + private final DeclarativeConfigContext context = + new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); + + @BeforeEach + void setup() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @Test + void create_BatchNullExporter() { + assertThatThrownBy( + () -> + LogRecordProcessorFactory.getInstance() + .create( + new LogRecordProcessorModel().withBatch(new BatchLogRecordProcessorModel()), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage("batch log record processor exporter is required but is null"); + } + + @Test + void create_BatchDefaults() { + List closeables = new ArrayList<>(); + BatchLogRecordProcessor expectedProcessor = + BatchLogRecordProcessor.builder( + OtlpHttpLogRecordExporter.builder().setComponentLoader(context).build()) + .build(); + cleanup.addCloseable(expectedProcessor); + + LogRecordProcessor processor = + LogRecordProcessorFactory.getInstance() + .create( + new LogRecordProcessorModel() + .withBatch( + new BatchLogRecordProcessorModel() + .withExporter( + new LogRecordExporterModel() + .withOtlpHttp(new OtlpHttpExporterModel()))), + context); + cleanup.addCloseable(processor); + cleanup.addCloseables(closeables); + + assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); + } + + @Test + void create_BatchConfigured() { + List closeables = new ArrayList<>(); + BatchLogRecordProcessor expectedProcessor = + BatchLogRecordProcessor.builder( + OtlpHttpLogRecordExporter.builder().setComponentLoader(context).build()) + .setScheduleDelay(Duration.ofMillis(1)) + .setMaxExportBatchSize(2) + .setExporterTimeout(Duration.ofMillis(3)) + .build(); + cleanup.addCloseable(expectedProcessor); + + LogRecordProcessor processor = + LogRecordProcessorFactory.getInstance() + .create( + new LogRecordProcessorModel() + .withBatch( + new BatchLogRecordProcessorModel() + .withExporter( + new LogRecordExporterModel() + .withOtlpHttp(new OtlpHttpExporterModel())) + .withScheduleDelay(1) + .withMaxExportBatchSize(2) + .withExportTimeout(3)), + context); + cleanup.addCloseable(processor); + cleanup.addCloseables(closeables); + + assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); + } + + @Test + void create_SimpleNullExporter() { + assertThatThrownBy( + () -> + LogRecordProcessorFactory.getInstance() + .create( + new LogRecordProcessorModel() + .withSimple(new SimpleLogRecordProcessorModel()), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage("simple log record processor exporter is required but is null"); + } + + @Test + void create_SimpleConfigured() { + List closeables = new ArrayList<>(); + LogRecordProcessor expectedProcessor = + SimpleLogRecordProcessor.create( + OtlpHttpLogRecordExporter.builder().setComponentLoader(context).build()); + cleanup.addCloseable(expectedProcessor); + + LogRecordProcessor processor = + LogRecordProcessorFactory.getInstance() + .create( + new LogRecordProcessorModel() + .withSimple( + new SimpleLogRecordProcessorModel() + .withExporter( + new LogRecordExporterModel() + .withOtlpHttp(new OtlpHttpExporterModel()))), + context); + cleanup.addCloseable(processor); + cleanup.addCloseables(closeables); + + assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); + } + + @Test + void create_SpiProcessor_Unknown() { + assertThatThrownBy( + () -> + LogRecordProcessorFactory.getInstance() + .create( + new LogRecordProcessorModel() + .withAdditionalProperty( + "unknown_key", + new LogRecordProcessorPropertyModel() + .withAdditionalProperty("key1", "value1")), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage( + "No component provider detected for io.opentelemetry.sdk.logs.LogRecordProcessor with name \"unknown_key\"."); + } + + @Test + void create_SpiExporter_Valid() { + LogRecordProcessor logRecordProcessor = + LogRecordProcessorFactory.getInstance() + .create( + new LogRecordProcessorModel() + .withAdditionalProperty( + "test", + new LogRecordProcessorPropertyModel() + .withAdditionalProperty("key1", "value1")), + context); + assertThat(logRecordProcessor) + .isInstanceOf(LogRecordProcessorComponentProvider.TestLogRecordProcessor.class); + Assertions.assertThat( + ((LogRecordProcessorComponentProvider.TestLogRecordProcessor) logRecordProcessor) + .config.getString("key1")) + .isEqualTo("value1"); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java new file mode 100644 index 00000000000..3381b3ea5e5 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java @@ -0,0 +1,165 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil.setLoggerConfigurator; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.sdk.common.internal.ScopeConfigurator; +import io.opentelemetry.sdk.common.internal.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLoggerConfigModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLoggerConfiguratorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLoggerMatcherAndConfigModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel.SeverityNumber; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; +import io.opentelemetry.sdk.logs.LogLimits; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; +import io.opentelemetry.sdk.logs.internal.LoggerConfig; +import java.io.Closeable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class LoggerProviderFactoryTest { + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + private static final DeclarativeConfigContext context = + new DeclarativeConfigContext( + ComponentLoader.forClassLoader(LoggerProviderFactoryTest.class.getClassLoader())); + + @BeforeEach + void setup() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @ParameterizedTest + @MethodSource("createArguments") + void create(LoggerProviderAndAttributeLimits model, SdkLoggerProvider expectedProvider) { + List closeables = new ArrayList<>(); + cleanup.addCloseable(expectedProvider); + + SdkLoggerProvider provider = LoggerProviderFactory.getInstance().create(model, context).build(); + cleanup.addCloseable(provider); + cleanup.addCloseables(closeables); + + assertThat(provider.toString()).isEqualTo(expectedProvider.toString()); + } + + private static Stream createArguments() { + return Stream.of( + Arguments.of( + LoggerProviderAndAttributeLimits.create(null, null), + SdkLoggerProvider.builder().build()), + Arguments.of( + LoggerProviderAndAttributeLimits.create( + new AttributeLimitsModel(), new LoggerProviderModel()), + SdkLoggerProvider.builder().build()), + Arguments.of( + LoggerProviderAndAttributeLimits.create( + new AttributeLimitsModel(), + new LoggerProviderModel() + .withLimits( + new LogRecordLimitsModel() + .withAttributeCountLimit(1) + .withAttributeValueLengthLimit(2)) + .withProcessors( + Collections.singletonList( + new LogRecordProcessorModel() + .withBatch( + new BatchLogRecordProcessorModel() + .withExporter( + new LogRecordExporterModel() + .withOtlpHttp(new OtlpHttpExporterModel()))))) + .withLoggerConfiguratorDevelopment( + new ExperimentalLoggerConfiguratorModel() + .withDefaultConfig( + new ExperimentalLoggerConfigModel().withEnabled(false)) + .withLoggers( + Collections.singletonList( + new ExperimentalLoggerMatcherAndConfigModel() + .withName("foo") + .withConfig( + new ExperimentalLoggerConfigModel() + .withEnabled(true) + .withTraceBased(true) + .withMinimumSeverity(SeverityNumber.INFO)))))), + setLoggerConfigurator( + SdkLoggerProvider.builder(), + ScopeConfigurator.builder() + .setDefault(LoggerConfig.disabled()) + .addCondition( + ScopeConfiguratorBuilder.nameMatchesGlob("foo"), + LoggerConfig.builder() + .setEnabled(true) + .setTraceBased(true) + .setMinimumSeverity(Severity.INFO) + .build()) + .build()) + .setLogLimits( + () -> + LogLimits.builder() + .setMaxNumberOfAttributes(1) + .setMaxAttributeValueLength(2) + .build()) + .addLogRecordProcessor( + BatchLogRecordProcessor.builder( + OtlpHttpLogRecordExporter.builder().setComponentLoader(context).build()) + .build()) + .build())); + } + + @ParameterizedTest + @MethodSource("severityNumberArguments") + void severityNumber(SeverityNumber model, Severity expectedSeverity) { + assertThat(LoggerProviderFactory.severityNumberToSeverity(model)).isEqualTo(expectedSeverity); + } + + private static Stream severityNumberArguments() { + return Stream.of( + Arguments.of(SeverityNumber.TRACE, Severity.TRACE), + Arguments.of(SeverityNumber.TRACE_2, Severity.TRACE2), + Arguments.of(SeverityNumber.TRACE_3, Severity.TRACE3), + Arguments.of(SeverityNumber.TRACE_4, Severity.TRACE4), + Arguments.of(SeverityNumber.DEBUG, Severity.DEBUG), + Arguments.of(SeverityNumber.DEBUG_2, Severity.DEBUG2), + Arguments.of(SeverityNumber.DEBUG_3, Severity.DEBUG3), + Arguments.of(SeverityNumber.DEBUG_4, Severity.DEBUG4), + Arguments.of(SeverityNumber.INFO, Severity.INFO), + Arguments.of(SeverityNumber.INFO_2, Severity.INFO2), + Arguments.of(SeverityNumber.INFO_3, Severity.INFO3), + Arguments.of(SeverityNumber.INFO_4, Severity.INFO4), + Arguments.of(SeverityNumber.WARN, Severity.WARN), + Arguments.of(SeverityNumber.WARN_2, Severity.WARN2), + Arguments.of(SeverityNumber.WARN_3, Severity.WARN3), + Arguments.of(SeverityNumber.WARN_4, Severity.WARN4), + Arguments.of(SeverityNumber.ERROR, Severity.ERROR), + Arguments.of(SeverityNumber.ERROR_2, Severity.ERROR2), + Arguments.of(SeverityNumber.ERROR_3, Severity.ERROR3), + Arguments.of(SeverityNumber.ERROR_4, Severity.ERROR4), + Arguments.of(SeverityNumber.FATAL, Severity.FATAL), + Arguments.of(SeverityNumber.FATAL_2, Severity.FATAL2), + Arguments.of(SeverityNumber.FATAL_3, Severity.FATAL3), + Arguments.of(SeverityNumber.FATAL_4, Severity.FATAL4)); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java new file mode 100644 index 00000000000..1254b411992 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java @@ -0,0 +1,119 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil.setMeterConfigurator; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.sdk.common.internal.ScopeConfigurator; +import io.opentelemetry.sdk.common.internal.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalMeterConfigModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalMeterConfiguratorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalMeterMatcherAndConfigModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewSelectorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewStreamModel; +import io.opentelemetry.sdk.metrics.ExemplarFilter; +import io.opentelemetry.sdk.metrics.InstrumentSelector; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.View; +import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; +import io.opentelemetry.sdk.metrics.internal.MeterConfig; +import java.io.Closeable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class MeterProviderFactoryTest { + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + private static final DeclarativeConfigContext context = + new DeclarativeConfigContext( + ComponentLoader.forClassLoader(MeterProviderFactoryTest.class.getClassLoader())); + + @BeforeEach + void setup() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @ParameterizedTest + @MethodSource("createArguments") + void create(MeterProviderModel model, SdkMeterProvider expectedProvider) { + List closeables = new ArrayList<>(); + cleanup.addCloseable(expectedProvider); + + SdkMeterProvider provider = MeterProviderFactory.getInstance().create(model, context).build(); + cleanup.addCloseable(provider); + cleanup.addCloseables(closeables); + + assertThat(provider.toString()).isEqualTo(expectedProvider.toString()); + } + + private static Stream createArguments() { + return Stream.of( + Arguments.of(new MeterProviderModel(), SdkMeterProvider.builder().build()), + Arguments.of( + new MeterProviderModel() + .withReaders( + Collections.singletonList( + new MetricReaderModel() + .withPeriodic( + new PeriodicMetricReaderModel() + .withExporter( + new PushMetricExporterModel() + .withOtlpHttp(new OtlpHttpMetricExporterModel()))))) + .withViews( + Collections.singletonList( + new ViewModel() + .withSelector( + new ViewSelectorModel().withInstrumentName("instrument-name")) + .withStream( + new ViewStreamModel() + .withName("stream-name") + .withAttributeKeys(null)))) + .withMeterConfiguratorDevelopment( + new ExperimentalMeterConfiguratorModel() + .withDefaultConfig(new ExperimentalMeterConfigModel().withEnabled(false)) + .withMeters( + Collections.singletonList( + new ExperimentalMeterMatcherAndConfigModel() + .withName("foo") + .withConfig( + new ExperimentalMeterConfigModel().withEnabled(true))))) + .withExemplarFilter(MeterProviderModel.ExemplarFilter.ALWAYS_ON), + setMeterConfigurator( + SdkMeterProvider.builder(), + ScopeConfigurator.builder() + .setDefault(MeterConfig.disabled()) + .addCondition( + ScopeConfiguratorBuilder.nameMatchesGlob("foo"), MeterConfig.enabled()) + .build()) + .setExemplarFilter(ExemplarFilter.alwaysOn()) + .registerMetricReader( + PeriodicMetricReader.builder( + OtlpHttpMetricExporter.builder().setComponentLoader(context).build()) + .build()) + .registerView( + InstrumentSelector.builder().setName("instrument-name").build(), + View.builder().setName("stream-name").build()) + .build())); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java new file mode 100644 index 00000000000..62e48f337f7 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java @@ -0,0 +1,474 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.exporter.logging.LoggingMetricExporter; +import io.opentelemetry.exporter.logging.otlp.internal.metrics.OtlpStdoutMetricExporter; +import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; +import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.sdk.extension.incubator.fileconfig.component.MetricExporterComponentProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalOtlpFileMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.GrpcTlsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HttpTlsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpGrpcMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterPropertyModel; +import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; +import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Path; +import java.security.cert.CertificateEncodingException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.io.TempDir; + +class MetricExporterFactoryTest { + + @RegisterExtension + static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension(); + + @RegisterExtension + static final SelfSignedCertificateExtension clientTls = new SelfSignedCertificateExtension(); + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + private CapturingComponentLoader capturingComponentLoader; + private DeclarativeConfigContext context; + + @BeforeEach + void setup() { + capturingComponentLoader = new CapturingComponentLoader(); + context = new DeclarativeConfigContext(capturingComponentLoader); + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @Test + void create_OtlpHttpDefaults() { + List closeables = new ArrayList<>(); + OtlpHttpMetricExporter expectedExporter = + OtlpHttpMetricExporter.getDefault().toBuilder() + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + MetricExporter exporter = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel().withOtlpHttp(new OtlpHttpMetricExporterModel()), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_http"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("protocol")).isNull(); + assertThat(configProperties.getString("endpoint")).isNull(); + assertThat(configProperties.getStructured("headers")).isNull(); + assertThat(configProperties.getString("compression")).isNull(); + assertThat(configProperties.getInt("timeout")).isNull(); + assertThat(configProperties.getString("certificate_file")).isNull(); + assertThat(configProperties.getString("client_key_file")).isNull(); + assertThat(configProperties.getString("client_certificate_file")).isNull(); + assertThat(configProperties.getString("temporality_preference")).isNull(); + assertThat(configProperties.getString("default_histogram_aggregation")).isNull(); + } + + @Test + void create_OtlpHttpConfigured(@TempDir Path tempDir) + throws CertificateEncodingException, IOException { + List closeables = new ArrayList<>(); + OtlpHttpMetricExporter expectedExporter = + OtlpHttpMetricExporter.builder() + .setEndpoint("http://example:4318/v1/metrics") + .addHeader("key1", "value1") + .addHeader("key2", "value2") + .setTimeout(Duration.ofSeconds(15)) + .setCompression("gzip") + .setAggregationTemporalitySelector(AggregationTemporalitySelector.deltaPreferred()) + .setDefaultAggregationSelector( + DefaultAggregationSelector.getDefault() + .with(InstrumentType.HISTOGRAM, Aggregation.base2ExponentialBucketHistogram())) + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + // Write certificates to temp files + String certificatePath = + createTempFileWithContent( + tempDir, "certificate.cert", serverTls.certificate().getEncoded()); + String clientKeyPath = + createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); + String clientCertificatePath = + createTempFileWithContent( + tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); + + MetricExporter exporter = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel() + .withOtlpHttp( + new OtlpHttpMetricExporterModel() + .withEndpoint("http://example:4318/v1/metrics") + .withHeaders( + Arrays.asList( + new NameStringValuePairModel() + .withName("key1") + .withValue("value1"), + new NameStringValuePairModel() + .withName("key2") + .withValue("value2"))) + .withCompression("gzip") + .withTimeout(15_000) + .withTls( + new HttpTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath)) + .withTemporalityPreference( + OtlpHttpMetricExporterModel.ExporterTemporalityPreference.DELTA) + .withDefaultHistogramAggregation( + OtlpHttpMetricExporterModel.ExporterDefaultHistogramAggregation + .BASE_2_EXPONENTIAL_BUCKET_HISTOGRAM)), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_http"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/metrics"); + List headers = configProperties.getStructuredList("headers"); + assertThat(headers) + .isNotNull() + .satisfiesExactly( + header -> { + assertThat(header.getString("name")).isEqualTo("key1"); + assertThat(header.getString("value")).isEqualTo("value1"); + }, + header -> { + assertThat(header.getString("name")).isEqualTo("key2"); + assertThat(header.getString("value")).isEqualTo("value2"); + }); + assertThat(configProperties.getString("compression")).isEqualTo("gzip"); + assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); + assertThat(configProperties.getString("temporality_preference")).isEqualTo("delta"); + assertThat(configProperties.getString("default_histogram_aggregation")) + .isEqualTo("base2_exponential_bucket_histogram"); + DeclarativeConfigProperties tls = configProperties.getStructured("tls"); + assertThat(tls).isNotNull(); + assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); + assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); + assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); + } + + @Test + void create_OtlpGrpcDefaults() { + List closeables = new ArrayList<>(); + OtlpGrpcMetricExporter expectedExporter = + OtlpGrpcMetricExporter.getDefault().toBuilder() + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + MetricExporter exporter = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel().withOtlpGrpc(new OtlpGrpcMetricExporterModel()), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_grpc"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("endpoint")).isNull(); + assertThat(configProperties.getStructured("headers")).isNull(); + assertThat(configProperties.getString("compression")).isNull(); + assertThat(configProperties.getInt("timeout")).isNull(); + assertThat(configProperties.getString("certificate_file")).isNull(); + assertThat(configProperties.getString("client_key_file")).isNull(); + assertThat(configProperties.getString("client_certificate_file")).isNull(); + assertThat(configProperties.getString("temporality_preference")).isNull(); + assertThat(configProperties.getString("default_histogram_aggregation")).isNull(); + } + + @Test + void create_OtlpGrpcConfigured(@TempDir Path tempDir) + throws CertificateEncodingException, IOException { + List closeables = new ArrayList<>(); + OtlpGrpcMetricExporter expectedExporter = + OtlpGrpcMetricExporter.builder() + .setEndpoint("http://example:4317") + .addHeader("key1", "value1") + .addHeader("key2", "value2") + .setTimeout(Duration.ofSeconds(15)) + .setCompression("gzip") + .setAggregationTemporalitySelector(AggregationTemporalitySelector.deltaPreferred()) + .setDefaultAggregationSelector( + DefaultAggregationSelector.getDefault() + .with(InstrumentType.HISTOGRAM, Aggregation.base2ExponentialBucketHistogram())) + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + // Write certificates to temp files + String certificatePath = + createTempFileWithContent( + tempDir, "certificate.cert", serverTls.certificate().getEncoded()); + String clientKeyPath = + createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); + String clientCertificatePath = + createTempFileWithContent( + tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); + + MetricExporter exporter = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel() + .withOtlpGrpc( + new OtlpGrpcMetricExporterModel() + .withEndpoint("http://example:4317") + .withHeaders( + Arrays.asList( + new NameStringValuePairModel() + .withName("key1") + .withValue("value1"), + new NameStringValuePairModel() + .withName("key2") + .withValue("value2"))) + .withCompression("gzip") + .withTimeout(15_000) + .withTls( + new GrpcTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath)) + .withTemporalityPreference( + OtlpHttpMetricExporterModel.ExporterTemporalityPreference.DELTA) + .withDefaultHistogramAggregation( + OtlpHttpMetricExporterModel.ExporterDefaultHistogramAggregation + .BASE_2_EXPONENTIAL_BUCKET_HISTOGRAM)), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_grpc"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4317"); + List headers = configProperties.getStructuredList("headers"); + assertThat(headers) + .isNotNull() + .satisfiesExactly( + header -> { + assertThat(header.getString("name")).isEqualTo("key1"); + assertThat(header.getString("value")).isEqualTo("value1"); + }, + header -> { + assertThat(header.getString("name")).isEqualTo("key2"); + assertThat(header.getString("value")).isEqualTo("value2"); + }); + assertThat(configProperties.getString("compression")).isEqualTo("gzip"); + assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); + assertThat(configProperties.getString("temporality_preference")).isEqualTo("delta"); + assertThat(configProperties.getString("default_histogram_aggregation")) + .isEqualTo("base2_exponential_bucket_histogram"); + DeclarativeConfigProperties tls = configProperties.getStructured("tls"); + assertThat(tls).isNotNull(); + assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); + assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); + assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); + } + + @Test + void create_Console() { + List closeables = new ArrayList<>(); + LoggingMetricExporter expectedExporter = LoggingMetricExporter.create(); + cleanup.addCloseable(expectedExporter); + + MetricExporter exporter = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel().withConsole(new ConsoleMetricExporterModel()), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + } + + @Test + void create_OtlpFile() { + List closeables = new ArrayList<>(); + OtlpStdoutMetricExporter expectedExporter = OtlpStdoutMetricExporter.builder().build(); + cleanup.addCloseable(expectedExporter); + + MetricExporter exporter = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel() + .withOtlpFileDevelopment(new ExperimentalOtlpFileMetricExporterModel()), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_file/development"); + assertThat(configProperties).isNotNull(); + } + + @Test + void create_SpiExporter_Unknown() { + assertThatThrownBy( + () -> + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel() + .withAdditionalProperty( + "unknown_key", + new PushMetricExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage( + "No component provider detected for io.opentelemetry.sdk.metrics.export.MetricExporter with name \"unknown_key\"."); + } + + @Test + void create_SpiExporter_Valid() { + MetricExporter metricExporter = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel() + .withAdditionalProperty( + "test", + new PushMetricExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), + context); + assertThat(metricExporter) + .isInstanceOf(MetricExporterComponentProvider.TestMetricExporter.class); + assertThat( + ((MetricExporterComponentProvider.TestMetricExporter) metricExporter) + .config.getString("key1")) + .isEqualTo("value1"); + } + + @Test + void create_Customizer() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addMetricExporterCustomizer( + MetricExporter.class, (exporter, properties) -> LoggingMetricExporter.create()); + + MetricExporter result = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel().withConsole(new ConsoleMetricExporterModel()), + context); + cleanup.addCloseable(result); + + assertThat(result).isInstanceOf(LoggingMetricExporter.class); + } + + @Test + void create_Customizer_TypeSafe() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addMetricExporterCustomizer( + OtlpGrpcMetricExporter.class, + (exporter, properties) -> + exporter.toBuilder().setTimeout(Duration.ofSeconds(42)).build()); + + MetricExporter result = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel().withOtlpGrpc(new OtlpGrpcMetricExporterModel()), + context); + cleanup.addCloseable(result); + + assertThat(result).isInstanceOf(OtlpGrpcMetricExporter.class); + assertThat(result.toString()).contains("timeoutNanos=42000000000"); + } + + @Test + void create_Customizer_TypeMismatch() { + AtomicInteger callCount = new AtomicInteger(0); + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addMetricExporterCustomizer( + OtlpGrpcMetricExporter.class, + (exporter, properties) -> { + callCount.incrementAndGet(); + return exporter; + }); + + MetricExporter result = + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel().withConsole(new ConsoleMetricExporterModel()), + context); + cleanup.addCloseable(result); + + assertThat(callCount.get()).isEqualTo(0); + } + + @Test + void create_Customizer_ReturnsNull() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addMetricExporterCustomizer(MetricExporter.class, (exporter, properties) -> null); + + assertThatThrownBy( + () -> + MetricExporterFactory.getInstance() + .create( + new PushMetricExporterModel().withConsole(new ConsoleMetricExporterModel()), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessageContaining("Customizer returned null for MetricExporter: console"); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java new file mode 100644 index 00000000000..3882003aa8d --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java @@ -0,0 +1,252 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import io.github.netmikey.logunit.api.LogCapturer; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; +import io.opentelemetry.exporter.prometheus.PrometheusHttpServer; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.CardinalityLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalPrometheusMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricReaderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.export.MetricReader; +import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; +import java.io.Closeable; +import java.io.IOException; +import java.net.ServerSocket; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class MetricReaderFactoryTest { + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + @RegisterExtension + LogCapturer logCapturer = + LogCapturer.create().captureForLogger(DeclarativeConfiguration.class.getName()); + + private final DeclarativeConfigContext context = + spy( + new DeclarativeConfigContext( + ComponentLoader.forClassLoader(getClass().getClassLoader()))); + + @BeforeEach + void setup() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @Test + void create_PeriodicNullExporter() { + assertThatThrownBy( + () -> + MetricReaderFactory.getInstance() + .create( + new MetricReaderModel().withPeriodic(new PeriodicMetricReaderModel()), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage("periodic metric reader exporter is required but is null"); + } + + @Test + void create_PeriodicDefaults() { + List closeables = new ArrayList<>(); + PeriodicMetricReader expectedReader = + PeriodicMetricReader.builder( + OtlpHttpMetricExporter.builder().setComponentLoader(context).build()) + .build(); + cleanup.addCloseable(expectedReader); + + MetricReaderAndCardinalityLimits readerAndCardinalityLimits = + MetricReaderFactory.getInstance() + .create( + new MetricReaderModel() + .withPeriodic( + new PeriodicMetricReaderModel() + .withExporter( + new PushMetricExporterModel() + .withOtlpHttp(new OtlpHttpMetricExporterModel()))), + context); + MetricReader reader = readerAndCardinalityLimits.getMetricReader(); + cleanup.addCloseable(reader); + cleanup.addCloseables(closeables); + + assertThat(reader.toString()).isEqualTo(expectedReader.toString()); + assertThat(readerAndCardinalityLimits.getCardinalityLimitsSelector()).isNull(); + } + + @Test + void create_PeriodicConfigured() { + List closeables = new ArrayList<>(); + MetricReader expectedReader = + PeriodicMetricReader.builder( + OtlpHttpMetricExporter.builder().setComponentLoader(context).build()) + .setInterval(Duration.ofMillis(1)) + .build(); + cleanup.addCloseable(expectedReader); + + MetricReaderAndCardinalityLimits readerAndCardinalityLimits = + MetricReaderFactory.getInstance() + .create( + new MetricReaderModel() + .withPeriodic( + new PeriodicMetricReaderModel() + .withExporter( + new PushMetricExporterModel() + .withOtlpHttp(new OtlpHttpMetricExporterModel())) + .withInterval(1) + .withCardinalityLimits(new CardinalityLimitsModel().withDefault(100))), + context); + MetricReader reader = readerAndCardinalityLimits.getMetricReader(); + cleanup.addCloseable(reader); + cleanup.addCloseables(closeables); + + assertThat(reader.toString()).isEqualTo(expectedReader.toString()); + assertThat( + readerAndCardinalityLimits + .getCardinalityLimitsSelector() + .getCardinalityLimit(InstrumentType.COUNTER)) + .isEqualTo(100); + } + + @Test + void create_PullPrometheusDefault() throws IOException { + int port = randomAvailablePort(); + List closeables = new ArrayList<>(); + PrometheusHttpServer expectedReader = PrometheusHttpServer.builder().setPort(port).build(); + // Close the reader to avoid port conflict with the new instance created by MetricReaderFactory + expectedReader.close(); + + MetricReaderAndCardinalityLimits readerAndCardinalityLimits = + MetricReaderFactory.getInstance() + .create( + new MetricReaderModel() + .withPull( + new PullMetricReaderModel() + .withExporter( + new PullMetricExporterModel() + .withPrometheusDevelopment( + new ExperimentalPrometheusMetricExporterModel() + .withPort(port)))), + context); + MetricReader reader = readerAndCardinalityLimits.getMetricReader(); + cleanup.addCloseable(reader); + cleanup.addCloseables(closeables); + + assertThat(reader.toString()).isEqualTo(expectedReader.toString()); + assertThat(readerAndCardinalityLimits.getCardinalityLimitsSelector()).isNull(); + // TODO(jack-berg): validate prometheus component provider was invoked with correct arguments + verify(context).loadComponent(eq(MetricReader.class), any(ConfigKeyValue.class)); + } + + @Test + void create_PullPrometheusConfigured() throws IOException { + int port = randomAvailablePort(); + + List closeables = new ArrayList<>(); + PrometheusHttpServer expectedReader = + PrometheusHttpServer.builder() + .setHost("localhost") + .setPort(port) + .setAllowedResourceAttributesFilter( + IncludeExcludePredicate.createPatternMatching( + singletonList("foo"), singletonList("bar"))) + .build(); + // Close the reader to avoid port conflict with the new instance created by MetricReaderFactory + expectedReader.close(); + + MetricReaderAndCardinalityLimits readerAndCardinalityLimits = + MetricReaderFactory.getInstance() + .create( + new MetricReaderModel() + .withPull( + new PullMetricReaderModel() + .withCardinalityLimits(new CardinalityLimitsModel().withDefault(100)) + .withExporter( + new PullMetricExporterModel() + .withPrometheusDevelopment( + new ExperimentalPrometheusMetricExporterModel() + .withHost("localhost") + .withPort(port) + .withWithResourceConstantLabels( + new IncludeExcludeModel() + .withIncluded(singletonList("foo")) + .withExcluded(singletonList("bar"))) + .withWithoutScopeInfo(false) + .withWithoutTargetInfoDevelopment(false) + .withTranslationStrategy( + ExperimentalPrometheusMetricExporterModel + .ExperimentalPrometheusTranslationStrategy + .UNDERSCORE_ESCAPING_WITHOUT_SUFFIXES_DEVELOPMENT)))), + context); + MetricReader reader = readerAndCardinalityLimits.getMetricReader(); + cleanup.addCloseable(reader); + cleanup.addCloseables(closeables); + + assertThat(reader.toString()).isEqualTo(expectedReader.toString()); + assertThat( + readerAndCardinalityLimits + .getCardinalityLimitsSelector() + .getCardinalityLimit(InstrumentType.COUNTER)) + .isEqualTo(100); + // TODO(jack-berg): validate prometheus component provider was invoked with correct arguments + verify(context).loadComponent(eq(MetricReader.class), any(ConfigKeyValue.class)); + } + + @Test + void create_InvalidPullReader() { + assertThatThrownBy( + () -> + MetricReaderFactory.getInstance() + .create(new MetricReaderModel().withPull(new PullMetricReaderModel()), context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage("pull metric reader exporter is required but is null"); + + assertThatThrownBy( + () -> + MetricReaderFactory.getInstance() + .create( + new MetricReaderModel() + .withPull( + new PullMetricReaderModel() + .withExporter(new PullMetricExporterModel())), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage("metric reader must have exactly one entry but has 0"); + } + + /** + * Find a random unused port. There's a small race if another process takes it before we + * initialize. Consider adding retries to this test if it flakes, presumably it never will on CI + * since there's no prometheus there blocking the well-known port. + */ + private static int randomAvailablePort() throws IOException { + try (ServerSocket socket2 = new ServerSocket(0)) { + return socket2.getLocalPort(); + } + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java new file mode 100644 index 00000000000..0b822a4d983 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java @@ -0,0 +1,404 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import io.github.netmikey.logunit.api.LogCapturer; +import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; +import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.extension.trace.propagation.B3Propagator; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.internal.testing.slf4j.SuppressLogger; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PropagatorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleLogRecordProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewSelectorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewStreamModel; +import io.opentelemetry.sdk.internal.ExtendedOpenTelemetrySdk; +import io.opentelemetry.sdk.internal.OpenTelemetrySdkBuilderUtil; +import io.opentelemetry.sdk.internal.SdkConfigProvider; +import io.opentelemetry.sdk.logs.LogLimits; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; +import io.opentelemetry.sdk.metrics.InstrumentSelector; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.View; +import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.SpanLimits; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import java.io.Closeable; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.slf4j.event.Level; + +class OpenTelemetryConfigurationFactoryTest { + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + @RegisterExtension + LogCapturer logCapturer = + LogCapturer.create() + .captureForLogger(OpenTelemetryConfigurationFactory.class.getName(), Level.WARN); + + private final DeclarativeConfigContext context = + new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); + + @BeforeEach + void setup() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @ParameterizedTest + @MethodSource("fileFormatArgs") + @SuppressLogger(OpenTelemetryConfigurationFactory.class) + void create_FileFormat(String fileFormat, boolean isValid) { + OpenTelemetryConfigurationModel model = + new OpenTelemetryConfigurationModel().withFileFormat(fileFormat); + + if (isValid) { + assertThatCode(() -> OpenTelemetryConfigurationFactory.getInstance().create(model, context)) + .doesNotThrowAnyException(); + } else { + assertThatThrownBy( + () -> OpenTelemetryConfigurationFactory.getInstance().create(model, context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessageMatching( + "Unsupported file format '.+'\\. Supported formats include 0\\.4, 1\\.0\\*"); + } + } + + private static Stream fileFormatArgs() { + return Stream.of( + // Invalid file formats + Arguments.of(null, false), + Arguments.of("0.3", false), + Arguments.of("a0.4", false), + Arguments.of("0.4a", false), + Arguments.of("foo", false), + Arguments.of("1.0-rc.a", false), + Arguments.of("1.0.0", false), + Arguments.of("1.0.3", false), + Arguments.of("1.0.0-rc.3", false), + // Valid file formats + Arguments.of("0.4", true), + Arguments.of("1.0-rc.1", true), + Arguments.of("1.0-rc.2", true), + Arguments.of("1.0-rc.3", true), + Arguments.of("1.0", true)); + } + + @Test + void create_FileFormatVersionMismatch_LogsWarning() { + OpenTelemetryConfigurationModel model = + new OpenTelemetryConfigurationModel().withFileFormat("1.0-rc.3"); + + ExtendedOpenTelemetrySdk sdk = + OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); + cleanup.addCloseable(sdk); + + logCapturer.assertContains( + "Configuration file_format '1.0-rc.3' does not exactly match expected version '1.0'"); + } + + @Test + void create_FileFormatExactMatch_NoWarning() { + OpenTelemetryConfigurationModel model = + new OpenTelemetryConfigurationModel().withFileFormat("1.0"); + + ExtendedOpenTelemetrySdk sdk = + OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); + cleanup.addCloseable(sdk); + + assertThat(logCapturer.size()).isEqualTo(0); + } + + @Test + void create_Defaults() { + List closeables = new ArrayList<>(); + OpenTelemetryConfigurationModel model = + new OpenTelemetryConfigurationModel().withFileFormat("1.0"); + OpenTelemetrySdk expectedSdk = + OpenTelemetrySdkBuilderUtil.setConfigProvider( + OpenTelemetrySdk.builder(), + SdkConfigProvider.create(DeclarativeConfigurationParser.toConfigProperties(model))) + .build(); + cleanup.addCloseable(expectedSdk); + + ExtendedOpenTelemetrySdk sdk = + OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); + cleanup.addCloseable(sdk); + cleanup.addCloseables(closeables); + + assertThat(sdk).hasToString(expectedSdk.toString()); + } + + @Test + void create_Disabled() { + List closeables = new ArrayList<>(); + OpenTelemetryConfigurationModel model = + new OpenTelemetryConfigurationModel() + .withFileFormat("1.0") + .withDisabled(true) + // Logger provider configuration should be ignored since SDK is disabled + .withLoggerProvider( + new LoggerProviderModel() + .withProcessors( + Collections.singletonList( + new LogRecordProcessorModel() + .withSimple( + new SimpleLogRecordProcessorModel() + .withExporter( + new LogRecordExporterModel() + .withOtlpHttp(new OtlpHttpExporterModel())))))); + OpenTelemetrySdk expectedSdk = + OpenTelemetrySdkBuilderUtil.setConfigProvider( + OpenTelemetrySdk.builder(), + SdkConfigProvider.create(DeclarativeConfigurationParser.toConfigProperties(model))) + .build(); + cleanup.addCloseable(expectedSdk); + + ExtendedOpenTelemetrySdk sdk = + OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); + cleanup.addCloseable(sdk); + cleanup.addCloseables(closeables); + + assertThat(sdk).hasToString(expectedSdk.toString()); + } + + @Test + void create_Configured() throws NoSuchFieldException { + List closeables = new ArrayList<>(); + Resource expectedResource = + Resource.getDefault().toBuilder() + .put("service.name", "my-service") + .put("key", "val") + // resource attributes from resource ComponentProviders + .put("color", "red") + .put("shape", "square") + .put("order", "second") + .build(); + + OpenTelemetryConfigurationModel model = + new OpenTelemetryConfigurationModel() + .withFileFormat("1.0") + .withPropagator( + new PropagatorModel().withCompositeList("tracecontext,baggage,b3multi,b3")) + .withResource( + new ResourceModel() + .withDetectionDevelopment( + new ExperimentalResourceDetectionModel() + .withDetectors( + Arrays.asList( + new ExperimentalResourceDetectorModel() + .withAdditionalProperty("order_first", null), + new ExperimentalResourceDetectorModel() + .withAdditionalProperty("order_second", null), + new ExperimentalResourceDetectorModel() + .withAdditionalProperty("shape_color", null)))) + .withAttributes( + Arrays.asList( + new AttributeNameValueModel() + .withName("service.name") + .withValue("my-service"), + new AttributeNameValueModel().withName("key").withValue("val")))) + .withLoggerProvider( + new LoggerProviderModel() + .withLimits( + new LogRecordLimitsModel() + .withAttributeValueLengthLimit(1) + .withAttributeCountLimit(2)) + .withProcessors( + Collections.singletonList( + new LogRecordProcessorModel() + .withBatch( + new BatchLogRecordProcessorModel() + .withExporter( + new LogRecordExporterModel() + .withOtlpHttp(new OtlpHttpExporterModel())))))) + .withTracerProvider( + new TracerProviderModel() + .withLimits( + new SpanLimitsModel() + .withAttributeCountLimit(1) + .withAttributeValueLengthLimit(2) + .withEventCountLimit(3) + .withLinkCountLimit(4) + .withEventAttributeCountLimit(5) + .withLinkAttributeCountLimit(6)) + .withSampler(new SamplerModel().withAlwaysOn(new AlwaysOnSamplerModel())) + .withProcessors( + Collections.singletonList( + new SpanProcessorModel() + .withBatch( + new BatchSpanProcessorModel() + .withExporter( + new SpanExporterModel() + .withOtlpHttp(new OtlpHttpExporterModel())))))) + .withMeterProvider( + new MeterProviderModel() + .withReaders( + Collections.singletonList( + new MetricReaderModel() + .withPeriodic( + new PeriodicMetricReaderModel() + .withExporter( + new PushMetricExporterModel() + .withOtlpHttp(new OtlpHttpMetricExporterModel()))))) + .withViews( + Collections.singletonList( + new ViewModel() + .withSelector( + new ViewSelectorModel().withInstrumentName("instrument-name")) + .withStream( + new ViewStreamModel() + .withName("stream-name") + .withAttributeKeys(null))))); + + OpenTelemetrySdk expectedSdk = + OpenTelemetrySdkBuilderUtil.setConfigProvider( + OpenTelemetrySdk.builder() + .setPropagators( + ContextPropagators.create( + TextMapPropagator.composite( + W3CTraceContextPropagator.getInstance(), + W3CBaggagePropagator.getInstance(), + B3Propagator.injectingMultiHeaders(), + B3Propagator.injectingSingleHeader()))) + .setLoggerProvider( + SdkLoggerProvider.builder() + .setResource(expectedResource) + .setLogLimits( + () -> + LogLimits.builder() + .setMaxAttributeValueLength(1) + .setMaxNumberOfAttributes(2) + .build()) + .addLogRecordProcessor( + BatchLogRecordProcessor.builder( + OtlpHttpLogRecordExporter.builder() + .setComponentLoader(context) + .build()) + .build()) + .build()) + .setTracerProvider( + SdkTracerProvider.builder() + .setResource(expectedResource) + .setSpanLimits( + SpanLimits.builder() + .setMaxNumberOfAttributes(1) + .setMaxAttributeValueLength(2) + .setMaxNumberOfEvents(3) + .setMaxNumberOfLinks(4) + .setMaxNumberOfAttributesPerEvent(5) + .setMaxNumberOfAttributesPerLink(6) + .build()) + .setSampler(alwaysOn()) + .addSpanProcessor( + BatchSpanProcessor.builder( + OtlpHttpSpanExporter.builder() + .setComponentLoader(context) + .build()) + .build()) + .build()) + .setMeterProvider( + SdkMeterProvider.builder() + .setResource(expectedResource) + .registerMetricReader( + PeriodicMetricReader.builder( + OtlpHttpMetricExporter.builder() + .setComponentLoader(context) + .build()) + .build()) + .registerView( + InstrumentSelector.builder().setName("instrument-name").build(), + View.builder().setName("stream-name").build()) + .build()), + SdkConfigProvider.create(DeclarativeConfigurationParser.toConfigProperties(model))) + .build(); + + cleanup.addCloseable(expectedSdk); + + ExtendedOpenTelemetrySdk sdk = + OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); + cleanup.addCloseable(sdk); + cleanup.addCloseables(closeables); + + assertThat(sdk).hasToString(expectedSdk.toString()); + + // test that the meter provider is wired through to the tracer and logger providers + Field field = SdkMeterProvider.class.getDeclaredField("sharedState"); + field.setAccessible(true); + + // Lazily initialized + assertThat(sdk) + .extracting("loggerProvider") + .extracting("delegate") + .extracting("sharedState") + .extracting("logRecordProcessor") + .extracting("worker") + .extracting("logProcessorInstrumentation") + .extracting("processedLogs") + .isNull(); + + // Lazily initialized + assertThat(sdk) + .extracting("tracerProvider") + .extracting("delegate") + .extracting("sharedState") + .extracting("activeSpanProcessor") + .extracting("worker") + .extracting("spanProcessorInstrumentation") + .extracting("processedSpans") + .isNull(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java new file mode 100644 index 00000000000..d3072f4aa31 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java @@ -0,0 +1,132 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.extension.trace.propagation.B3Propagator; +import io.opentelemetry.sdk.extension.incubator.fileconfig.component.TextMapPropagatorComponentProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.B3MultiPropagatorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.B3PropagatorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BaggagePropagatorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PropagatorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TextMapPropagatorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TraceContextPropagatorModel; +import java.util.Arrays; +import java.util.Collections; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class PropagatorFactoryTest { + + private final DeclarativeConfigContext context = + new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); + + @ParameterizedTest + @MethodSource("createArguments") + void create(PropagatorModel model, ContextPropagators expectedPropagators) { + ContextPropagators propagators = PropagatorFactory.getInstance().create(model, context); + + assertThat(propagators.toString()).isEqualTo(expectedPropagators.toString()); + } + + private static Stream createArguments() { + return Stream.of( + // structured list + Arguments.of( + new PropagatorModel() + .withComposite( + Arrays.asList( + new TextMapPropagatorModel() + .withTracecontext(new TraceContextPropagatorModel()), + new TextMapPropagatorModel().withBaggage(new BaggagePropagatorModel()), + new TextMapPropagatorModel().withB3multi(new B3MultiPropagatorModel()), + new TextMapPropagatorModel().withB3(new B3PropagatorModel()))), + ContextPropagators.create( + TextMapPropagator.composite( + W3CTraceContextPropagator.getInstance(), + W3CBaggagePropagator.getInstance(), + B3Propagator.injectingMultiHeaders(), + B3Propagator.injectingSingleHeader()))), + // string list + Arguments.of( + new PropagatorModel().withCompositeList("tracecontext,baggage,b3multi,b3 ,none"), + ContextPropagators.create( + TextMapPropagator.composite( + W3CTraceContextPropagator.getInstance(), + W3CBaggagePropagator.getInstance(), + B3Propagator.injectingMultiHeaders(), + B3Propagator.injectingSingleHeader()))), + // structured list and string list + Arguments.of( + new PropagatorModel() + .withComposite( + Arrays.asList( + new TextMapPropagatorModel() + .withTracecontext(new TraceContextPropagatorModel()), + new TextMapPropagatorModel().withBaggage(new BaggagePropagatorModel()))) + .withCompositeList("b3multi,b3"), + ContextPropagators.create( + TextMapPropagator.composite( + W3CTraceContextPropagator.getInstance(), + W3CBaggagePropagator.getInstance(), + B3Propagator.injectingMultiHeaders(), + B3Propagator.injectingSingleHeader()))), + // structured list and string list with overlap + Arguments.of( + new PropagatorModel() + .withComposite( + Arrays.asList( + new TextMapPropagatorModel() + .withTracecontext(new TraceContextPropagatorModel()), + new TextMapPropagatorModel().withBaggage(new BaggagePropagatorModel()))) + .withCompositeList("tracecontext,b3multi,b3"), + ContextPropagators.create( + TextMapPropagator.composite( + W3CTraceContextPropagator.getInstance(), + W3CBaggagePropagator.getInstance(), + B3Propagator.injectingMultiHeaders(), + B3Propagator.injectingSingleHeader()))), + // spi + Arguments.of( + new PropagatorModel() + .withComposite( + Collections.singletonList( + new TextMapPropagatorModel().withAdditionalProperty("test", null))), + ContextPropagators.create( + TextMapPropagator.composite( + new TextMapPropagatorComponentProvider.TestTextMapPropagator( + DeclarativeConfigProperties.empty())))), + Arguments.of( + new PropagatorModel().withCompositeList("test"), + ContextPropagators.create( + TextMapPropagator.composite( + new TextMapPropagatorComponentProvider.TestTextMapPropagator( + DeclarativeConfigProperties.empty()))))); + } + + @Test + void create_SpiPropagator_Unknown() { + assertThatThrownBy( + () -> + PropagatorFactory.getInstance() + .create(new PropagatorModel().withCompositeList("foo"), context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage( + "No component provider detected for io.opentelemetry.context.propagation.TextMapPropagator with name \"foo\"."); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java new file mode 100644 index 00000000000..58b1bd6e7f5 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java @@ -0,0 +1,196 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel; +import io.opentelemetry.sdk.resources.Resource; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import javax.annotation.Nullable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class ResourceFactoryTest { + + private final DeclarativeConfigContext context = + new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); + + @ParameterizedTest + @MethodSource("createArgs") + void create(ResourceModel model, Resource expectedResource) { + assertThat(ResourceFactory.getInstance().create(model, context)).isEqualTo(expectedResource); + } + + private static Stream createArgs() { + return Stream.of( + Arguments.of( + new ResourceModel() + .withAttributes( + Arrays.asList( + new AttributeNameValueModel() + .withName("service.name") + .withValue("my-service"), + new AttributeNameValueModel().withName("key").withValue("val"), + new AttributeNameValueModel().withName("shape").withValue("circle"))), + Resource.getDefault().toBuilder() + .put("shape", "circle") + .put("service.name", "my-service") + .put("key", "val") + .build()), + Arguments.of( + new ResourceModel().withSchemaUrl("http://foo"), + Resource.getDefault().toBuilder().setSchemaUrl("http://foo").build()), + Arguments.of( + new ResourceModel().withAttributesList("key1=val1,key2=val2"), + Resource.getDefault().toBuilder().put("key1", "val1").put("key2", "val2").build())); + } + + @ParameterizedTest + @MethodSource("createWithDetectorsArgs") + void createWithDetectors( + @Nullable List included, @Nullable List excluded, Resource expectedResource) { + ResourceModel resourceModel = + new ResourceModel() + .withDetectionDevelopment( + new ExperimentalResourceDetectionModel() + .withDetectors( + Arrays.asList( + new ExperimentalResourceDetectorModel() + .withAdditionalProperty("order_first", null), + new ExperimentalResourceDetectorModel() + .withAdditionalProperty("order_second", null), + new ExperimentalResourceDetectorModel() + .withAdditionalProperty("shape_color", null))) + .withAttributes( + new IncludeExcludeModel().withIncluded(included).withExcluded(excluded))); + Resource resource = ResourceFactory.getInstance().create(resourceModel, context); + assertThat(resource).isEqualTo(expectedResource); + } + + private static Stream createWithDetectorsArgs() { + return Stream.of( + Arguments.of( + null, + null, + Resource.getDefault().toBuilder() + .put("color", "red") + .put("shape", "square") + .put("order", "second") + .build()), + Arguments.of( + Collections.singletonList("color"), + null, + Resource.getDefault().toBuilder().put("color", "red").build()), + Arguments.of( + Arrays.asList("color", "shape"), + null, + Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build()), + Arguments.of( + null, + Collections.singletonList("color"), + Resource.getDefault().toBuilder() + .put("shape", "square") + .put("order", "second") + .build()), + Arguments.of( + null, + Arrays.asList("color", "shape"), + Resource.getDefault().toBuilder().put("order", "second").build()), + Arguments.of( + Collections.singletonList("color"), + Collections.singletonList("color"), + Resource.getDefault().toBuilder().build()), + Arguments.of( + Arrays.asList("color", "shape"), + Collections.singletonList("color"), + Resource.getDefault().toBuilder().put("shape", "square").build()), + Arguments.of( + Collections.singletonList("c*"), + null, + Resource.getDefault().toBuilder().put("color", "red").build()), + Arguments.of( + Collections.singletonList("c?lor"), + null, + Resource.getDefault().toBuilder().put("color", "red").build()), + Arguments.of( + null, + Collections.singletonList("c*"), + Resource.getDefault().toBuilder() + .put("shape", "square") + .put("order", "second") + .build()), + Arguments.of( + null, + Collections.singletonList("c?lor"), + Resource.getDefault().toBuilder() + .put("shape", "square") + .put("order", "second") + .build()), + Arguments.of( + Collections.singletonList("*o*"), + Collections.singletonList("order"), + Resource.getDefault().toBuilder().put("color", "red").build()), + // empty or missing include should be treated as include all + Arguments.of( + Collections.emptyList(), + Collections.singletonList("order"), + Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build()), + Arguments.of( + null, + Collections.singletonList("order"), + Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build())); + } + + @ParameterizedTest + @MethodSource("createInvalidDetectorsArgs") + void createWithDetectors_Invalid(ResourceModel model, String expectedMessage) { + assertThatThrownBy(() -> ResourceFactory.getInstance().create(model, context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage(expectedMessage); + } + + private static Stream createInvalidDetectorsArgs() { + return Stream.of( + Arguments.of( + new ResourceModel() + .withDetectionDevelopment( + new ExperimentalResourceDetectionModel() + .withDetectors( + Collections.singletonList( + new ExperimentalResourceDetectorModel() + .withAdditionalProperty("foo", null)))), + "No component provider detected for io.opentelemetry.sdk.resources.Resource with name \"foo\"."), + Arguments.of( + new ResourceModel() + .withDetectionDevelopment( + new ExperimentalResourceDetectionModel() + .withDetectors( + Collections.singletonList( + new ExperimentalResourceDetectorModel() + .withAdditionalProperty("foo", null) + .withAdditionalProperty("bar", null)))), + "resource detector must have exactly one entry but has 2: [foo,bar]"), + Arguments.of( + new ResourceModel() + .withDetectionDevelopment( + new ExperimentalResourceDetectionModel() + .withDetectors( + Collections.singletonList(new ExperimentalResourceDetectorModel()))), + "resource detector must have exactly one entry but has 0")); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java new file mode 100644 index 00000000000..52775f1abe4 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java @@ -0,0 +1,236 @@ +/* + * 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.assertThatThrownBy; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.internal.testing.slf4j.SuppressLogger; +import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SamplerComponentProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOffSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableAlwaysOffSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableAlwaysOnSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableParentThresholdSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableProbabilitySamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalJaegerRemoteSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ParentBasedSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerPropertyModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TraceIdRatioBasedSamplerModel; +import io.opentelemetry.sdk.extension.incubator.trace.samplers.ComposableSampler; +import io.opentelemetry.sdk.extension.incubator.trace.samplers.CompositeSampler; +import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler; +import io.opentelemetry.sdk.trace.samplers.ParentBasedSamplerBuilder; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import java.io.Closeable; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import javax.annotation.Nullable; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +// Suppress logs from JaegerRemoteSampler +@SuppressLogger( + loggerName = "io.opentelemetry.sdk.extension.trace.jaeger.sampler.OkHttpGrpcService") +@SuppressLogger(ParentBasedSamplerBuilder.class) +@SuppressLogger(JaegerRemoteSampler.class) +class SamplerFactoryTest { + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + private final DeclarativeConfigContext context = + new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); + + @ParameterizedTest + @MethodSource("createArguments") + void create(@Nullable SamplerModel model, Sampler expectedSampler) { + // Some samplers like JaegerRemoteSampler are Closeable - ensure these get cleaned up + if (expectedSampler instanceof Closeable) { + cleanup.addCloseable((Closeable) expectedSampler); + } + + List closeables = new ArrayList<>(); + Sampler sampler = SamplerFactory.getInstance().create(model, context); + cleanup.addCloseables(closeables); + + assertThat(sampler.toString()).isEqualTo(expectedSampler.toString()); + } + + private static Stream createArguments() { + return Stream.of( + Arguments.of( + new SamplerModel().withAlwaysOn(new AlwaysOnSamplerModel()), Sampler.alwaysOn()), + Arguments.of( + new SamplerModel().withAlwaysOff(new AlwaysOffSamplerModel()), Sampler.alwaysOff()), + Arguments.of( + new SamplerModel().withTraceIdRatioBased(new TraceIdRatioBasedSamplerModel()), + Sampler.traceIdRatioBased(1.0d)), + Arguments.of( + new SamplerModel() + .withTraceIdRatioBased(new TraceIdRatioBasedSamplerModel().withRatio(0.5d)), + Sampler.traceIdRatioBased(0.5)), + Arguments.of( + new SamplerModel().withParentBased(new ParentBasedSamplerModel()), + Sampler.parentBased(Sampler.alwaysOn())), + Arguments.of( + new SamplerModel() + .withParentBased( + new ParentBasedSamplerModel() + .withRoot( + new SamplerModel() + .withTraceIdRatioBased( + new TraceIdRatioBasedSamplerModel().withRatio(0.1d))) + .withRemoteParentSampled( + new SamplerModel() + .withTraceIdRatioBased( + new TraceIdRatioBasedSamplerModel().withRatio(0.2d))) + .withRemoteParentNotSampled( + new SamplerModel() + .withTraceIdRatioBased( + new TraceIdRatioBasedSamplerModel().withRatio(0.3d))) + .withLocalParentSampled( + new SamplerModel() + .withTraceIdRatioBased( + new TraceIdRatioBasedSamplerModel().withRatio(0.4d))) + .withLocalParentNotSampled( + new SamplerModel() + .withTraceIdRatioBased( + new TraceIdRatioBasedSamplerModel().withRatio(0.5d)))), + Sampler.parentBasedBuilder(Sampler.traceIdRatioBased(0.1d)) + .setRemoteParentSampled(Sampler.traceIdRatioBased(0.2d)) + .setRemoteParentNotSampled(Sampler.traceIdRatioBased(0.3d)) + .setLocalParentSampled(Sampler.traceIdRatioBased(0.4d)) + .setLocalParentNotSampled(Sampler.traceIdRatioBased(0.5d)) + .build()), + Arguments.of( + new SamplerModel() + .withJaegerRemoteDevelopment( + new ExperimentalJaegerRemoteSamplerModel() + .withEndpoint("http://jaeger-remote-endpoint") + .withInterval(10_000) + .withInitialSampler( + new SamplerModel().withAlwaysOff(new AlwaysOffSamplerModel()))), + JaegerRemoteSampler.builder() + .setEndpoint("http://jaeger-remote-endpoint") + .setPollingInterval(Duration.ofSeconds(10)) + .setInitialSampler(Sampler.alwaysOff()) + .build()), + Arguments.of( + new SamplerModel() + .withCompositeDevelopment( + new ExperimentalComposableSamplerModel() + .withAlwaysOn(new ExperimentalComposableAlwaysOnSamplerModel())), + CompositeSampler.wrap(ComposableSampler.alwaysOn())), + Arguments.of( + new SamplerModel() + .withCompositeDevelopment( + new ExperimentalComposableSamplerModel() + .withAlwaysOff(new ExperimentalComposableAlwaysOffSamplerModel())), + CompositeSampler.wrap(ComposableSampler.alwaysOff())), + Arguments.of( + new SamplerModel() + .withCompositeDevelopment( + new ExperimentalComposableSamplerModel() + .withProbability( + new ExperimentalComposableProbabilitySamplerModel().withRatio(0.5))), + CompositeSampler.wrap(ComposableSampler.probability(0.5))), + Arguments.of( + new SamplerModel() + .withCompositeDevelopment( + new ExperimentalComposableSamplerModel() + .withRuleBased(new ExperimentalComposableRuleBasedSamplerModel())), + CompositeSampler.wrap(ComposableSampler.ruleBasedBuilder().build())), + Arguments.of( + new SamplerModel() + .withCompositeDevelopment( + new ExperimentalComposableSamplerModel() + .withParentThreshold( + new ExperimentalComposableParentThresholdSamplerModel() + .withRoot( + new ExperimentalComposableSamplerModel() + .withAlwaysOn( + new ExperimentalComposableAlwaysOnSamplerModel())))), + CompositeSampler.wrap( + ComposableSampler.parentThreshold(ComposableSampler.alwaysOn())))); + } + + @ParameterizedTest + @MethodSource("createInvalidArguments") + void createInvalid(SamplerModel model, String expectedMessage) { + assertThatThrownBy(() -> SamplerFactory.getInstance().create(model, context)) + .isInstanceOf(DeclarativeConfigException.class) + .extracting(throwable -> throwable.getCause() == null ? throwable : throwable.getCause()) + .extracting(Throwable::getMessage) + .isEqualTo(expectedMessage); + } + + private static Stream createInvalidArguments() { + return Stream.of( + Arguments.of( + new SamplerModel() + .withJaegerRemoteDevelopment(new ExperimentalJaegerRemoteSamplerModel()), + "jaeger remote sampler endpoint is required"), + Arguments.of( + new SamplerModel() + .withJaegerRemoteDevelopment( + new ExperimentalJaegerRemoteSamplerModel() + .withEndpoint("http://jaeger-remote-endpoint")), + "jaeger remote sampler initial_sampler is required"), + Arguments.of( + new SamplerModel() + .withCompositeDevelopment( + new ExperimentalComposableSamplerModel() + .withParentThreshold( + new ExperimentalComposableParentThresholdSamplerModel())), + "parent threshold sampler root is required but is null")); + } + + @Test + void create_SpiExporter_Unknown() { + List closeables = new ArrayList<>(); + + assertThatThrownBy( + () -> + SamplerFactory.getInstance() + .create( + new SamplerModel() + .withAdditionalProperty( + "unknown_key", + new SamplerPropertyModel() + .withAdditionalProperty("key1", "value1")), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage( + "No component provider detected for io.opentelemetry.sdk.trace.samplers.Sampler with name \"unknown_key\"."); + cleanup.addCloseables(closeables); + } + + @Test + void create_SpiExporter_Valid() { + Sampler sampler = + SamplerFactory.getInstance() + .create( + new SamplerModel() + .withAdditionalProperty( + "test", + new SamplerPropertyModel().withAdditionalProperty("key1", "value1")), + context); + assertThat(sampler).isInstanceOf(SamplerComponentProvider.TestSampler.class); + assertThat(((SamplerComponentProvider.TestSampler) sampler).config.getString("key1")) + .isEqualTo("value1"); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java new file mode 100644 index 00000000000..4778fe1b614 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java @@ -0,0 +1,64 @@ +/* + * 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.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.resources.Resource; +import java.util.Objects; +import java.util.UUID; +import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.ClearSystemProperty; + +class ServiceResourceDetectorTest { + + @Test + void getTypeAndName() { + ServiceResourceDetector detector = new ServiceResourceDetector(); + + assertThat(detector.getType()).isEqualTo(Resource.class); + assertThat(detector.getName()).isEqualTo("service"); + } + + @Test + @ClearSystemProperty(key = "otel.service.name") + void create_SystemPropertySet() { + System.setProperty("otel.service.name", "test"); + + assertThat(new ServiceResourceDetector().create(DeclarativeConfigProperties.empty())) + .satisfies( + resource -> { + Attributes attributes = resource.getAttributes(); + assertThat(attributes.get(AttributeKey.stringKey("service.name"))).isEqualTo("test"); + assertThatCode( + () -> + UUID.fromString( + Objects.requireNonNull( + attributes.get(AttributeKey.stringKey("service.instance.id"))))) + .doesNotThrowAnyException(); + }); + } + + @Test + void create_NoSystemProperty() { + assertThat(new ServiceResourceDetector().create(DeclarativeConfigProperties.empty())) + .satisfies( + resource -> { + Attributes attributes = resource.getAttributes(); + assertThat(attributes.get(AttributeKey.stringKey("service.name"))).isNull(); + assertThatCode( + () -> + UUID.fromString( + Objects.requireNonNull( + attributes.get(AttributeKey.stringKey("service.instance.id"))))) + .doesNotThrowAnyException(); + }); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java new file mode 100644 index 00000000000..906ced22056 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java @@ -0,0 +1,437 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.exporter.logging.LoggingSpanExporter; +import io.opentelemetry.exporter.logging.otlp.internal.traces.OtlpStdoutSpanExporter; +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanExporterComponentProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalOtlpFileExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.GrpcTlsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HttpTlsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpGrpcExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterPropertyModel; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.io.Closeable; +import java.io.IOException; +import java.nio.file.Path; +import java.security.cert.CertificateEncodingException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.io.TempDir; + +class SpanExporterFactoryTest { + + @RegisterExtension + static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension(); + + @RegisterExtension + static final SelfSignedCertificateExtension clientTls = new SelfSignedCertificateExtension(); + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + private CapturingComponentLoader capturingComponentLoader; + private DeclarativeConfigContext context; + + @BeforeEach + void setup() { + capturingComponentLoader = new CapturingComponentLoader(); + context = new DeclarativeConfigContext(capturingComponentLoader); + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @Test + void create_OtlpHttpDefaults() { + List closeables = new ArrayList<>(); + OtlpHttpSpanExporter expectedExporter = + OtlpHttpSpanExporter.getDefault().toBuilder() + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + SpanExporter exporter = + SpanExporterFactory.getInstance() + .create(new SpanExporterModel().withOtlpHttp(new OtlpHttpExporterModel()), context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_http"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("protocol")).isNull(); + assertThat(configProperties.getString("endpoint")).isNull(); + assertThat(configProperties.getStructured("headers")).isNull(); + assertThat(configProperties.getString("compression")).isNull(); + assertThat(configProperties.getInt("timeout")).isNull(); + assertThat(configProperties.getString("certificate_file")).isNull(); + assertThat(configProperties.getString("client_key_file")).isNull(); + assertThat(configProperties.getString("client_certificate_file")).isNull(); + } + + @Test + void create_OtlpHttpConfigured(@TempDir Path tempDir) + throws CertificateEncodingException, IOException { + List closeables = new ArrayList<>(); + OtlpHttpSpanExporter expectedExporter = + OtlpHttpSpanExporter.builder() + .setEndpoint("http://example:4318/v1/traces") + .addHeader("key1", "value1") + .addHeader("key2", "value2") + .setTimeout(Duration.ofSeconds(15)) + .setCompression("gzip") + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + // Write certificates to temp files + String certificatePath = + createTempFileWithContent( + tempDir, "certificate.cert", serverTls.certificate().getEncoded()); + String clientKeyPath = + createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); + String clientCertificatePath = + createTempFileWithContent( + tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); + + SpanExporter exporter = + SpanExporterFactory.getInstance() + .create( + new SpanExporterModel() + .withOtlpHttp( + new OtlpHttpExporterModel() + .withEndpoint("http://example:4318/v1/traces") + .withHeaders( + Arrays.asList( + new NameStringValuePairModel() + .withName("key1") + .withValue("value1"), + new NameStringValuePairModel() + .withName("key2") + .withValue("value2"))) + .withCompression("gzip") + .withTimeout(15_000) + .withTls( + new HttpTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath))), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_http"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/traces"); + List headers = configProperties.getStructuredList("headers"); + assertThat(headers) + .isNotNull() + .satisfiesExactly( + header -> { + assertThat(header.getString("name")).isEqualTo("key1"); + assertThat(header.getString("value")).isEqualTo("value1"); + }, + header -> { + assertThat(header.getString("name")).isEqualTo("key2"); + assertThat(header.getString("value")).isEqualTo("value2"); + }); + assertThat(configProperties.getString("compression")).isEqualTo("gzip"); + assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); + DeclarativeConfigProperties tls = configProperties.getStructured("tls"); + assertThat(tls).isNotNull(); + assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); + assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); + assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); + } + + @Test + void create_OtlpGrpcDefaults() { + List closeables = new ArrayList<>(); + OtlpGrpcSpanExporter expectedExporter = + OtlpGrpcSpanExporter.getDefault().toBuilder() + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + SpanExporter exporter = + SpanExporterFactory.getInstance() + .create(new SpanExporterModel().withOtlpGrpc(new OtlpGrpcExporterModel()), context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_grpc"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("endpoint")).isNull(); + assertThat(configProperties.getStructured("headers")).isNull(); + assertThat(configProperties.getString("compression")).isNull(); + assertThat(configProperties.getInt("timeout")).isNull(); + assertThat(configProperties.getString("certificate_file")).isNull(); + assertThat(configProperties.getString("client_key_file")).isNull(); + assertThat(configProperties.getString("client_certificate_file")).isNull(); + } + + @Test + void create_OtlpGrpcConfigured(@TempDir Path tempDir) + throws CertificateEncodingException, IOException { + List closeables = new ArrayList<>(); + OtlpGrpcSpanExporter expectedExporter = + OtlpGrpcSpanExporter.builder() + .setEndpoint("http://example:4317") + .addHeader("key1", "value1") + .addHeader("key2", "value2") + .setTimeout(Duration.ofSeconds(15)) + .setCompression("gzip") + .setComponentLoader(context) // needed for the toString() check to pass + .build(); + cleanup.addCloseable(expectedExporter); + + // Write certificates to temp files + String certificatePath = + createTempFileWithContent( + tempDir, "certificate.cert", serverTls.certificate().getEncoded()); + String clientKeyPath = + createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); + String clientCertificatePath = + createTempFileWithContent( + tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); + + SpanExporter exporter = + SpanExporterFactory.getInstance() + .create( + new SpanExporterModel() + .withOtlpGrpc( + new OtlpGrpcExporterModel() + .withEndpoint("http://example:4317") + .withHeaders( + Arrays.asList( + new NameStringValuePairModel() + .withName("key1") + .withValue("value1"), + new NameStringValuePairModel() + .withName("key2") + .withValue("value2"))) + .withCompression("gzip") + .withTimeout(15_000) + .withTls( + new GrpcTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath))), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_grpc"); + assertThat(configProperties).isNotNull(); + assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4317"); + List headers = configProperties.getStructuredList("headers"); + assertThat(headers) + .isNotNull() + .satisfiesExactly( + header -> { + assertThat(header.getString("name")).isEqualTo("key1"); + assertThat(header.getString("value")).isEqualTo("value1"); + }, + header -> { + assertThat(header.getString("name")).isEqualTo("key2"); + assertThat(header.getString("value")).isEqualTo("value2"); + }); + assertThat(configProperties.getString("compression")).isEqualTo("gzip"); + assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); + DeclarativeConfigProperties tls = configProperties.getStructured("tls"); + assertThat(tls).isNotNull(); + assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); + assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); + assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); + } + + @Test + void create_Console() { + List closeables = new ArrayList<>(); + LoggingSpanExporter expectedExporter = LoggingSpanExporter.create(); + cleanup.addCloseable(expectedExporter); + + SpanExporter exporter = + SpanExporterFactory.getInstance() + .create(new SpanExporterModel().withConsole(new ConsoleExporterModel()), context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + } + + @Test + void create_OtlpFile() { + List closeables = new ArrayList<>(); + OtlpStdoutSpanExporter expectedExporter = OtlpStdoutSpanExporter.builder().build(); + cleanup.addCloseable(expectedExporter); + + SpanExporter exporter = + SpanExporterFactory.getInstance() + .create( + new SpanExporterModel() + .withOtlpFileDevelopment(new ExperimentalOtlpFileExporterModel()), + context); + cleanup.addCloseable(exporter); + cleanup.addCloseables(closeables); + + assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); + + // Verify the configuration passed to the component provider + DeclarativeConfigProperties configProperties = + capturingComponentLoader.getCapturedConfig("otlp_file/development"); + assertThat(configProperties).isNotNull(); + } + + @Test + void create_SpiExporter_Unknown() { + List closeables = new ArrayList<>(); + + assertThatThrownBy( + () -> + SpanExporterFactory.getInstance() + .create( + new SpanExporterModel() + .withAdditionalProperty( + "unknown_key", + new SpanExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage( + "No component provider detected for io.opentelemetry.sdk.trace.export.SpanExporter with name \"unknown_key\"."); + cleanup.addCloseables(closeables); + } + + @Test + void create_SpiExporter_Valid() { + SpanExporter spanExporter = + SpanExporterFactory.getInstance() + .create( + new SpanExporterModel() + .withAdditionalProperty( + "test", + new SpanExporterPropertyModel().withAdditionalProperty("key1", "value1")), + context); + assertThat(spanExporter).isInstanceOf(SpanExporterComponentProvider.TestSpanExporter.class); + assertThat( + ((SpanExporterComponentProvider.TestSpanExporter) spanExporter) + .config.getString("key1")) + .isEqualTo("value1"); + } + + @Test + void create_Customizer() { + // Generic customizer applied to all span exporters + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addSpanExporterCustomizer( + SpanExporter.class, + (exporter, properties) -> + SpanExporter.composite(exporter, LoggingSpanExporter.create())); + + SpanExporter result = + SpanExporterFactory.getInstance() + .create(new SpanExporterModel().withConsole(new ConsoleExporterModel()), context); + cleanup.addCloseable(result); + + // Result should be wrapped in composite + assertThat(result.toString()).contains("LoggingSpanExporter"); + } + + @Test + void create_Customizer_TypeSafe() { + // Customizer for specific type gets type-safe access to exporter builder methods + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addSpanExporterCustomizer( + OtlpGrpcSpanExporter.class, + (exporter, properties) -> + exporter.toBuilder().setTimeout(Duration.ofSeconds(42)).build()); + + SpanExporter result = + SpanExporterFactory.getInstance() + .create(new SpanExporterModel().withOtlpGrpc(new OtlpGrpcExporterModel()), context); + cleanup.addCloseable(result); + + assertThat(result).isInstanceOf(OtlpGrpcSpanExporter.class); + assertThat(result.toString()).contains("timeoutNanos=42000000000"); + } + + @Test + void create_Customizer_TypeMismatch() { + // Customizer registered for OtlpGrpcSpanExporter should NOT be called for other types + AtomicInteger callCount = new AtomicInteger(0); + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addSpanExporterCustomizer( + OtlpGrpcSpanExporter.class, + (exporter, properties) -> { + callCount.incrementAndGet(); + return exporter; + }); + + SpanExporter result = + SpanExporterFactory.getInstance() + .create(new SpanExporterModel().withConsole(new ConsoleExporterModel()), context); + cleanup.addCloseable(result); + + // Customizer should not have been called since types don't match + assertThat(callCount.get()).isEqualTo(0); + } + + @Test + void create_Customizer_ReturnsNull() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + context + .getBuilder() + .addSpanExporterCustomizer(SpanExporter.class, (exporter, properties) -> null); + + assertThatThrownBy( + () -> + SpanExporterFactory.getInstance() + .create( + new SpanExporterModel().withConsole(new ConsoleExporterModel()), context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessageContaining("Customizer returned null for SpanExporter: console"); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java new file mode 100644 index 00000000000..cfbec8b16eb --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java @@ -0,0 +1,62 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.mockito.Mockito.mock; + +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanLimitsModel; +import io.opentelemetry.sdk.trace.SpanLimits; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class SpanLimitsFactoryTest { + + @ParameterizedTest + @MethodSource("createArguments") + void create(SpanLimitsAndAttributeLimits model, SpanLimits expectedSpanLimits) { + assertThat(SpanLimitsFactory.getInstance().create(model, mock(DeclarativeConfigContext.class))) + .isEqualTo(expectedSpanLimits); + } + + private static Stream createArguments() { + return Stream.of( + Arguments.of(SpanLimitsAndAttributeLimits.create(null, null), SpanLimits.getDefault()), + Arguments.of( + SpanLimitsAndAttributeLimits.create(new AttributeLimitsModel(), new SpanLimitsModel()), + SpanLimits.getDefault()), + Arguments.of( + SpanLimitsAndAttributeLimits.create( + new AttributeLimitsModel() + .withAttributeCountLimit(1) + .withAttributeValueLengthLimit(2), + new SpanLimitsModel()), + SpanLimits.builder().setMaxNumberOfAttributes(1).setMaxAttributeValueLength(2).build()), + Arguments.of( + SpanLimitsAndAttributeLimits.create( + new AttributeLimitsModel() + .withAttributeCountLimit(1) + .withAttributeValueLengthLimit(2), + new SpanLimitsModel() + .withAttributeCountLimit(3) + .withAttributeValueLengthLimit(4) + .withEventCountLimit(5) + .withLinkCountLimit(6) + .withEventAttributeCountLimit(7) + .withLinkAttributeCountLimit(8)), + SpanLimits.builder() + .setMaxNumberOfAttributes(3) + .setMaxAttributeValueLength(4) + .setMaxNumberOfEvents(5) + .setMaxNumberOfLinks(6) + .setMaxNumberOfAttributesPerEvent(7) + .setMaxNumberOfAttributesPerLink(8) + .build())); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java new file mode 100644 index 00000000000..f56aedf746f --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java @@ -0,0 +1,180 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanProcessorComponentProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleSpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorPropertyModel; +import io.opentelemetry.sdk.trace.SpanProcessor; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import java.io.Closeable; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class SpanProcessorFactoryTest { + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + private static final DeclarativeConfigContext context = + new DeclarativeConfigContext( + ComponentLoader.forClassLoader(SpanProcessorFactoryTest.class.getClassLoader())); + + @BeforeEach + void setup() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @Test + void create_BatchNullExporter() { + assertThatThrownBy( + () -> + SpanProcessorFactory.getInstance() + .create( + new SpanProcessorModel().withBatch(new BatchSpanProcessorModel()), context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage("batch span processor exporter is required but is null"); + } + + @Test + void create_BatchDefaults() { + List closeables = new ArrayList<>(); + BatchSpanProcessor expectedProcessor = + BatchSpanProcessor.builder( + OtlpHttpSpanExporter.builder().setComponentLoader(context).build()) + .build(); + cleanup.addCloseable(expectedProcessor); + + SpanProcessor processor = + SpanProcessorFactory.getInstance() + .create( + new SpanProcessorModel() + .withBatch( + new BatchSpanProcessorModel() + .withExporter( + new SpanExporterModel().withOtlpHttp(new OtlpHttpExporterModel()))), + context); + cleanup.addCloseable(processor); + cleanup.addCloseables(closeables); + + assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); + } + + @Test + void create_BatchConfigured() { + List closeables = new ArrayList<>(); + BatchSpanProcessor expectedProcessor = + BatchSpanProcessor.builder( + OtlpHttpSpanExporter.builder().setComponentLoader(context).build()) + .setScheduleDelay(Duration.ofMillis(1)) + .setMaxExportBatchSize(2) + .setExporterTimeout(Duration.ofMillis(3)) + .build(); + cleanup.addCloseable(expectedProcessor); + + SpanProcessor processor = + SpanProcessorFactory.getInstance() + .create( + new SpanProcessorModel() + .withBatch( + new BatchSpanProcessorModel() + .withExporter( + new SpanExporterModel().withOtlpHttp(new OtlpHttpExporterModel())) + .withScheduleDelay(1) + .withMaxExportBatchSize(2) + .withExportTimeout(3)), + context); + cleanup.addCloseable(processor); + cleanup.addCloseables(closeables); + + assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); + } + + @Test + void create_SimpleNullExporter() { + assertThatThrownBy( + () -> + SpanProcessorFactory.getInstance() + .create( + new SpanProcessorModel().withSimple(new SimpleSpanProcessorModel()), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage("simple span processor exporter is required but is null"); + } + + @Test + void create_SimpleConfigured() { + List closeables = new ArrayList<>(); + SpanProcessor expectedProcessor = + SimpleSpanProcessor.create( + OtlpHttpSpanExporter.builder().setComponentLoader(context).build()); + cleanup.addCloseable(expectedProcessor); + + SpanProcessor processor = + SpanProcessorFactory.getInstance() + .create( + new SpanProcessorModel() + .withSimple( + new SimpleSpanProcessorModel() + .withExporter( + new SpanExporterModel().withOtlpHttp(new OtlpHttpExporterModel()))), + context); + cleanup.addCloseable(processor); + cleanup.addCloseables(closeables); + + assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); + } + + @Test + void create_SpiProcessor_Unknown() { + assertThatThrownBy( + () -> + SpanProcessorFactory.getInstance() + .create( + new SpanProcessorModel() + .withAdditionalProperty( + "unknown_key", + new SpanProcessorPropertyModel() + .withAdditionalProperty("key1", "value1")), + context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage( + "No component provider detected for io.opentelemetry.sdk.trace.SpanProcessor with name \"unknown_key\"."); + } + + @Test + void create_SpiExporter_Valid() { + SpanProcessor spanProcessor = + SpanProcessorFactory.getInstance() + .create( + new SpanProcessorModel() + .withAdditionalProperty( + "test", + new SpanProcessorPropertyModel().withAdditionalProperty("key1", "value1")), + context); + assertThat(spanProcessor).isInstanceOf(SpanProcessorComponentProvider.TestSpanProcessor.class); + Assertions.assertThat( + ((SpanProcessorComponentProvider.TestSpanProcessor) spanProcessor) + .config.getString("key1")) + .isEqualTo("value1"); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java new file mode 100644 index 00000000000..ac80fa388da --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel; +import java.util.ArrayList; +import java.util.List; + +public class TestDeclarativeConfigurationCustomizerProvider + implements DeclarativeConfigurationCustomizerProvider { + + @Override + public void customize(DeclarativeConfigurationCustomizer customizer) { + customizer.addModelCustomizer( + model -> { + ResourceModel resource = model.getResource(); + if (resource == null) { + resource = new ResourceModel(); + model.withResource(resource); + } + List attributes = resource.getAttributes(); + if (attributes == null) { + attributes = new ArrayList<>(); + resource.withAttributes(attributes); + } + attributes.add( + new AttributeNameValueModel() + .withName("foo") + .withType(AttributeNameValueModel.AttributeType.STRING) + .withValue("bar")); + attributes.add( + new AttributeNameValueModel() + .withName("color") + .withType(AttributeNameValueModel.AttributeType.STRING) + .withValue("blue")); + return model; + }); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java new file mode 100644 index 00000000000..b2610d678b9 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java @@ -0,0 +1,141 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn; + +import io.opentelemetry.common.ComponentLoader; +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.internal.testing.CleanupExtension; +import io.opentelemetry.sdk.common.internal.ScopeConfigurator; +import io.opentelemetry.sdk.common.internal.ScopeConfiguratorBuilder; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalTracerConfigModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalTracerConfiguratorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalTracerMatcherAndConfigModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanLimitsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; +import io.opentelemetry.sdk.trace.SpanLimits; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.sdk.trace.internal.SdkTracerProviderUtil; +import io.opentelemetry.sdk.trace.internal.TracerConfig; +import java.io.Closeable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class TracerProviderFactoryTest { + + @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); + + private static final DeclarativeConfigContext context = + new DeclarativeConfigContext( + ComponentLoader.forClassLoader(TracerProviderFactoryTest.class.getClassLoader())); + + @BeforeEach + void setup() { + context.setBuilder(new DeclarativeConfigurationBuilder()); + } + + @ParameterizedTest + @MethodSource("createArguments") + void create(TracerProviderAndAttributeLimits model, SdkTracerProvider expectedProvider) { + List closeables = new ArrayList<>(); + cleanup.addCloseable(expectedProvider); + + SdkTracerProvider provider = TracerProviderFactory.getInstance().create(model, context).build(); + cleanup.addCloseable(provider); + cleanup.addCloseables(closeables); + + assertThat(provider.toString()).isEqualTo(expectedProvider.toString()); + } + + private static Stream createArguments() { + return Stream.of( + Arguments.of( + TracerProviderAndAttributeLimits.create(null, null), + SdkTracerProvider.builder().build()), + Arguments.of( + TracerProviderAndAttributeLimits.create( + new AttributeLimitsModel(), new TracerProviderModel()), + SdkTracerProvider.builder().build()), + Arguments.of( + TracerProviderAndAttributeLimits.create( + new AttributeLimitsModel(), + new TracerProviderModel() + .withLimits( + new SpanLimitsModel() + .withAttributeCountLimit(1) + .withAttributeValueLengthLimit(2) + .withEventCountLimit(3) + .withLinkCountLimit(4) + .withEventAttributeCountLimit(5) + .withLinkAttributeCountLimit(6)) + .withSampler(new SamplerModel().withAlwaysOn(new AlwaysOnSamplerModel())) + .withProcessors( + Collections.singletonList( + new SpanProcessorModel() + .withBatch( + new BatchSpanProcessorModel() + .withExporter( + new SpanExporterModel() + .withOtlpHttp(new OtlpHttpExporterModel()))))) + .withTracerConfiguratorDevelopment( + new ExperimentalTracerConfiguratorModel() + .withDefaultConfig( + new ExperimentalTracerConfigModel().withEnabled(false)) + .withTracers( + Collections.singletonList( + new ExperimentalTracerMatcherAndConfigModel() + .withName("foo") + .withConfig( + new ExperimentalTracerConfigModel() + .withEnabled(true)))))), + addTracerConfigurator( + SdkTracerProvider.builder(), + ScopeConfigurator.builder() + .setDefault(TracerConfig.disabled()) + .addCondition( + ScopeConfiguratorBuilder.nameMatchesGlob("foo"), TracerConfig.enabled()) + .build()) + .setSpanLimits( + SpanLimits.builder() + .setMaxNumberOfAttributes(1) + .setMaxAttributeValueLength(2) + .setMaxNumberOfEvents(3) + .setMaxNumberOfLinks(4) + .setMaxNumberOfAttributesPerEvent(5) + .setMaxNumberOfAttributesPerLink(6) + .build()) + .setSampler(alwaysOn()) + .addSpanProcessor( + BatchSpanProcessor.builder( + OtlpHttpSpanExporter.builder().setComponentLoader(context).build()) + .build()) + .build())); + } + + private static SdkTracerProviderBuilder addTracerConfigurator( + SdkTracerProviderBuilder builder, ScopeConfigurator tracerConfigurator) { + SdkTracerProviderUtil.setTracerConfigurator(builder, tracerConfigurator); + return builder; + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java new file mode 100644 index 00000000000..1911c8fbbac --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java @@ -0,0 +1,73 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static org.mockito.Mockito.mock; + +import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AggregationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExplicitBucketHistogramAggregationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewStreamModel; +import io.opentelemetry.sdk.metrics.Aggregation; +import io.opentelemetry.sdk.metrics.ExplicitBucketHistogramOptions; +import io.opentelemetry.sdk.metrics.View; +import java.util.Arrays; +import java.util.Collections; +import org.junit.jupiter.api.Test; + +class ViewFactoryTest { + + @Test + void create_Defaults() { + View expectedView = View.builder().build(); + + View view = + ViewFactory.getInstance() + .create( + new ViewStreamModel().withAttributeKeys(null), + mock(DeclarativeConfigContext.class)); + + assertThat(view.toString()).isEqualTo(expectedView.toString()); + } + + @Test + void create() { + View expectedView = + View.builder() + .setName("name") + .setDescription("description") + .setAttributeFilter( + IncludeExcludePredicate.createExactMatching( + Arrays.asList("foo", "bar"), Collections.singletonList("baz"))) + .setAggregation( + Aggregation.explicitBucketHistogram( + ExplicitBucketHistogramOptions.builder() + .setBucketBoundaries(Arrays.asList(1.0, 2.0)) + .build())) + .build(); + + View view = + ViewFactory.getInstance() + .create( + new ViewStreamModel() + .withName("name") + .withDescription("description") + .withAttributeKeys( + new IncludeExcludeModel() + .withIncluded(Arrays.asList("foo", "bar")) + .withExcluded(Collections.singletonList("baz"))) + .withAggregation( + new AggregationModel() + .withExplicitBucketHistogram( + new ExplicitBucketHistogramAggregationModel() + .withBoundaries(Arrays.asList(1.0, 2.0)))), + mock(DeclarativeConfigContext.class)); + + assertThat(view.toString()).isEqualTo(expectedView.toString()); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java new file mode 100644 index 00000000000..c22835f2b5a --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java @@ -0,0 +1,300 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig; + +import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.common.collect.ImmutableSet; +import io.github.netmikey.logunit.api.LogCapturer; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.internal.testing.slf4j.SuppressLogger; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +@SuppressLogger(YamlDeclarativeConfigProperties.class) +class YamlDeclarativeConfigPropertiesTest { + + @RegisterExtension + LogCapturer logs = LogCapturer.create().captureForType(YamlDeclarativeConfigProperties.class); + + private static final String extendedSchema = + "file_format: \"1.0\"\n" + + "disabled: false\n" + + "\n" + + "resource:\n" + + " attributes:\n" + + " - name: service.name\n" + + " value: \"unknown_service\"\n" + + "\n" + + "other:\n" + + " str_key: str_value\n" + + " int_key: 1\n" + + " float_key: 1.1\n" + + " bool_key: true\n" + + " null_key:\n" + + " str_list_key: [val1, val2]\n" + + " int_list_key: [1, 2]\n" + + " float_list_key: [1.1, 2.2]\n" + + " bool_list_key: [true, false]\n" + + " mixed_list_key: [val1, 1, 1.1, true]\n" + + " map_key:\n" + + " str_key1: str_value1\n" + + " int_key1: 2\n" + + " map_key1:\n" + + " str_key2: str_value2\n" + + " int_key2: 3\n" + + " list_key:\n" + + " - str_key1: str_value1\n" + + " int_key1: 2\n" + + " map_key1:\n" + + " str_key2: str_value2\n" + + " int_key2: 3\n" + + " - str_key1: str_value1\n" + + " int_key1: 2"; + + private DeclarativeConfigProperties structuredConfigProps; + + @BeforeEach + void setup() { + OpenTelemetryConfigurationModel configuration = + DeclarativeConfigurationParser.parse( + new ByteArrayInputStream(extendedSchema.getBytes(StandardCharsets.UTF_8))); + structuredConfigProps = DeclarativeConfigurationParser.toConfigProperties(configuration); + } + + @Test + void configurationSchema() { + // Validate can read declarative configuration schema properties + assertThat(structuredConfigProps.getString("file_format")).isEqualTo("1.0"); + DeclarativeConfigProperties resourceProps = structuredConfigProps.getStructured("resource"); + assertThat(resourceProps).isNotNull(); + List resourceAttributesList = + resourceProps.getStructuredList("attributes"); + assertThat(resourceAttributesList) + .isNotNull() + .satisfiesExactly( + attributeEntry -> { + assertThat(attributeEntry.getString("name")).isEqualTo("service.name"); + assertThat(attributeEntry.getString("value")).isEqualTo("unknown_service"); + }); + } + + @Test + void additionalProperties() { + assertThat(structuredConfigProps.getPropertyKeys()) + .isEqualTo(ImmutableSet.of("file_format", "disabled", "resource", "other")); + + // Validate can read properties not part of configuration schema + // .other + DeclarativeConfigProperties otherProps = structuredConfigProps.getStructured("other"); + assertThat(otherProps).isNotNull(); + assertThat(otherProps.getPropertyKeys()) + .isEqualTo( + ImmutableSet.of( + "str_key", + "int_key", + "float_key", + "bool_key", + "null_key", + "str_list_key", + "int_list_key", + "float_list_key", + "bool_list_key", + "mixed_list_key", + "map_key", + "list_key")); + assertThat(otherProps.getString("str_key")).isEqualTo("str_value"); + assertThat(otherProps.getInt("int_key")).isEqualTo(1); + assertThat(otherProps.getLong("int_key")).isEqualTo(1); + assertThat(otherProps.getDouble("float_key")).isEqualTo(1.1); + assertThat(otherProps.getString("null_key")).isNull(); + assertThat(otherProps.getInt("null_key")).isNull(); + assertThat(otherProps.getLong("null_key")).isNull(); + assertThat(otherProps.getBoolean("null_key")).isNull(); + assertThat(otherProps.getScalarList("str_list_key", String.class)) + .isEqualTo(Arrays.asList("val1", "val2")); + assertThat(otherProps.getScalarList("int_list_key", Long.class)) + .isEqualTo(Arrays.asList(1L, 2L)); + assertThat(otherProps.getScalarList("float_list_key", Double.class)) + .isEqualTo(Arrays.asList(1.1d, 2.2d)); + assertThat(otherProps.getScalarList("bool_list_key", Boolean.class)) + .isEqualTo(Arrays.asList(true, false)); + // If reading a scalar list which is mixed, entries which are not aligned with + // the requested + // type are filtered out + assertThat(otherProps.getScalarList("mixed_list_key", String.class)) + .isEqualTo(Collections.singletonList("val1")); + assertThat(otherProps.getScalarList("mixed_list_key", Long.class)) + .isEqualTo(Collections.singletonList(1L)); + assertThat(otherProps.getScalarList("mixed_list_key", Double.class)) + .isEqualTo(Collections.singletonList(1.1d)); + assertThat(otherProps.getScalarList("mixed_list_key", Boolean.class)) + .isEqualTo(Collections.singletonList(true)); + + // .other.map_key + DeclarativeConfigProperties otherMapKeyProps = otherProps.getStructured("map_key"); + assertThat(otherMapKeyProps).isNotNull(); + assertThat(otherMapKeyProps.getPropertyKeys()) + .isEqualTo(ImmutableSet.of("str_key1", "int_key1", "map_key1")); + assertThat(otherMapKeyProps.getString("str_key1")).isEqualTo("str_value1"); + assertThat(otherMapKeyProps.getInt("int_key1")).isEqualTo(2); + // other.map_key.map_key1 + DeclarativeConfigProperties otherMapKeyMapKey1Props = + otherMapKeyProps.getStructured("map_key1"); + assertThat(otherMapKeyMapKey1Props).isNotNull(); + assertThat(otherMapKeyMapKey1Props.getPropertyKeys()) + .isEqualTo(ImmutableSet.of("str_key2", "int_key2")); + assertThat(otherMapKeyMapKey1Props.getString("str_key2")).isEqualTo("str_value2"); + assertThat(otherMapKeyMapKey1Props.getInt("int_key2")).isEqualTo(3); + + // .other.list_key + List listKey = otherProps.getStructuredList("list_key"); + assertThat(listKey).hasSize(2); + DeclarativeConfigProperties listKeyProps1 = listKey.get(0); + assertThat(listKeyProps1.getPropertyKeys()) + .isEqualTo(ImmutableSet.of("str_key1", "int_key1", "map_key1")); + assertThat(listKeyProps1.getString("str_key1")).isEqualTo("str_value1"); + assertThat(listKeyProps1.getInt("int_key1")).isEqualTo(2); + // .other.list_key[0] + DeclarativeConfigProperties listKeyProps1MapKeyProps = listKeyProps1.getStructured("map_key1"); + assertThat(listKeyProps1MapKeyProps).isNotNull(); + assertThat(listKeyProps1MapKeyProps.getPropertyKeys()) + .isEqualTo(ImmutableSet.of("str_key2", "int_key2")); + assertThat(listKeyProps1MapKeyProps.getString("str_key2")).isEqualTo("str_value2"); + assertThat(listKeyProps1MapKeyProps.getInt("int_key2")).isEqualTo(3); + // .other.list_key[1] + DeclarativeConfigProperties listKeyProps2 = listKey.get(1); + assertThat(listKeyProps2.getPropertyKeys()).isEqualTo(ImmutableSet.of("str_key1", "int_key1")); + assertThat(listKeyProps2.getString("str_key1")).isEqualTo("str_value1"); + assertThat(listKeyProps2.getInt("int_key1")).isEqualTo(2); + } + + @Test + void treeWalking() { + // Validate common pattern of walking down tree path which is not defined + // Access string at .foo.bar.baz without null checking and without exception. + assertThat( + structuredConfigProps + .get("foo") // short for getStructured("foo", empty()) + .getStructured("bar", empty()) + .getString("baz")) + .isNull(); + } + + @Test + void defaults() { + assertThat(structuredConfigProps.getString("foo", "bar")).isEqualTo("bar"); + assertThat(structuredConfigProps.getInt("foo", 1)).isEqualTo(1); + assertThat(structuredConfigProps.getLong("foo", 1)).isEqualTo(1); + assertThat(structuredConfigProps.getDouble("foo", 1.1)).isEqualTo(1.1); + assertThat(structuredConfigProps.getBoolean("foo", true)).isTrue(); + assertThat( + structuredConfigProps.getScalarList( + "foo", String.class, Collections.singletonList("bar"))) + .isEqualTo(Collections.singletonList("bar")); + assertThat(structuredConfigProps.getStructured("foo", empty())).isEqualTo(empty()); + assertThat(structuredConfigProps.getStructuredList("foo", Collections.emptyList())) + .isEqualTo(Collections.emptyList()); + } + + @Test + void missingKeys() { + assertThat(structuredConfigProps.getString("foo")).isNull(); + assertThat(structuredConfigProps.getInt("foo")).isNull(); + assertThat(structuredConfigProps.getLong("foo")).isNull(); + assertThat(structuredConfigProps.getDouble("foo")).isNull(); + assertThat(structuredConfigProps.getBoolean("foo")).isNull(); + assertThat(structuredConfigProps.getScalarList("foo", String.class)).isNull(); + assertThat(structuredConfigProps.getStructured("foo")).isNull(); + assertThat(structuredConfigProps.getStructuredList("foo")).isNull(); + } + + @Test + void wrongType() { + DeclarativeConfigProperties otherProps = structuredConfigProps.getStructured("other"); + assertThat(otherProps).isNotNull(); + + assertThat(otherProps.getString("int_key")).isNull(); + assertThat(otherProps.getInt("str_key")).isNull(); + assertThat(otherProps.getLong("str_key")).isNull(); + assertThat(otherProps.getDouble("str_key")).isNull(); + assertThat(otherProps.getBoolean("str_key")).isNull(); + assertThat(otherProps.getScalarList("str_key", String.class)).isNull(); + assertThat(otherProps.getScalarList("str_list_key", Long.class)).isNull(); + assertThat(otherProps.getScalarList("str_list_key", Boolean.class)).isNull(); + assertThat(otherProps.getScalarList("str_list_key", Double.class)).isNull(); + assertThat(otherProps.getStructured("str_key")).isNull(); + assertThat(otherProps.getStructuredList("str_key")).isNull(); + assertThat(otherProps.getStructured("str_list_key")).isNull(); + assertThat(otherProps.getStructuredList("map_key")).isNull(); + + assertWarning("Ignoring value for key [int_key] because it is Integer instead of String: 1"); + assertWarning( + "Ignoring value for key [str_key] because it is String instead of Long: str_value"); + assertWarning( + "Ignoring value for key [str_key] because it is String instead of Double: str_value"); + assertWarning( + "Ignoring value for key [str_key] because it is String instead of Boolean: str_value"); + assertWarning( + "Ignoring value for key [str_list_key] because it is String instead of Long: val1"); + } + + @Test + void wrongTypeWithDefault() { + DeclarativeConfigProperties otherProps = structuredConfigProps.getStructured("other"); + assertThat(otherProps).isNotNull(); + + assertThat(otherProps.getString("int_key", "default")).isEqualTo("default"); + assertThat(otherProps.getInt("str_key", 100)).isEqualTo(100); + assertThat(otherProps.getLong("str_key", 100L)).isEqualTo(100L); + assertThat(otherProps.getDouble("str_key", 1.1)).isEqualTo(1.1); + assertThat(otherProps.getBoolean("str_key", true)).isTrue(); + assertThat( + otherProps.getScalarList("str_key", String.class, Collections.singletonList("default"))) + .isEqualTo(Collections.singletonList("default")); + assertThat(otherProps.getStructured("str_key", empty())).isEqualTo(empty()); + assertThat(otherProps.getStructuredList("str_key", Collections.emptyList())) + .isEqualTo(Collections.emptyList()); + } + + private void assertWarning(String message) { + logs.assertContains( + e -> + String.format(e.getMessage().replaceAll("\\{\\d}", "%s"), e.getArgumentArray()) + .contains(message), + message); + } + + @Test + void emptyProperties() { + assertThat(empty().getString("foo")).isNull(); + assertThat(empty().getInt("foo")).isNull(); + assertThat(empty().getLong("foo")).isNull(); + assertThat(empty().getDouble("foo")).isNull(); + assertThat(empty().getBoolean("foo")).isNull(); + assertThat(empty().getScalarList("foo", String.class)).isNull(); + assertThat(empty().getStructured("foo")).isNull(); + assertThat(empty().getStructuredList("foo")).isNull(); + assertThat(empty().getString("foo", "bar")).isEqualTo("bar"); + assertThat(empty().getInt("foo", 1)).isEqualTo(1); + assertThat(empty().getLong("foo", 1)).isEqualTo(1); + assertThat(empty().getDouble("foo", 1.1)).isEqualTo(1.1); + assertThat(empty().getBoolean("foo", true)).isTrue(); + assertThat(empty().getScalarList("foo", String.class, Collections.singletonList("bar"))) + .isEqualTo(Collections.singletonList("bar")); + assertThat(empty().getStructured("foo", empty())).isEqualTo(empty()); + assertThat(empty().getStructuredList("foo", Collections.emptyList())) + .isEqualTo(Collections.emptyList()); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java new file mode 100644 index 00000000000..8c56339f578 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; + +// TODO(jack-berg): This allows DeclarativeConfigurationCreateTest to pass with kitchen-sink.yaml +// example. Delete after resource providers from opentelemetry-java-instrumentation are renamed to +// reflect declarative config naming +public class ContainerResourceProvider implements ComponentProvider { + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + return "container"; + } + + @Override + public Resource create(DeclarativeConfigProperties config) { + return Resource.empty(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java new file mode 100644 index 00000000000..7bff673457d --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; + +// TODO(jack-berg): This allows DeclarativeConfigurationCreateTest to pass with kitchen-sink.yaml +// example. Delete after resource providers from opentelemetry-java-instrumentation are renamed to +// reflect declarative config naming +public class HostResourceProvider implements ComponentProvider { + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + return "host"; + } + + @Override + public Resource create(DeclarativeConfigProperties config) { + return Resource.empty(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java new file mode 100644 index 00000000000..cae58c59540 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import java.util.Collection; + +public class LogRecordExporterComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return LogRecordExporter.class; + } + + @Override + public String getName() { + return "test"; + } + + @Override + public LogRecordExporter create(DeclarativeConfigProperties config) { + return new TestLogRecordExporter(config); + } + + public static class TestLogRecordExporter implements LogRecordExporter { + + public final DeclarativeConfigProperties config; + + private TestLogRecordExporter(DeclarativeConfigProperties config) { + this.config = config; + } + + @Override + public CompletableResultCode export(Collection logs) { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java new file mode 100644 index 00000000000..28724787319 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java @@ -0,0 +1,47 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.logs.LogRecordProcessor; +import io.opentelemetry.sdk.logs.ReadWriteLogRecord; + +public class LogRecordProcessorComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return LogRecordProcessor.class; + } + + @Override + public String getName() { + return "test"; + } + + @Override + public LogRecordProcessor create(DeclarativeConfigProperties config) { + return new TestLogRecordProcessor(config); + } + + public static class TestLogRecordProcessor implements LogRecordProcessor { + + public final DeclarativeConfigProperties config; + + private TestLogRecordProcessor(DeclarativeConfigProperties config) { + this.config = config; + } + + @Override + public void onEmit(Context context, ReadWriteLogRecord logRecord) {} + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java new file mode 100644 index 00000000000..f0860d2fd48 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java @@ -0,0 +1,63 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.metrics.InstrumentType; +import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import java.util.Collection; + +public class MetricExporterComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return MetricExporter.class; + } + + @Override + public String getName() { + return "test"; + } + + @Override + public MetricExporter create(DeclarativeConfigProperties config) { + return new TestMetricExporter(config); + } + + public static class TestMetricExporter implements MetricExporter { + + public final DeclarativeConfigProperties config; + + private TestMetricExporter(DeclarativeConfigProperties config) { + this.config = config; + } + + @Override + public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { + return AggregationTemporalitySelector.alwaysCumulative() + .getAggregationTemporality(instrumentType); + } + + @Override + public CompletableResultCode export(Collection metrics) { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java new file mode 100644 index 00000000000..a8a6801dca6 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; + +// TODO(jack-berg): This allows DeclarativeConfigurationCreateTest to pass with kitchen-sink.yaml +// example. Delete after resource providers from opentelemetry-java-instrumentation are renamed to +// reflect declarative config naming +public class OsResourceProvider implements ComponentProvider { + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + return "os"; + } + + @Override + public Resource create(DeclarativeConfigProperties config) { + return Resource.empty(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java new file mode 100644 index 00000000000..87718b791ba --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; + +// TODO(jack-berg): This allows DeclarativeConfigurationCreateTest to pass with kitchen-sink.yaml +// example. Delete after resource providers from opentelemetry-java-instrumentation are renamed to +// reflect declarative config naming +public class ProcessResourceProvider implements ComponentProvider { + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + return "process"; + } + + @Override + public Resource create(DeclarativeConfigProperties config) { + return Resource.empty(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java new file mode 100644 index 00000000000..f15d1919917 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; + +public class ResourceComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + return "shape_color"; + } + + @Override + public Resource create(DeclarativeConfigProperties config) { + return Resource.builder().put("shape", "square").put("color", "red").build(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java new file mode 100644 index 00000000000..565dc1c4f96 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; + +public class ResourceFirstComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + return "order_first"; + } + + @Override + public Resource create(DeclarativeConfigProperties config) { + return Resource.builder().put("order", "first").build(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java new file mode 100644 index 00000000000..f512e1e354f --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.resources.Resource; + +public class ResourceSecondComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return Resource.class; + } + + @Override + public String getName() { + return "order_second"; + } + + @Override + public Resource create(DeclarativeConfigProperties config) { + return Resource.builder().put("order", "second").build(); + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java new file mode 100644 index 00000000000..e48a4a0ceab --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java @@ -0,0 +1,58 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.trace.data.LinkData; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import io.opentelemetry.sdk.trace.samplers.SamplingResult; +import java.util.List; + +public class SamplerComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return Sampler.class; + } + + @Override + public String getName() { + return "test"; + } + + @Override + public Sampler create(DeclarativeConfigProperties config) { + return new TestSampler(config); + } + + public static class TestSampler implements Sampler { + + public final DeclarativeConfigProperties config; + + private TestSampler(DeclarativeConfigProperties config) { + this.config = config; + } + + @Override + public SamplingResult shouldSample( + Context parentContext, + String traceId, + String name, + SpanKind spanKind, + Attributes attributes, + List parentLinks) { + return SamplingResult.recordOnly(); + } + + @Override + public String getDescription() { + return "test"; + } + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java new file mode 100644 index 00000000000..f1068a082b8 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java @@ -0,0 +1,54 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.util.Collection; + +public class SpanExporterComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return SpanExporter.class; + } + + @Override + public String getName() { + return "test"; + } + + @Override + public SpanExporter create(DeclarativeConfigProperties config) { + return new TestSpanExporter(config); + } + + public static class TestSpanExporter implements SpanExporter { + + public final DeclarativeConfigProperties config; + + private TestSpanExporter(DeclarativeConfigProperties config) { + this.config = config; + } + + @Override + public CompletableResultCode export(Collection spans) { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode flush() { + return CompletableResultCode.ofSuccess(); + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java new file mode 100644 index 00000000000..b42a4795ef6 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java @@ -0,0 +1,61 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.context.Context; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.common.CompletableResultCode; +import io.opentelemetry.sdk.trace.ReadWriteSpan; +import io.opentelemetry.sdk.trace.ReadableSpan; +import io.opentelemetry.sdk.trace.SpanProcessor; + +public class SpanProcessorComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return SpanProcessor.class; + } + + @Override + public String getName() { + return "test"; + } + + @Override + public SpanProcessor create(DeclarativeConfigProperties config) { + return new TestSpanProcessor(config); + } + + public static class TestSpanProcessor implements SpanProcessor { + + public final DeclarativeConfigProperties config; + + private TestSpanProcessor(DeclarativeConfigProperties config) { + this.config = config; + } + + @Override + public void onStart(Context parentContext, ReadWriteSpan span) {} + + @Override + public boolean isStartRequired() { + return true; + } + + @Override + public void onEnd(ReadableSpan span) {} + + @Override + public boolean isEndRequired() { + return true; + } + + @Override + public CompletableResultCode shutdown() { + return CompletableResultCode.ofSuccess(); + } + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java new file mode 100644 index 00000000000..e87c64feec1 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java @@ -0,0 +1,60 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.component; + +import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.TextMapGetter; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.context.propagation.TextMapSetter; +import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import java.util.Collection; +import java.util.Collections; +import javax.annotation.Nullable; + +public class TextMapPropagatorComponentProvider implements ComponentProvider { + @Override + public Class getType() { + return TextMapPropagator.class; + } + + @Override + public String getName() { + return "test"; + } + + @Override + public TextMapPropagator create(DeclarativeConfigProperties config) { + return new TestTextMapPropagator(config); + } + + public static class TestTextMapPropagator implements TextMapPropagator { + + public final DeclarativeConfigProperties config; + + public TestTextMapPropagator(DeclarativeConfigProperties config) { + this.config = config; + } + + @Override + public Collection fields() { + return Collections.emptyList(); + } + + @Override + public void inject(Context context, @Nullable C carrier, TextMapSetter setter) {} + + @Override + public Context extract(Context context, @Nullable C carrier, TextMapGetter getter) { + return context; + } + + @Override + public String toString() { + return "TestTextMapPropagator{}"; + } + } +} diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider new file mode 100644 index 00000000000..da5f7288070 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider @@ -0,0 +1,14 @@ +io.opentelemetry.sdk.extension.incubator.fileconfig.component.MetricExporterComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanExporterComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordExporterComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.TextMapPropagatorComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.SamplerComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanProcessorComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordProcessorComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.ResourceComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.ResourceFirstComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.ResourceSecondComponentProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.ContainerResourceProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.HostResourceProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.OsResourceProvider +io.opentelemetry.sdk.extension.incubator.fileconfig.component.ProcessResourceProvider diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider new file mode 100644 index 00000000000..f60ca4e082e --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider @@ -0,0 +1 @@ +io.opentelemetry.sdk.extension.incubator.fileconfig.TestDeclarativeConfigurationCustomizerProvider diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/aggregation-args.yaml b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/aggregation-args.yaml new file mode 100644 index 00000000000..9ddf21b5c8d --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/aggregation-args.yaml @@ -0,0 +1,21 @@ +- selector: + instrument_type: HISTOGRAM + view: + aggregation: explicit_bucket_histogram + aggregation_args: + bucket_boundaries: [1.0, 2.0, 5.0] +- selector: + instrument_type: HISTOGRAM + view: + aggregation: explicit_bucket_histogram + aggregation_args: + bucket_boundaries: + - 1.0 + - 2.0 + - 5.0 +- selector: + instrument_type: HISTOGRAM + view: + aggregation: exponential_bucket_histogram + aggregation_args: + max_buckets: 20 diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/empty-selector-config.yaml b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/empty-selector-config.yaml new file mode 100644 index 00000000000..657a53c0f87 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/empty-selector-config.yaml @@ -0,0 +1,5 @@ +- selector: + view: + name: name1 + description: description1 + aggregation: sum diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/empty-view-config.yaml b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/empty-view-config.yaml new file mode 100644 index 00000000000..7b27e1e26a9 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/empty-view-config.yaml @@ -0,0 +1,8 @@ +- selector: + instrument_name: name1 + instrument_type: COUNTER + instrument_unit: ms + meter_name: meterName1 + meter_version: 1.0.0 + meter_schema_url: http://example1.com + view: diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/full-config.yaml b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/full-config.yaml new file mode 100644 index 00000000000..bf968c7e1d6 --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/full-config.yaml @@ -0,0 +1,28 @@ +- selector: + instrument_name: name1 + instrument_type: COUNTER + instrument_unit: ms + meter_name: meterName1 + meter_version: 1.0.0 + meter_schema_url: http://example1.com + view: + name: name1 + description: description1 + aggregation: sum + attribute_keys: + - foo + - bar +- selector: + instrument_name: name2 + instrument_type: COUNTER + instrument_unit: s + meter_name: meterName2 + meter_version: 2.0.0 + meter_schema_url: http://example2.com + view: + name: name2 + description: description2 + aggregation: last_value + attribute_keys: + - baz + - qux diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/view-config-customizer-test.yaml b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/view-config-customizer-test.yaml new file mode 100644 index 00000000000..afa6514b62b --- /dev/null +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/resources/view-config-customizer-test.yaml @@ -0,0 +1,6 @@ +- selector: + instrument_type: OBSERVABLE_COUNTER + view: + attribute_keys: + - foo + - bar \ No newline at end of file diff --git a/sdk-extensions/incubator/build.gradle.kts b/sdk-extensions/incubator/build.gradle.kts index df122d6aa36..9728e3ee1a0 100644 --- a/sdk-extensions/incubator/build.gradle.kts +++ b/sdk-extensions/incubator/build.gradle.kts @@ -1,14 +1,8 @@ -import de.undercouch.gradle.tasks.download.Download -import java.io.FileFilter - plugins { id("otel.java-conventions") id("otel.publish-conventions") id("otel.animalsniffer-conventions") - - id("de.undercouch.download") - id("org.jsonschema2pojo") } // SDK modules that are still being developed. @@ -27,233 +21,11 @@ dependencies { // io.opentelemetry.sdk.extension.incubator.fileconfig api(project(":api:incubator")) - compileOnly("com.fasterxml.jackson.core:jackson-databind") - api("com.fasterxml.jackson.core:jackson-annotations") - - testImplementation("org.snakeyaml:snakeyaml-engine") - testImplementation("com.fasterxml.jackson.core:jackson-databind") testImplementation(project(":sdk:testing")) - testImplementation(project(":sdk-extensions:autoconfigure")) - testImplementation(project(":exporters:logging")) - testImplementation(project(":exporters:logging-otlp")) - testImplementation(project(":exporters:otlp:all")) - testImplementation(project(":exporters:prometheus")) - testImplementation(project(":sdk-extensions:jaeger-remote-sampler")) - testImplementation(project(":extensions:trace-propagators")) testImplementation("edu.berkeley.cs.jqf:jqf-fuzz") - testImplementation("io.opentelemetry.contrib:opentelemetry-aws-xray-propagator") - testImplementation("com.linecorp.armeria:armeria-junit5") testImplementation("com.google.guava:guava-testlib") -} - -// The following tasks download the JSON Schema files from open-telemetry/opentelemetry-configuration and generate classes from the type definitions which are used with jackson-databind to parse JSON / YAML to the configuration schema. -// The sequence of tasks is: -// 1. downloadConfigurationSchema - download configuration schema from open-telemetry/opentelemetry-configuration -// 2. unzipConfigurationSchema - unzip the configuration schema archive contents to $buildDir/configuration/ -// 3. generateJsonSchema2Pojo - generate java POJOs from the configuration schema -// 4. jsonSchema2PojoPostProcessing - perform various post processing on the generated POJOs, e.g. replace javax.annotation.processing.Generated with javax.annotation.Generated, add @SuppressWarning("rawtypes") annotation -// 5. overwriteJs2p - overwrite original generated classes with versions containing updated @Generated annotation -// 6. deleteJs2pTmp - delete tmp directory -// ... proceed with normal sourcesJar, compileJava, etc - -val configurationTag = "1.0.0" -val configurationRef = "refs/tags/v$configurationTag" // Replace with commit SHA to point to experiment with a specific commit -val configurationRepoZip = "https://github.com/open-telemetry/opentelemetry-configuration/archive/$configurationRef.zip" -val buildDirectory = layout.buildDirectory.asFile.get() - -val downloadConfigurationSchema by tasks.registering(Download::class) { - src(configurationRepoZip) - // The version is encoded in the filename so that a configurationTag change results in a new - // path that doesn't yet exist, triggering a fresh download. On subsequent builds with the same - // tag the file already exists and overwrite(false) skips the network request. Note: the - // de.undercouch Download task always reports itself as not up-to-date, so overwrite(false) is - // the intended mechanism for avoiding redundant downloads. - // - // The zip is stored in tmp/ so it is outside the Sync task's output directory (configuration/). - dest("$buildDirectory/tmp/opentelemetry-configuration-v$configurationTag.zip") - overwrite(false) -} - -val unzipConfigurationSchema by tasks.registering(Sync::class) { - // Sync (not Copy) removes stale files from the destination when the source changes, ensuring - // files deleted or renamed between schema versions don't linger in the build dir. - dependsOn(downloadConfigurationSchema) - - from(zipTree(downloadConfigurationSchema.get().dest)) - eachFile(closureOf { - // Remove the top level folder "/opentelemetry-configuration-$configurationRef" - val pathParts = path.split("/") - path = pathParts.subList(1, pathParts.size).joinToString("/") - }) - into("$buildDirectory/configuration/") - includeEmptyDirs = false -} - -jsonSchema2Pojo { - sourceFiles = setOf(file("$buildDirectory/configuration/opentelemetry_configuration.json")) - targetDirectory = file("$buildDirectory/generated/sources/js2p/java/main") - targetPackage = "io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model" - - // Clear old source files to avoid contaminated source dir when updating - removeOldOutput = true - - // Include @Nullable annotation. Note: jsonSchmea2Pojo will not add @Nullable annotations on getters - // so we perform some steps in jsonSchema2PojoPostProcessing to add these. - includeJsr305Annotations = true - - // Prefer builders to setters - includeSetters = false - generateBuilders = true - - // Use title field to generate class name, instead of default which is based on filename / propertynames - useTitleAsClassname = true - - // Force java 9+ @Generated annotation, since java 8 @Generated annotation isn't detected by - // jsonSchema2Pojo and annotation is skipped altogether - targetVersion = "1.9" - - // Append Model as suffix to the generated classes. - classNameSuffix = "Model" -} - -val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo") -generateJsonSchema2Pojo.dependsOn(unzipConfigurationSchema) - -val jsonSchema2PojoPostProcessing by tasks.registering(Copy::class) { - dependsOn(generateJsonSchema2Pojo) - - from("$buildDirectory/generated/sources/js2p") - into("$buildDirectory/generated/sources/js2p-tmp") - filter { - it - // Remove @Nullable annotation so it can be deterministically added later - .replace("import javax.annotation.Nullable;\n", "") - // Replace java 9+ @Generated annotation with java 8 version, add @Nullable annotation - .replace("import javax.annotation.processing.Generated;", "import javax.annotation.Nullable;\nimport javax.annotation.Generated;") - // Add @SuppressWarnings("rawtypes") annotation to address raw types used in jsonschema2pojo builders - .replace("@Generated(\"jsonschema2pojo\")", "@Generated(\"jsonschema2pojo\")\n@SuppressWarnings(\"rawtypes\")") - // Add @Nullable annotations to all getters - .replace("( *)public ([a-zA-Z]*) get([a-zA-Z]*)".toRegex(), "$1@Nullable\n$1public $2 get$3") - } -} -val overwriteJs2p by tasks.registering(Copy::class) { - dependsOn(jsonSchema2PojoPostProcessing) - - from("$buildDirectory/generated/sources/js2p-tmp") - into("$buildDirectory/generated/sources/js2p") -} -val deleteJs2pTmp by tasks.registering(Delete::class) { - dependsOn(overwriteJs2p) - - delete("$buildDirectory/generated/sources/js2p-tmp/") -} - -// Copies EnvironmentResource.java from the autoconfigure module into a generated source set so -// that the incubator can use the exact same source without taking a runtime dependency on -// autoconfigure and without the risk of divergence from manual syncing. -val generatedResourceConfigDir = - layout.buildDirectory.dir("generated/sources/resource-configuration/java/main") -val copyResourceConfiguration by tasks.registering(Copy::class) { - from( - project(":sdk-extensions:autoconfigure").file( - "src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java" - ) - ) - into(generatedResourceConfigDir.map { it.dir("io/opentelemetry/extension/incubator/fileconfig") }) - // Only the package declaration needs rewriting; everything else is copied verbatim. - filter { line: String -> - line.replace( - "package io.opentelemetry.sdk.autoconfigure;", - "package io.opentelemetry.sdk.extension.incubator.fileconfig;" - ) - } -} - -sourceSets { - main { - java { - srcDir(generatedResourceConfigDir) - } - } -} - -val buildGraalVmReflectionJson = tasks.register("buildGraalVmReflectionJson") { - val buildDir = buildDirectory - val targetFile = File( - buildDir, - "resources/main/META-INF/native-image/io.opentelemetry/io.opentelemetry.sdk.extension.incubator/reflect-config.json" - ) - val sourcePackage = - "io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model" - val sourcePackagePath = sourcePackage.replace(".", "/") - val classesDir = - File( - buildDir, - "classes/java/main/$sourcePackagePath" - ) - - inputs.dir(classesDir) - outputs.file(targetFile) - - onlyIf { !targetFile.exists() } - - dependsOn("compileJava") - - doLast { - println("Generating GraalVM reflection config at: ${targetFile.absolutePath}") - - val classes = mutableListOf() - classesDir.walkTopDown().filter { it.isFile && it.extension == "class" }.forEach { file -> - val relativePath = file.toRelativeString(classesDir) - val className = relativePath - .removeSuffix(".class") - .replace(File.separatorChar, '.') - classes.add("$sourcePackage.$className") - } - classes.sort() - - targetFile.parentFile.mkdirs() - targetFile.bufferedWriter().use { writer -> - writer.write("[\n") - classes.forEachIndexed { index, className -> - writer.write(" {\n") - writer.write(" \"name\": \"$className\",\n") - writer.write(" \"allDeclaredMethods\": true,\n") - writer.write(" \"allDeclaredFields\": true,\n") - writer.write(" \"allDeclaredConstructors\": true\n") - writer.write(" }") - if (index < classes.size - 1) { - writer.write(",\n") - } else { - writer.write("\n") - } - } - writer.write("]\n") - } - } -} - -tasks.getByName("compileJava").dependsOn(deleteJs2pTmp, copyResourceConfiguration) -tasks.getByName("sourcesJar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson, copyResourceConfiguration) -tasks.getByName("jar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson) -tasks.getByName("javadoc").dependsOn(buildGraalVmReflectionJson) -tasks.getByName("compileTestJava").dependsOn(buildGraalVmReflectionJson) - -// Exclude jsonschema2pojo generated sources from checkstyle -tasks.named("checkstyleMain") { - dependsOn(buildGraalVmReflectionJson) - exclude("**/fileconfig/internal/model/**") -} - -tasks { - withType().configureEach { - environment( - mapOf( - // Expose the kitchen sink example file to tests - "CONFIG_REPO_ROOT" to "$buildDirectory/configuration" - ) - ) - } + testImplementation(project(":sdk-extensions:autoconfigure")) + testImplementation("org.snakeyaml:snakeyaml-engine") } diff --git a/settings.gradle.kts b/settings.gradle.kts index 8ba7a5f6003..4150bcd08f3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -66,6 +66,7 @@ include(":sdk:testing") include(":sdk:trace") include(":sdk:trace-shaded-deps") include(":sdk-extensions:autoconfigure") +include(":sdk-extensions:autoconfigure-config") include(":sdk-extensions:autoconfigure-spi") include(":sdk-extensions:incubator") include(":sdk-extensions:jaeger-remote-sampler") From de18ba123f150860a47715171c8b90defd4466a4 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 9 Apr 2026 12:16:40 +0000 Subject: [PATCH 04/11] Fix graal-incubating test: DeclarativeConfigurationParser moved to autoconfigure module Signed-off-by: Gregor Zeitlinger --- integration-tests/graal-incubating/build.gradle.kts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/integration-tests/graal-incubating/build.gradle.kts b/integration-tests/graal-incubating/build.gradle.kts index 8b2153620c4..8400925ce51 100644 --- a/integration-tests/graal-incubating/build.gradle.kts +++ b/integration-tests/graal-incubating/build.gradle.kts @@ -25,6 +25,9 @@ dependencies { implementation(project(":exporters:otlp:all")) implementation(project(":api:incubator")) implementation(project(":sdk-extensions:incubator")) + implementation(project(":sdk-extensions:autoconfigure")) + implementation("org.snakeyaml:snakeyaml-engine") + implementation("com.fasterxml.jackson.core:jackson-databind") } // org.graalvm.buildtools.native plugin requires java 17+ as of version 0.11.0 From 2f8a2eaf79d3609c5616066aa4b1f82b7160cb68 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 9 Apr 2026 12:54:55 +0000 Subject: [PATCH 05/11] Fix CI: remove duplicate test files from src/test, fix incubator javadoc - Delete fileconfig tests from src/test/ (they were moved to testDeclarativeConfig in the previous commit but deletions were not staged) - Fix ViewConfig/ViewConfigCustomizer javadoc: replace broken {@link} cross-module reference to DeclarativeConfigurationParser with {@code} (class moved to autoconfigure module which is not a main-scope dep of incubator) - Delete incubator META-INF/services ComponentProvider registration (ServiceResourceDetector moved to autoconfigure module) Signed-off-by: Gregor Zeitlinger --- .../fileconfig/AggregationFactoryTest.java | 134 ----- .../fileconfig/AttributeListFactoryTest.java | 138 ----- .../fileconfig/CapturingComponentLoader.java | 76 --- .../CardinalityLimitsFactoryTest.java | 78 --- ...ComposableRuleBasedSamplerFactoryTest.java | 366 ------------- .../DeclarativeConfigContextTest.java | 55 -- .../DeclarativeConfigurationBuilderTest.java | 116 ----- .../DeclarativeConfigurationCreateTest.java | 211 -------- .../DeclarativeConfigurationParseTest.java | 489 ------------------ .../fileconfig/ExemplarFilterFactoryTest.java | 34 -- .../fileconfig/FileConfigTestUtil.java | 22 - .../InstrumentSelectorFactoryTest.java | 53 -- .../fileconfig/LogLimitsFactoryTest.java | 53 -- .../LogRecordExporterFactoryTest.java | 421 --------------- .../LogRecordProcessorFactoryTest.java | 186 ------- .../fileconfig/LoggerProviderFactoryTest.java | 165 ------ .../fileconfig/MeterProviderFactoryTest.java | 119 ----- .../fileconfig/MetricExporterFactoryTest.java | 474 ----------------- .../fileconfig/MetricReaderFactoryTest.java | 252 --------- ...OpenTelemetryConfigurationFactoryTest.java | 404 --------------- .../fileconfig/PropagatorFactoryTest.java | 132 ----- .../fileconfig/ResourceFactoryTest.java | 209 -------- .../fileconfig/SamplerFactoryTest.java | 236 --------- .../ServiceResourceDetectorTest.java | 64 --- .../fileconfig/SpanExporterFactoryTest.java | 437 ---------------- .../fileconfig/SpanLimitsFactoryTest.java | 62 --- .../fileconfig/SpanProcessorFactoryTest.java | 180 ------- ...rativeConfigurationCustomizerProvider.java | 43 -- .../fileconfig/TracerProviderFactoryTest.java | 141 ----- .../incubator/fileconfig/ViewFactoryTest.java | 73 --- .../YamlDeclarativeConfigPropertiesTest.java | 300 ----------- .../component/ContainerResourceProvider.java | 30 -- .../component/HostResourceProvider.java | 30 -- .../LogRecordExporterComponentProvider.java | 54 -- .../LogRecordProcessorComponentProvider.java | 47 -- .../MetricExporterComponentProvider.java | 63 --- .../component/OsResourceProvider.java | 30 -- .../component/ProcessResourceProvider.java | 30 -- .../component/ResourceComponentProvider.java | 27 - .../ResourceFirstComponentProvider.java | 27 - .../ResourceSecondComponentProvider.java | 27 - .../component/SamplerComponentProvider.java | 58 --- .../SpanExporterComponentProvider.java | 54 -- .../SpanProcessorComponentProvider.java | 61 --- .../TextMapPropagatorComponentProvider.java | 60 --- ...toconfigure.spi.internal.ComponentProvider | 14 - ...DeclarativeConfigurationCustomizerProvider | 1 - .../src/test/resources/aggregation-args.yaml | 21 - .../test/resources/empty-selector-config.yaml | 5 - .../src/test/resources/empty-view-config.yaml | 8 - .../src/test/resources/full-config.yaml | 28 - .../view-config-customizer-test.yaml | 6 - ...ComposableRuleBasedSamplerFactoryTest.java | 72 +++ .../fileconfig/ResourceFactoryTest.java | 25 +- .../incubator/fileconfig/ViewFactoryTest.java | 2 +- .../metric/viewconfig/ViewConfig.java | 5 +- .../viewconfig/ViewConfigCustomizer.java | 6 +- ...toconfigure.spi.internal.ComponentProvider | 1 - 58 files changed, 97 insertions(+), 6418 deletions(-) delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java delete mode 100644 sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider delete mode 100644 sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider delete mode 100644 sdk-extensions/autoconfigure/src/test/resources/aggregation-args.yaml delete mode 100644 sdk-extensions/autoconfigure/src/test/resources/empty-selector-config.yaml delete mode 100644 sdk-extensions/autoconfigure/src/test/resources/empty-view-config.yaml delete mode 100644 sdk-extensions/autoconfigure/src/test/resources/full-config.yaml delete mode 100644 sdk-extensions/autoconfigure/src/test/resources/view-config-customizer-test.yaml delete mode 100644 sdk-extensions/incubator/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java deleted file mode 100644 index 9b043bf54a7..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AggregationFactoryTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.mockito.Mockito.mock; - -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AggregationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Base2ExponentialBucketHistogramAggregationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DropAggregationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExplicitBucketHistogramAggregationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LastValueAggregationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SumAggregationModel; -import io.opentelemetry.sdk.metrics.Aggregation; -import io.opentelemetry.sdk.metrics.Base2ExponentialHistogramOptions; -import io.opentelemetry.sdk.metrics.ExplicitBucketHistogramOptions; -import java.util.Arrays; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class AggregationFactoryTest { - - @ParameterizedTest - @MethodSource("createTestCases") - void create(AggregationModel model, Aggregation expectedResult) { - Aggregation aggregation = - AggregationFactory.getInstance().create(model, mock(DeclarativeConfigContext.class)); - assertThat(aggregation.toString()).isEqualTo(expectedResult.toString()); - } - - private static Stream createTestCases() { - return Stream.of( - Arguments.of(new AggregationModel(), Aggregation.defaultAggregation()), - Arguments.of( - new AggregationModel().withDrop(new DropAggregationModel()), Aggregation.drop()), - Arguments.of(new AggregationModel().withSum(new SumAggregationModel()), Aggregation.sum()), - Arguments.of( - new AggregationModel().withLastValue(new LastValueAggregationModel()), - Aggregation.lastValue()), - Arguments.of( - new AggregationModel() - .withBase2ExponentialBucketHistogram( - new Base2ExponentialBucketHistogramAggregationModel()), - Aggregation.base2ExponentialBucketHistogram()), - Arguments.of( - new AggregationModel() - .withBase2ExponentialBucketHistogram( - new Base2ExponentialBucketHistogramAggregationModel() - .withMaxSize(2) - .withMaxScale(2)), - Aggregation.base2ExponentialBucketHistogram( - Base2ExponentialHistogramOptions.builder() - .setMaxBuckets(2) - .setMaxScale(2) - .build())), - Arguments.of( - new AggregationModel() - .withExplicitBucketHistogram( - new ExplicitBucketHistogramAggregationModel().withBoundaries(null)), - Aggregation.explicitBucketHistogram()), - Arguments.of( - new AggregationModel() - .withExplicitBucketHistogram( - new ExplicitBucketHistogramAggregationModel() - .withBoundaries(Arrays.asList(1.0, 2.0))), - Aggregation.explicitBucketHistogram( - ExplicitBucketHistogramOptions.builder() - .setBucketBoundaries(Arrays.asList(1.0, 2.0)) - .build())), - // Test recordMinMax parameter for explicit bucket histogram - Arguments.of( - new AggregationModel() - .withExplicitBucketHistogram( - new ExplicitBucketHistogramAggregationModel() - .withBoundaries(Arrays.asList(1.0, 2.0)) - .withRecordMinMax(true)), - Aggregation.explicitBucketHistogram( - ExplicitBucketHistogramOptions.builder() - .setBucketBoundaries(Arrays.asList(1.0, 2.0)) - .setRecordMinMax(true) - .build())), - Arguments.of( - new AggregationModel() - .withExplicitBucketHistogram( - new ExplicitBucketHistogramAggregationModel() - .withBoundaries(Arrays.asList(1.0, 2.0)) - .withRecordMinMax(false)), - Aggregation.explicitBucketHistogram( - ExplicitBucketHistogramOptions.builder() - .setBucketBoundaries(Arrays.asList(1.0, 2.0)) - .setRecordMinMax(false) - .build())), - Arguments.of( - new AggregationModel() - .withExplicitBucketHistogram( - new ExplicitBucketHistogramAggregationModel() - .withBoundaries(null) - .withRecordMinMax(false)), - Aggregation.explicitBucketHistogram( - ExplicitBucketHistogramOptions.builder().setRecordMinMax(false).build())), - // Test recordMinMax parameter for exponential bucket histogram - Arguments.of( - new AggregationModel() - .withBase2ExponentialBucketHistogram( - new Base2ExponentialBucketHistogramAggregationModel() - .withMaxSize(2) - .withMaxScale(2) - .withRecordMinMax(true)), - Aggregation.base2ExponentialBucketHistogram( - Base2ExponentialHistogramOptions.builder() - .setMaxBuckets(2) - .setMaxScale(2) - .setRecordMinMax(true) - .build())), - Arguments.of( - new AggregationModel() - .withBase2ExponentialBucketHistogram( - new Base2ExponentialBucketHistogramAggregationModel() - .withMaxSize(2) - .withMaxScale(2) - .withRecordMinMax(false)), - Aggregation.base2ExponentialBucketHistogram( - Base2ExponentialHistogramOptions.builder() - .setMaxBuckets(2) - .setMaxScale(2) - .setRecordMinMax(false) - .build()))); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java deleted file mode 100644 index 382fd772f8b..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/AttributeListFactoryTest.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; - -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class AttributeListFactoryTest { - - @ParameterizedTest - @MethodSource("invalidAttributes") - void create_InvalidAttributes(List model, String expectedMessage) { - assertThatThrownBy( - () -> - AttributeListFactory.getInstance() - .create(model, mock(DeclarativeConfigContext.class))) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessageContaining(expectedMessage); - } - - private static Stream invalidAttributes() { - return Stream.of( - Arguments.of( - Collections.singletonList(new AttributeNameValueModel().withName("key")), - "attribute value is required but is null"), - Arguments.of( - Collections.singletonList( - new AttributeNameValueModel().withName("key").withValue(new Object())), - "Error processing attribute with name \"key\": value did not match type STRING"), - Arguments.of( - Collections.singletonList( - new AttributeNameValueModel() - .withName("key") - .withType(AttributeNameValueModel.AttributeType.INT) - .withValue(Arrays.asList(1L, 1))), - "Error processing attribute with name \"key\": value did not match type INT"), - Arguments.of( - Collections.singletonList( - new AttributeNameValueModel() - .withName("key") - .withType(AttributeNameValueModel.AttributeType.INT) - .withValue(true)), - "Error processing attribute with name \"key\": value did not match type INT")); - } - - @Test - void create() { - Attributes expectedAttributes = - Attributes.builder() - .put("service.name", "my-service") - .put("strKey", "val") - .put("longKey", 1L) - .put("intKey", 2) - .put("doubleKey", 1.0d) - .put("floatKey", 2.0f) - .put("boolKey", true) - .put("strArrKey", "val1", "val2") - .put("longArrKey", 1L, 2L) - .put("intArrKey", 1, 2) - .put("doubleArrKey", 1.0d, 2.0d) - .put("floatArrKey", 1.0f, 2.0f) - .put("boolArrKey", true, false) - .build(); - assertThat( - AttributeListFactory.getInstance() - .create( - Arrays.asList( - new AttributeNameValueModel() - .withName("service.name") - .withValue("my-service"), - new AttributeNameValueModel() - .withName("strKey") - .withValue("val") - .withType(AttributeNameValueModel.AttributeType.STRING), - new AttributeNameValueModel() - .withName("longKey") - .withValue(1L) - .withType(AttributeNameValueModel.AttributeType.INT), - new AttributeNameValueModel() - .withName("intKey") - .withValue(2) - .withType(AttributeNameValueModel.AttributeType.INT), - new AttributeNameValueModel() - .withName("doubleKey") - .withValue(1.0d) - .withType(AttributeNameValueModel.AttributeType.DOUBLE), - new AttributeNameValueModel() - .withName("floatKey") - .withValue(2.0f) - .withType(AttributeNameValueModel.AttributeType.DOUBLE), - new AttributeNameValueModel() - .withName("boolKey") - .withValue(true) - .withType(AttributeNameValueModel.AttributeType.BOOL), - new AttributeNameValueModel() - .withName("strArrKey") - .withValue(Arrays.asList("val1", "val2")) - .withType(AttributeNameValueModel.AttributeType.STRING_ARRAY), - new AttributeNameValueModel() - .withName("longArrKey") - .withValue(Arrays.asList(1L, 2L)) - .withType(AttributeNameValueModel.AttributeType.INT_ARRAY), - new AttributeNameValueModel() - .withName("intArrKey") - .withValue(Arrays.asList(1, 2)) - .withType(AttributeNameValueModel.AttributeType.INT_ARRAY), - new AttributeNameValueModel() - .withName("doubleArrKey") - .withValue(Arrays.asList(1.0d, 2.0d)) - .withType(AttributeNameValueModel.AttributeType.DOUBLE_ARRAY), - new AttributeNameValueModel() - .withName("floatArrKey") - .withValue(Arrays.asList(1.0f, 2.0f)) - .withType(AttributeNameValueModel.AttributeType.DOUBLE_ARRAY), - new AttributeNameValueModel() - .withName("boolArrKey") - .withValue(Arrays.asList(true, false)) - .withType(AttributeNameValueModel.AttributeType.BOOL_ARRAY)), - mock(DeclarativeConfigContext.class))) - .isEqualTo(expectedAttributes); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java deleted file mode 100644 index ee99e1e1517..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CapturingComponentLoader.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * A test utility that captures the configuration passed to component providers during loading. This - * allows tests to verify that component providers receive the expected configuration. - */ -class CapturingComponentLoader implements ComponentLoader { - - private final ComponentLoader delegate; - private final Map capturedConfigs = - new ConcurrentHashMap<>(); - - CapturingComponentLoader() { - delegate = ComponentLoader.forClassLoader(getClass().getClassLoader()); - } - - DeclarativeConfigProperties getCapturedConfig(String name) { - return capturedConfigs.get(name); - } - - @Override - public Iterable load(Class spiClass) { - if (spiClass == ComponentProvider.class) { - return createWrappedComponentProviders(); - } - return delegate.load(spiClass); - } - - @SuppressWarnings("unchecked") - private Iterable createWrappedComponentProviders() { - List wrappedProviders = new ArrayList<>(); - for (ComponentProvider provider : delegate.load(ComponentProvider.class)) { - ComponentProvider wrapped = new CapturingComponentProvider(provider); - wrappedProviders.add((T) wrapped); - } - return wrappedProviders; - } - - private class CapturingComponentProvider implements ComponentProvider { - - private final ComponentProvider delegate; - - CapturingComponentProvider(ComponentProvider delegate) { - this.delegate = delegate; - } - - @Override - public Class getType() { - return delegate.getType(); - } - - @Override - public String getName() { - return delegate.getName(); - } - - @Override - public Object create(DeclarativeConfigProperties config) { - capturedConfigs.put(getName(), config); - return delegate.create(config); - } - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java deleted file mode 100644 index 103abba7ee0..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/CardinalityLimitsFactoryTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.mockito.Mockito.mock; - -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.CardinalityLimitsModel; -import io.opentelemetry.sdk.metrics.InstrumentType; -import io.opentelemetry.sdk.metrics.export.CardinalityLimitSelector; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class CardinalityLimitsFactoryTest { - - @ParameterizedTest - @MethodSource("createTestCases") - void create(CardinalityLimitsModel model, CardinalityLimitSelector expectedResult) { - CardinalityLimitSelector cardinalityLimitSelector = - CardinalityLimitsFactory.getInstance().create(model, mock(DeclarativeConfigContext.class)); - - for (InstrumentType instrumentType : InstrumentType.values()) { - assertThat(cardinalityLimitSelector.getCardinalityLimit(instrumentType)) - .describedAs(instrumentType.toString()) - .isEqualTo(expectedResult.getCardinalityLimit(instrumentType)); - } - } - - private static Stream createTestCases() { - return Stream.of( - Arguments.of( - new CardinalityLimitsModel(), - CardinalityLimitSelector.defaultCardinalityLimitSelector()), - Arguments.of( - new CardinalityLimitsModel().withDefault(10).withCounter(1), - (CardinalityLimitSelector) - instrumentType -> { - if (instrumentType == InstrumentType.COUNTER) { - return 1; - } - return 10; - }), - Arguments.of( - new CardinalityLimitsModel() - .withCounter(1) - .withUpDownCounter(2) - .withHistogram(3) - .withObservableCounter(4) - .withObservableUpDownCounter(5) - .withObservableGauge(6) - .withGauge(7), - (CardinalityLimitSelector) - instrumentType -> { - switch (instrumentType) { - case COUNTER: - return 1; - case UP_DOWN_COUNTER: - return 2; - case HISTOGRAM: - return 3; - case OBSERVABLE_COUNTER: - return 4; - case OBSERVABLE_UP_DOWN_COUNTER: - return 5; - case OBSERVABLE_GAUGE: - return 6; - case GAUGE: - return 7; - } - return 2000; - })); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java deleted file mode 100644 index 0016992593b..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.api.trace.SpanKind.CLIENT; -import static io.opentelemetry.api.trace.SpanKind.CONSUMER; -import static io.opentelemetry.api.trace.SpanKind.INTERNAL; -import static io.opentelemetry.api.trace.SpanKind.PRODUCER; -import static io.opentelemetry.api.trace.SpanKind.SERVER; -import static io.opentelemetry.sdk.extension.incubator.fileconfig.ComposableRuleBasedSamplerFactory.DeclarativeConfigSamplingPredicate.toSpanParent; -import static java.util.Collections.emptyList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.SpanContext; -import io.opentelemetry.api.trace.TraceFlags; -import io.opentelemetry.api.trace.TraceState; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; -import io.opentelemetry.sdk.extension.incubator.fileconfig.ComposableRuleBasedSamplerFactory.AttributeMatcher; -import io.opentelemetry.sdk.extension.incubator.fileconfig.ComposableRuleBasedSamplerFactory.DeclarativeConfigSamplingPredicate; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableAlwaysOffSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableAlwaysOnSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableProbabilitySamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerRuleAttributePatternsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerRuleAttributeValuesModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerRuleModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalSpanParent; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanKind; -import io.opentelemetry.sdk.extension.incubator.trace.samplers.ComposableSampler; -import io.opentelemetry.sdk.trace.IdGenerator; -import java.util.Arrays; -import java.util.Collections; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class ComposableRuleBasedSamplerFactoryTest { - - private final DeclarativeConfigContext context = - new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); - - @ParameterizedTest - @MethodSource("createTestCases") - void create(ExperimentalComposableRuleBasedSamplerModel model, ComposableSampler expectedResult) { - ComposableSampler composableSampler = - ComposableRuleBasedSamplerFactory.getInstance().create(model, context); - assertThat(composableSampler.toString()).isEqualTo(expectedResult.toString()); - } - - @ParameterizedTest - @MethodSource("createInvalidTestCases") - void createInvalid(ExperimentalComposableRuleBasedSamplerModel model, String expectedMessage) { - assertThatThrownBy(() -> ComposableRuleBasedSamplerFactory.getInstance().create(model, context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage(expectedMessage); - } - - private static Stream createInvalidTestCases() { - return Stream.of( - Arguments.of( - new ExperimentalComposableRuleBasedSamplerModel() - .withRules( - Collections.singletonList( - new ExperimentalComposableRuleBasedSamplerRuleModel() - .withAttributePatterns( - new ExperimentalComposableRuleBasedSamplerRuleAttributePatternsModel() - .withKey("http.path") - .withIncluded(Collections.emptyList()) - .withExcluded(null)) - .withSampler( - new ExperimentalComposableSamplerModel() - .withAlwaysOn( - new ExperimentalComposableAlwaysOnSamplerModel())))), - "included must not be empty"), - Arguments.of( - new ExperimentalComposableRuleBasedSamplerModel() - .withRules( - Collections.singletonList( - new ExperimentalComposableRuleBasedSamplerRuleModel() - .withAttributePatterns( - new ExperimentalComposableRuleBasedSamplerRuleAttributePatternsModel() - .withKey("http.path") - .withIncluded(null) - .withExcluded(Collections.emptyList())) - .withSampler( - new ExperimentalComposableSamplerModel() - .withAlwaysOn( - new ExperimentalComposableAlwaysOnSamplerModel())))), - "excluded must not be empty"), - Arguments.of( - new ExperimentalComposableRuleBasedSamplerModel() - .withRules( - Collections.singletonList( - new ExperimentalComposableRuleBasedSamplerRuleModel() - .withAttributeValues( - new ExperimentalComposableRuleBasedSamplerRuleAttributeValuesModel() - .withKey("http.route") - .withValues(null)) - .withSampler( - new ExperimentalComposableSamplerModel() - .withAlwaysOn( - new ExperimentalComposableAlwaysOnSamplerModel())))), - ".values is required and must be non-empty"), - Arguments.of( - new ExperimentalComposableRuleBasedSamplerModel() - .withRules( - Collections.singletonList( - new ExperimentalComposableRuleBasedSamplerRuleModel() - .withAttributeValues( - new ExperimentalComposableRuleBasedSamplerRuleAttributeValuesModel() - .withKey("http.route") - .withValues(Collections.emptyList())) - .withSampler( - new ExperimentalComposableSamplerModel() - .withAlwaysOn( - new ExperimentalComposableAlwaysOnSamplerModel())))), - ".values is required and must be non-empty")); - } - - private static Stream createTestCases() { - return Stream.of( - Arguments.of( - new ExperimentalComposableRuleBasedSamplerModel(), - ComposableSampler.ruleBasedBuilder().build()), - // Recreate example - Arguments.of( - new ExperimentalComposableRuleBasedSamplerModel() - .withRules( - Arrays.asList( - new ExperimentalComposableRuleBasedSamplerRuleModel() - .withAttributeValues( - new ExperimentalComposableRuleBasedSamplerRuleAttributeValuesModel() - .withKey("http.route") - .withValues(Arrays.asList("/healthz", "/livez"))) - .withSampler( - new ExperimentalComposableSamplerModel() - .withAlwaysOff( - new ExperimentalComposableAlwaysOffSamplerModel())), - new ExperimentalComposableRuleBasedSamplerRuleModel() - .withAttributePatterns( - new ExperimentalComposableRuleBasedSamplerRuleAttributePatternsModel() - .withKey("http.path") - .withIncluded(Collections.singletonList("/internal/*")) - .withExcluded(Collections.singletonList("/internal/special/*"))) - .withSampler( - new ExperimentalComposableSamplerModel() - .withAlwaysOn( - new ExperimentalComposableAlwaysOnSamplerModel())), - new ExperimentalComposableRuleBasedSamplerRuleModel() - .withParent(Collections.singletonList(ExperimentalSpanParent.NONE)) - .withSpanKinds(Collections.singletonList(SpanKind.CLIENT)) - .withSampler( - new ExperimentalComposableSamplerModel() - .withProbability( - new ExperimentalComposableProbabilitySamplerModel() - .withRatio(0.05))), - new ExperimentalComposableRuleBasedSamplerRuleModel() - .withSampler( - new ExperimentalComposableSamplerModel() - .withProbability( - new ExperimentalComposableProbabilitySamplerModel() - .withRatio(0.05))))), - ComposableSampler.ruleBasedBuilder() - .add( - new DeclarativeConfigSamplingPredicate( - new AttributeMatcher( - "http.route", - IncludeExcludePredicate.createExactMatching( - Arrays.asList("/healthz", "/livez"), null)), - null, - null, - null), - ComposableSampler.alwaysOff()) - .add( - new DeclarativeConfigSamplingPredicate( - null, - new AttributeMatcher( - "http.path", - IncludeExcludePredicate.createPatternMatching( - Collections.singletonList("/internal/*"), - Collections.singletonList("/internal/special/*"))), - null, - null), - ComposableSampler.alwaysOn()) - .add( - new DeclarativeConfigSamplingPredicate( - null, - null, - Collections.singleton(ExperimentalSpanParent.NONE), - Collections.singleton(CLIENT)), - ComposableSampler.probability(0.05)) - .add( - new DeclarativeConfigSamplingPredicate(null, null, null, null), - ComposableSampler.probability(0.05)) - .build())); - } - - private static final Context noParent = Context.current(); - private static final Context localParent = - Context.root() - .with( - Span.wrap( - SpanContext.create( - IdGenerator.random().generateTraceId(), - IdGenerator.random().generateSpanId(), - TraceFlags.getDefault(), - TraceState.getDefault()))); - private static final Context remoteParent = - Context.root() - .with( - Span.wrap( - SpanContext.createFromRemoteParent( - IdGenerator.random().generateTraceId(), - IdGenerator.random().generateSpanId(), - TraceFlags.getDefault(), - TraceState.getDefault()))); - private static final String tid = IdGenerator.random().generateTraceId(); - private static final String sn = "name"; - private static final io.opentelemetry.api.trace.SpanKind sk = CLIENT; - private static final AttributeKey HTTP_ROUTE = AttributeKey.stringKey("http.route"); - private static final AttributeKey HTTP_PATH = AttributeKey.stringKey("http.path"); - - @ParameterizedTest - @MethodSource("declarativeConfigSamplingPredicateArgs") - void declarativeConfigSamplingPredicate( - DeclarativeConfigSamplingPredicate predicate, - Context context, - io.opentelemetry.api.trace.SpanKind spanKind, - Attributes attributes, - boolean expectedResult) { - assertThat(predicate.matches(context, tid, sn, spanKind, attributes, emptyList())) - .isEqualTo(expectedResult); - } - - @SuppressWarnings("unused") - private static Stream declarativeConfigSamplingPredicateArgs() { - DeclarativeConfigSamplingPredicate matchAll = - new DeclarativeConfigSamplingPredicate(null, null, null, null); - DeclarativeConfigSamplingPredicate valuesMatcher = - new DeclarativeConfigSamplingPredicate( - new AttributeMatcher( - "http.route", - IncludeExcludePredicate.createExactMatching( - Arrays.asList("/healthz", "/livez"), null)), - null, - null, - null); - DeclarativeConfigSamplingPredicate patternsMatcher = - new DeclarativeConfigSamplingPredicate( - null, - new AttributeMatcher( - "http.path", - IncludeExcludePredicate.createPatternMatching( - Collections.singletonList("/internal/*"), - Collections.singletonList("/internal/special/*"))), - null, - null); - DeclarativeConfigSamplingPredicate parentMatcher = - new DeclarativeConfigSamplingPredicate( - null, null, Collections.singleton(ExperimentalSpanParent.NONE), null); - DeclarativeConfigSamplingPredicate spanKindMatcher = - new DeclarativeConfigSamplingPredicate(null, null, null, Collections.singleton(CLIENT)); - DeclarativeConfigSamplingPredicate multiMatcher = - new DeclarativeConfigSamplingPredicate( - new AttributeMatcher( - "http.route", - IncludeExcludePredicate.createExactMatching( - Arrays.asList("/healthz", "/livez"), null)), - new AttributeMatcher( - "http.path", - IncludeExcludePredicate.createPatternMatching( - Collections.singletonList("/internal/*"), - Collections.singletonList("/internal/special/*"))), - Collections.singleton(ExperimentalSpanParent.NONE), - Collections.singleton(CLIENT)); - - return Stream.of( - // match all - Arguments.of(matchAll, noParent, sk, Attributes.empty(), true), - Arguments.of(matchAll, noParent, sk, Attributes.of(HTTP_ROUTE, "/healthz"), true), - Arguments.of( - matchAll, noParent, sk, Attributes.of(HTTP_PATH, "/internal/admin/users"), true), - Arguments.of(matchAll, noParent, SERVER, Attributes.empty(), true), - Arguments.of(matchAll, remoteParent, sk, Attributes.empty(), true), - // value matcher - Arguments.of(valuesMatcher, noParent, sk, Attributes.of(HTTP_ROUTE, "/healthz"), true), - Arguments.of(valuesMatcher, noParent, sk, Attributes.of(HTTP_ROUTE, "/livez"), true), - Arguments.of(valuesMatcher, noParent, sk, Attributes.of(HTTP_ROUTE, "/foo"), false), - Arguments.of(valuesMatcher, noParent, sk, Attributes.empty(), false), - // pattern matcher - Arguments.of( - patternsMatcher, noParent, sk, Attributes.of(HTTP_PATH, "/internal/admin/users"), true), - Arguments.of( - patternsMatcher, - noParent, - sk, - Attributes.of(HTTP_PATH, "/internal/management/config"), - true), - Arguments.of( - patternsMatcher, noParent, sk, Attributes.of(HTTP_PATH, "/users/profile/123"), false), - Arguments.of( - patternsMatcher, - noParent, - sk, - Attributes.of(HTTP_PATH, "/internal/special/foo"), - false), - // parent matcher - Arguments.of(parentMatcher, noParent, sk, Attributes.empty(), true), - Arguments.of(parentMatcher, localParent, sk, Attributes.empty(), false), - Arguments.of(parentMatcher, remoteParent, sk, Attributes.empty(), false), - // span kind matcher - Arguments.of(spanKindMatcher, noParent, CLIENT, Attributes.empty(), true), - Arguments.of(spanKindMatcher, noParent, SERVER, Attributes.empty(), false), - Arguments.of(spanKindMatcher, noParent, INTERNAL, Attributes.empty(), false), - Arguments.of(spanKindMatcher, noParent, PRODUCER, Attributes.empty(), false), - Arguments.of(spanKindMatcher, noParent, CONSUMER, Attributes.empty(), false), - // multi matcher - Arguments.of( - multiMatcher, - noParent, - CLIENT, - Attributes.of(HTTP_ROUTE, "/livez", HTTP_PATH, "/internal/admin/users"), - true), - Arguments.of(multiMatcher, noParent, CLIENT, Attributes.of(HTTP_ROUTE, "/livez"), false), - Arguments.of( - multiMatcher, - noParent, - CLIENT, - Attributes.of(HTTP_PATH, "/internal/admin/users"), - false), - Arguments.of( - multiMatcher, - noParent, - SERVER, - Attributes.of(HTTP_ROUTE, "/livez", HTTP_PATH, "/internal/admin/users"), - false), - Arguments.of( - multiMatcher, - localParent, - CLIENT, - Attributes.of(HTTP_ROUTE, "/livez", HTTP_PATH, "/internal/admin/users"), - false)); - } - - @Test - void toSpanParent_Valid() { - assertThat(toSpanParent(SpanContext.getInvalid())).isEqualTo(ExperimentalSpanParent.NONE); - assertThat(toSpanParent(Span.fromContext(localParent).getSpanContext())) - .isEqualTo(ExperimentalSpanParent.LOCAL); - assertThat(toSpanParent(Span.fromContext(remoteParent).getSpanContext())) - .isEqualTo(ExperimentalSpanParent.REMOTE); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java deleted file mode 100644 index 71b9df870df..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigContextTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.resources.Resource; -import java.util.Collections; -import org.junit.jupiter.api.Test; - -class DeclarativeConfigContextTest { - - private final ComponentLoader componentLoader = - spy(ComponentLoader.forClassLoader(getClass().getClassLoader())); - private final DeclarativeConfigContext context = new DeclarativeConfigContext(componentLoader); - - @Test - void componentProvidersCached() { - // First loadComponent call should load providers - assertThatThrownBy( - () -> - context.loadComponent( - Resource.class, - ConfigKeyValue.of( - "nonexistent", - YamlDeclarativeConfigProperties.create( - Collections.emptyMap(), componentLoader)))) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessageContaining("No component provider detected"); - - // Second loadComponent call should use cached providers, not reload - assertThatThrownBy( - () -> - context.loadComponent( - Resource.class, - ConfigKeyValue.of( - "another", - YamlDeclarativeConfigProperties.create( - Collections.emptyMap(), componentLoader)))) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessageContaining("No component provider detected"); - - // Verify spiHelper.load() was only called once - verify(componentLoader, times(1)).load(ComponentProvider.class); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java deleted file mode 100644 index d1abd33fcd9..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationBuilderTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.logs.export.LogRecordExporter; -import io.opentelemetry.sdk.metrics.export.MetricExporter; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import org.junit.jupiter.api.Test; - -class DeclarativeConfigurationBuilderTest { - - @Test - void spanExporterCustomizer_Single() { - DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); - - builder.addSpanExporterCustomizer( - SpanExporter.class, (exporter, properties) -> mock(SpanExporter.class)); - - assertThat(builder.getSpanExporterCustomizers()).hasSize(1); - } - - @Test - void spanExporterCustomizer_Multiple_Compose() { - DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); - - builder.addSpanExporterCustomizer( - SpanExporter.class, (exporter, properties) -> mock(SpanExporter.class)); - builder.addSpanExporterCustomizer( - SpanExporter.class, (exporter, properties) -> mock(SpanExporter.class)); - - assertThat(builder.getSpanExporterCustomizers()).hasSize(2); - } - - @Test - void metricExporterCustomizer_Single() { - DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); - - builder.addMetricExporterCustomizer( - MetricExporter.class, (exporter, properties) -> mock(MetricExporter.class)); - - assertThat(builder.getMetricExporterCustomizers()).hasSize(1); - } - - @Test - void metricExporterCustomizer_Multiple_Compose() { - DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); - - builder.addMetricExporterCustomizer( - MetricExporter.class, (exporter, properties) -> mock(MetricExporter.class)); - builder.addMetricExporterCustomizer( - MetricExporter.class, (exporter, properties) -> mock(MetricExporter.class)); - - assertThat(builder.getMetricExporterCustomizers()).hasSize(2); - } - - @Test - void logRecordExporterCustomizer_Single() { - DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); - - builder.addLogRecordExporterCustomizer( - LogRecordExporter.class, (exporter, properties) -> mock(LogRecordExporter.class)); - - assertThat(builder.getLogRecordExporterCustomizers()).hasSize(1); - } - - @Test - void logRecordExporterCustomizer_Multiple_Compose() { - DeclarativeConfigurationBuilder builder = new DeclarativeConfigurationBuilder(); - - builder.addLogRecordExporterCustomizer( - LogRecordExporter.class, (exporter, properties) -> mock(LogRecordExporter.class)); - builder.addLogRecordExporterCustomizer( - LogRecordExporter.class, (exporter, properties) -> mock(LogRecordExporter.class)); - - assertThat(builder.getLogRecordExporterCustomizers()).hasSize(2); - } - - @Test - void customizer_ClosesOriginalWhenReplaced() throws Exception { - SpanExporter original = mock(SpanExporter.class); - SpanExporter replacement = mock(SpanExporter.class); - DeclarativeConfigProperties props = mock(DeclarativeConfigProperties.class); - - DeclarativeConfigurationBuilder.Customizer customizer = - new DeclarativeConfigurationBuilder.Customizer<>( - SpanExporter.class, (exporter, properties) -> replacement); - - SpanExporter result = customizer.maybeCustomize(original, "test", props); - - assertThat(result).isSameAs(replacement); - verify(original).close(); - } - - @Test - void customizer_DoesNotCloseWhenSameInstance() throws Exception { - SpanExporter exporter = mock(SpanExporter.class); - DeclarativeConfigProperties props = mock(DeclarativeConfigProperties.class); - - DeclarativeConfigurationBuilder.Customizer customizer = - new DeclarativeConfigurationBuilder.Customizer<>(SpanExporter.class, (e, properties) -> e); - - SpanExporter result = customizer.maybeCustomize(exporter, "test", props); - - assertThat(result).isSameAs(exporter); - verify(exporter, never()).close(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java deleted file mode 100644 index eace3c6203a..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationCreateTest.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent; -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.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; -import io.github.netmikey.logunit.api.LogCapturer; -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.internal.testing.slf4j.SuppressLogger; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; -import io.opentelemetry.sdk.internal.ExtendedOpenTelemetrySdk; -import io.opentelemetry.sdk.trace.samplers.ParentBasedSamplerBuilder; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.cert.CertificateEncodingException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.api.io.TempDir; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.slf4j.event.Level; - -class DeclarativeConfigurationCreateTest { - - @RegisterExtension - static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension(); - - @RegisterExtension - static final SelfSignedCertificateExtension clientTls = new SelfSignedCertificateExtension(); - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - @RegisterExtension - LogCapturer logCapturer = - LogCapturer.create().captureForLogger(DeclarativeConfiguration.class.getName(), Level.TRACE); - - /** - * Verify each example in open-telemetry/opentelemetry-configuration/examples - * can pass {@link DeclarativeConfigurationParser#parseAndCreate(InputStream)}. - */ - @ParameterizedTest - @MethodSource("exampleFiles") - @SuppressLogger(ParentBasedSamplerBuilder.class) - void parseAndCreate_Examples(File example, @TempDir Path tempDir) - throws IOException, CertificateEncodingException { - // Write certificates to temp files - String certificatePath = - createTempFileWithContent( - tempDir, "certificate.cert", serverTls.certificate().getEncoded()); - String clientKeyPath = - createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); - String clientCertificatePath = - createTempFileWithContent( - tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); - - // Rewrite references to cert files in examples - String exampleContent = - new String(Files.readAllBytes(example.toPath()), StandardCharsets.UTF_8); - String rewrittenExampleContent = - exampleContent - .replaceAll( - "ca_file: .*\n", - "ca_file: " + certificatePath.replace("\\", "\\\\") + System.lineSeparator()) - .replaceAll( - "key_file: .*\n", - "key_file: " + clientKeyPath.replace("\\", "\\\\") + System.lineSeparator()) - .replaceAll( - "cert_file: .*\n", - "cert_file: " - + clientCertificatePath.replace("\\", "\\\\") - + System.lineSeparator()); - InputStream is = - new ByteArrayInputStream(rewrittenExampleContent.getBytes(StandardCharsets.UTF_8)); - - // Verify that file can be parsed and interpreted without error - assertThatCode(() -> cleanup.addCloseable(DeclarativeConfigurationParser.parseAndCreate(is).getSdk())) - .as("Example file: " + example.getName()) - .doesNotThrowAnyException(); - } - - private static Stream exampleFiles() { - File configRepoRoot = new File(System.getenv("CONFIG_REPO_ROOT")); - File examplesDir = new File(configRepoRoot + "/examples/"); - File snippetsDir = new File(configRepoRoot + "/snippets/"); - List examples = new ArrayList<>(); - examples.addAll(Arrays.asList(Objects.requireNonNull(examplesDir.listFiles()))); - examples.addAll(Arrays.asList(Objects.requireNonNull(snippetsDir.listFiles()))); - - return examples.stream().map(file -> Arguments.argumentSet(file.getName(), file)); - } - - @Test - void parseAndCreate_Exception_CleansUpPartials() { - // Trigger an exception after some components have been configured by adding a valid batch - // exporter with OTLP exporter, following by invalid batch exporter which references invalid - // exporter "foo". - String yaml = - "file_format: \"1.0\"\n" - + "logger_provider:\n" - + " processors:\n" - + " - batch:\n" - + " exporter:\n" - + " otlp_http: {}\n" - + " - batch:\n" - + " exporter:\n" - + " foo: {}\n"; - - assertThatThrownBy( - () -> - DeclarativeConfigurationParser.parseAndCreate( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)))) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage( - "No component provider detected for io.opentelemetry.sdk.logs.export.LogRecordExporter with name \"foo\"."); - logCapturer.assertContains( - "Error encountered interpreting model. Closing partially configured components."); - logCapturer.assertContains( - "Closing io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter"); - logCapturer.assertContains("Closing io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor"); - } - - @Test - void parseAndCreate_EmptyComponentProviderConfig() { - String yaml = - "file_format: \"1.0\"\n" - + "logger_provider:\n" - + " processors:\n" - + " - test:\n" - + "tracer_provider:\n" - + " processors:\n" - + " - test:\n"; - - assertThatCode( - () -> - DeclarativeConfigurationParser.parseAndCreate( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)))) - .doesNotThrowAnyException(); - } - - @Test - void create_ModelCustomizer() { - OpenTelemetryConfigurationModel model = new OpenTelemetryConfigurationModel(); - model.withFileFormat("1.0"); - model.withTracerProvider( - new TracerProviderModel() - .withProcessors( - Collections.singletonList( - new SpanProcessorModel().withAdditionalProperty("test", null)))); - ExtendedOpenTelemetrySdk sdk = - DeclarativeConfiguration.create( - model, - // customizer is TestDeclarativeConfigurationCustomizerProvider - ComponentLoader.forClassLoader( - DeclarativeConfigurationCreateTest.class.getClassLoader())) - .getSdk(); - assertThat(sdk.toString()) - .contains( - "resource=Resource{schemaUrl=null, attributes={" - + "color=\"blue\", " - + "foo=\"bar\", " - + "service.name=\"unknown_service:java\", " - + "telemetry.sdk.language=\"java\", " - + "telemetry.sdk.name=\"opentelemetry\", " - + "telemetry.sdk.version=\""); - } - - @Test - @SuppressLogger(DeclarativeConfiguration.class) - void callAutoConfigureListeners_exceptionIsCaught() { - DeclarativeConfigContext context = mock(DeclarativeConfigContext.class); - when(context.getListeners()) - .thenReturn( - Collections.singleton( - sdk -> { - throw new RuntimeException("Test exception from AutoConfigureListener"); - })); - - assertThatCode( - () -> - DeclarativeConfiguration.callAutoConfigureListeners( - context, OpenTelemetrySdk.builder().build())) - .doesNotThrowAnyException(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java deleted file mode 100644 index 6c50081f494..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfigurationParseTest.java +++ /dev/null @@ -1,489 +0,0 @@ -/* - * 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.assertThatThrownBy; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AggregationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TraceIdRatioBasedSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import java.util.AbstractMap; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Stream; -import javax.annotation.Nullable; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class DeclarativeConfigurationParseTest { - - @Test - void parse_BadInputStream() { - assertThatThrownBy( - () -> - DeclarativeConfigurationParser.parseAndCreate( - new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8)))) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage("Unable to parse configuration input stream"); - } - - @Test - void parse_nullValuesParsedToEmptyObjects() { - String objectPlaceholderString = - "file_format: \"1.0\"\n" - + "tracer_provider:\n" - + " processors:\n" - + " - batch:\n" - + " exporter:\n" - + " console: {}\n" - + "meter_provider:\n" - + " views:\n" - + " - selector:\n" - + " instrument_type: histogram\n" - + " stream:\n" - + " aggregation:\n" - + " drop: {}\n"; - OpenTelemetryConfigurationModel objectPlaceholderModel = - DeclarativeConfigurationParser.parse( - new ByteArrayInputStream(objectPlaceholderString.getBytes(StandardCharsets.UTF_8))); - - String noOjbectPlaceholderString = - "file_format: \"1.0\"\n" - + "tracer_provider:\n" - + " processors:\n" - + " - batch:\n" - + " exporter:\n" - + " console:\n" - + "meter_provider:\n" - + " views:\n" - + " - selector:\n" - + " instrument_type: histogram\n" - + " stream:\n" - + " aggregation:\n" - + " drop:\n"; - OpenTelemetryConfigurationModel noObjectPlaceholderModel = - DeclarativeConfigurationParser.parse( - new ByteArrayInputStream(noOjbectPlaceholderString.getBytes(StandardCharsets.UTF_8))); - - SpanExporterModel exporter = - noObjectPlaceholderModel - .getTracerProvider() - .getProcessors() - .get(0) - .getBatch() - .getExporter(); - assertThat(exporter.getConsole()).isNotNull(); - assertThat(exporter.getOtlpHttp()).isNull(); - - AggregationModel aggregation = - noObjectPlaceholderModel.getMeterProvider().getViews().get(0).getStream().getAggregation(); - assertThat(aggregation.getDrop()).isNotNull(); - assertThat(aggregation.getSum()).isNull(); - - assertThat(objectPlaceholderModel).isEqualTo(noObjectPlaceholderModel); - } - - @Test - void parse_nullBoxedPrimitivesParsedToNull() { - String yaml = - "file_format:\n" // String - + "disabled:\n" // Boolean - + "attribute_limits:\n" - + " attribute_value_length_limit:\n" // Integer - + "tracer_provider:\n" - + " sampler:\n" - + " trace_id_ratio_based:\n" - + " ratio:\n"; // Double - - OpenTelemetryConfigurationModel model = - DeclarativeConfigurationParser.parse( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); - - assertThat(model.getFileFormat()).isNull(); - assertThat(model.getDisabled()).isNull(); - assertThat(model.getAttributeLimits().getAttributeValueLengthLimit()).isNull(); - assertThat(model.getTracerProvider().getSampler().getTraceIdRatioBased().getRatio()).isNull(); - - assertThat(model) - .isEqualTo( - new OpenTelemetryConfigurationModel() - .withAttributeLimits(new AttributeLimitsModel()) - .withTracerProvider( - new TracerProviderModel() - .withSampler( - new SamplerModel() - .withTraceIdRatioBased(new TraceIdRatioBasedSamplerModel())))); - } - - @Test - void parse_quotedInput() { - String yaml = - "resource:\n" - + " attributes:\n" - + " - name: single_quote\n" - + " value: '\"single\"'\n" - + " - name: double_quote\n" - + " value: \"\\\"double\\\"\""; - - OpenTelemetryConfigurationModel model = - DeclarativeConfigurationParser.parse( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8))); - - Assertions.assertNotNull(model.getResource()); - assertThat(model.getResource().getAttributes()) - .containsExactly( - new AttributeNameValueModel().withName("single_quote").withValue("\"single\""), - new AttributeNameValueModel().withName("double_quote").withValue("\"double\"")); - } - - @ParameterizedTest - @MethodSource("coreSchemaValuesArgs") - void coreSchemaValues(String rawYaml, Object expectedYamlResult) { - Object yaml = - DeclarativeConfigurationParser.loadYaml( - new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)), - Collections.emptyMap(), - Collections.emptyMap()); - assertThat(yaml).isEqualTo(expectedYamlResult); - } - - @SuppressWarnings("unchecked") - private static Stream coreSchemaValuesArgs() { - return Stream.of( - Arguments.of("key1: 0o123\n", mapOf(entry("key1", 83))), - Arguments.of("key1: 0123\n", mapOf(entry("key1", 123))), - Arguments.of("key1: 0xdeadbeef\n", mapOf(entry("key1", 3735928559L))), - Arguments.of("key1: \"0xdeadbeef\"\n", mapOf(entry("key1", "0xdeadbeef")))); - } - - @ParameterizedTest - @MethodSource("envVarSubstitutionArgs") - void envSubstituteAndLoadYaml(String rawYaml, Object expectedYamlResult) { - Map environmentVariables = new HashMap<>(); - environmentVariables.put("FOO", "BAR"); - environmentVariables.put("STR_1", "value1"); - environmentVariables.put("STR_2", "value2"); - environmentVariables.put("VALUE_WITH_ESCAPE", "value$$"); - environmentVariables.put("EMPTY_STR", ""); - environmentVariables.put("BOOL", "true"); - environmentVariables.put("INT", "1"); - environmentVariables.put("FLOAT", "1.1"); - environmentVariables.put("HEX", "0xdeadbeef"); - - Object yaml = - DeclarativeConfigurationParser.loadYaml( - new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)), - environmentVariables, - Collections.emptyMap()); - assertThat(yaml).isEqualTo(expectedYamlResult); - } - - @SuppressWarnings("unchecked") - private static Stream envVarSubstitutionArgs() { - return Stream.of( - // Simple cases - Arguments.of("key1: ${STR_1}\n", mapOf(entry("key1", "value1"))), - Arguments.of("key1: ${BOOL}\n", mapOf(entry("key1", true))), - Arguments.of("key1: ${INT}\n", mapOf(entry("key1", 1))), - Arguments.of("key1: ${FLOAT}\n", mapOf(entry("key1", 1.1))), - Arguments.of("key1: ${HEX}\n", mapOf(entry("key1", 3735928559L))), - Arguments.of( - "key1: ${STR_1}\n" + "key2: value2\n", - mapOf(entry("key1", "value1"), entry("key2", "value2"))), - Arguments.of( - "key1: ${STR_1} value1\n" + "key2: value2\n", - mapOf(entry("key1", "value1 value1"), entry("key2", "value2"))), - // Default cases - Arguments.of("key1: ${NOT_SET:-value1}\n", mapOf(entry("key1", "value1"))), - Arguments.of("key1: ${NOT_SET:-true}\n", mapOf(entry("key1", true))), - Arguments.of("key1: ${NOT_SET:-1}\n", mapOf(entry("key1", 1))), - Arguments.of("key1: ${NOT_SET:-1.1}\n", mapOf(entry("key1", 1.1))), - Arguments.of("key1: ${NOT_SET:-0xdeadbeef}\n", mapOf(entry("key1", 3735928559L))), - Arguments.of( - "key1: ${NOT_SET:-value1} value2\n" + "key2: value2\n", - mapOf(entry("key1", "value1 value2"), entry("key2", "value2"))), - // Multiple environment variables referenced - Arguments.of("key1: ${STR_1}${STR_2}\n", mapOf(entry("key1", "value1value2"))), - Arguments.of("key1: ${STR_1} ${STR_2}\n", mapOf(entry("key1", "value1 value2"))), - Arguments.of( - "key1: ${STR_1} ${NOT_SET:-default} ${STR_2}\n", - mapOf(entry("key1", "value1 default value2"))), - // Undefined / empty environment variable - Arguments.of("key1: ${EMPTY_STR}\n", mapOf(entry("key1", null))), - Arguments.of("key1: ${STR_3}\n", mapOf(entry("key1", null))), - Arguments.of("key1: ${STR_1} ${STR_3}\n", mapOf(entry("key1", "value1 "))), - // Environment variable keys must match pattern: [a-zA-Z_]+[a-zA-Z0-9_]* - Arguments.of("key1: ${VAR&}\n", mapOf(entry("key1", "${VAR&}"))), - // Environment variable substitution only takes place in scalar values of maps - Arguments.of("${STR_1}: value1\n", mapOf(entry("${STR_1}", "value1"))), - Arguments.of( - "key1:\n ${STR_1}: value1\n", - mapOf(entry("key1", mapOf(entry("${STR_1}", "value1"))))), - Arguments.of( - "key1:\n - ${STR_1}\n", mapOf(entry("key1", Collections.singletonList("${STR_1}")))), - // Double-quoted environment variables - Arguments.of("key1: \"${HEX}\"\n", mapOf(entry("key1", "0xdeadbeef"))), - Arguments.of("key1: \"${STR_1}\"\n", mapOf(entry("key1", "value1"))), - Arguments.of("key1: \"${EMPTY_STR}\"\n", mapOf(entry("key1", ""))), - Arguments.of("key1: \"${BOOL}\"\n", mapOf(entry("key1", "true"))), - Arguments.of("key1: \"${INT}\"\n", mapOf(entry("key1", "1"))), - Arguments.of("key1: \"${FLOAT}\"\n", mapOf(entry("key1", "1.1"))), - Arguments.of( - "key1: \"${HEX} ${BOOL} ${INT}\"\n", mapOf(entry("key1", "0xdeadbeef true 1"))), - // Single-quoted environment variables - Arguments.of("key1: '${HEX}'\n", mapOf(entry("key1", "0xdeadbeef"))), - Arguments.of("key1: '${STR_1}'\n", mapOf(entry("key1", "value1"))), - Arguments.of("key1: '${EMPTY_STR}'\n", mapOf(entry("key1", ""))), - Arguments.of("key1: '${BOOL}'\n", mapOf(entry("key1", "true"))), - Arguments.of("key1: '${INT}'\n", mapOf(entry("key1", "1"))), - Arguments.of("key1: '${FLOAT}'\n", mapOf(entry("key1", "1.1"))), - Arguments.of("key1: '${HEX} ${BOOL} ${INT}'\n", mapOf(entry("key1", "0xdeadbeef true 1"))), - // Escaped - Arguments.of("key1: ${FOO}\n", mapOf(entry("key1", "BAR"))), - Arguments.of("key1: $${FOO}\n", mapOf(entry("key1", "${FOO}"))), - Arguments.of("key1: $$${FOO}\n", mapOf(entry("key1", "$BAR"))), - Arguments.of("key1: $$$${FOO}\n", mapOf(entry("key1", "$${FOO}"))), - Arguments.of("key1: a $$ b\n", mapOf(entry("key1", "a $ b"))), - Arguments.of("key1: $$ b\n", mapOf(entry("key1", "$ b"))), - Arguments.of("key1: a $$\n", mapOf(entry("key1", "a $"))), - Arguments.of("key1: a $ b\n", mapOf(entry("key1", "a $ b"))), - Arguments.of("key1: $${STR_1}\n", mapOf(entry("key1", "${STR_1}"))), - Arguments.of("key1: $${STR_1}$${STR_1}\n", mapOf(entry("key1", "${STR_1}${STR_1}"))), - Arguments.of("key1: $${STR_1}$$\n", mapOf(entry("key1", "${STR_1}$"))), - Arguments.of("key1: $$${STR_1}\n", mapOf(entry("key1", "$value1"))), - Arguments.of("key1: \"$${STR_1}\"\n", mapOf(entry("key1", "${STR_1}"))), - Arguments.of("key1: $${STR_1} ${STR_2}\n", mapOf(entry("key1", "${STR_1} value2"))), - Arguments.of("key1: $${STR_1} $${STR_2}\n", mapOf(entry("key1", "${STR_1} ${STR_2}"))), - Arguments.of("key1: $${NOT_SET:-value1}\n", mapOf(entry("key1", "${NOT_SET:-value1}"))), - Arguments.of("key1: $${STR_1:-fallback}\n", mapOf(entry("key1", "${STR_1:-fallback}"))), - Arguments.of("key1: $${STR_1:-${STR_1}}\n", mapOf(entry("key1", "${STR_1:-value1}"))), - Arguments.of("key1: ${NOT_SET:-${FALLBACK}}\n", mapOf(entry("key1", "${FALLBACK}"))), - Arguments.of( - "key1: ${NOT_SET:-$${FALLBACK}}\n", mapOf(entry("key1", "${NOT_SET:-${FALLBACK}}"))), - Arguments.of("key1: ${VALUE_WITH_ESCAPE}\n", mapOf(entry("key1", "value$$")))); - } - - private static Map.Entry entry(K key, @Nullable V value) { - return new AbstractMap.SimpleEntry<>(key, value); - } - - @SuppressWarnings("unchecked") - private static Map mapOf(Map.Entry... entries) { - Map result = new HashMap<>(); - for (Map.Entry entry : entries) { - result.put(entry.getKey(), entry.getValue()); - } - return result; - } - - @ParameterizedTest - @MethodSource("sysPropertySubstitutionArgs") - void sysPropertySubstituteAndLoadYaml(String rawYaml, Object expectedYamlResult) { - Map systemProperties = new HashMap<>(); - systemProperties.put("foo.bar", "BAR"); - systemProperties.put("str.1", "value1"); - systemProperties.put("str.2", "value2"); - systemProperties.put("value.with.escape", "value$$"); - systemProperties.put("empty.str", ""); - systemProperties.put("bool.prop", "true"); - systemProperties.put("int.prop", "1"); - systemProperties.put("float.prop", "1.1"); - systemProperties.put("hex.prop", "0xdeadbeef"); - - Object yaml = - DeclarativeConfigurationParser.loadYaml( - new ByteArrayInputStream(rawYaml.getBytes(StandardCharsets.UTF_8)), - Collections.emptyMap(), - systemProperties); - assertThat(yaml).isEqualTo(expectedYamlResult); - } - - @SuppressWarnings("unchecked") - private static Stream sysPropertySubstitutionArgs() { - return Stream.of( - // Simple cases with sys: prefix - Arguments.of("key1: ${sys:str.1}\n", mapOf(entry("key1", "value1"))), - Arguments.of("key1: ${sys:bool.prop}\n", mapOf(entry("key1", true))), - Arguments.of("key1: ${sys:int.prop}\n", mapOf(entry("key1", 1))), - Arguments.of("key1: ${sys:float.prop}\n", mapOf(entry("key1", 1.1))), - Arguments.of("key1: ${sys:hex.prop}\n", mapOf(entry("key1", 3735928559L))), - // Default values - Arguments.of("key1: ${sys:not.set:-value1}\n", mapOf(entry("key1", "value1"))), - Arguments.of("key1: ${sys:not.set:-true}\n", mapOf(entry("key1", true))), - Arguments.of("key1: ${sys:not.set:-1}\n", mapOf(entry("key1", 1))), - // Multiple property references - Arguments.of("key1: ${sys:str.1}${sys:str.2}\n", mapOf(entry("key1", "value1value2"))), - Arguments.of("key1: ${sys:str.1} ${sys:str.2}\n", mapOf(entry("key1", "value1 value2"))), - Arguments.of( - "key1: ${sys:str.1} ${sys:not.set:-default} ${sys:str.2}\n", - mapOf(entry("key1", "value1 default value2"))), - // Undefined / empty system property - Arguments.of("key1: ${sys:empty.str}\n", mapOf(entry("key1", null))), - Arguments.of("key1: ${sys:str.3}\n", mapOf(entry("key1", null))), - Arguments.of("key1: ${sys:str.1} ${sys:str.3}\n", mapOf(entry("key1", "value1 "))), - // Quoted system properties - Arguments.of("key1: \"${sys:hex.prop}\"\n", mapOf(entry("key1", "0xdeadbeef"))), - Arguments.of("key1: \"${sys:str.1}\"\n", mapOf(entry("key1", "value1"))), - Arguments.of("key1: '${sys:str.1}'\n", mapOf(entry("key1", "value1"))), - // Escaped - Arguments.of("key1: ${sys:foo.bar}\n", mapOf(entry("key1", "BAR"))), - Arguments.of("key1: $${sys:foo.bar}\n", mapOf(entry("key1", "${sys:foo.bar}"))), - Arguments.of("key1: $$${sys:foo.bar}\n", mapOf(entry("key1", "$BAR"))), - Arguments.of("key1: $$$${sys:foo.bar}\n", mapOf(entry("key1", "$${sys:foo.bar}"))), - // Mixed env and sys - Arguments.of("key1: ${sys:value.with.escape}\n", mapOf(entry("key1", "value$$")))); - } - - @Test - void read_WithEnvironmentVariables() { - String yaml = - "file_format: \"1.0\"\n" - + "tracer_provider:\n" - + " processors:\n" - + " - batch:\n" - + " exporter:\n" - + " otlp_http:\n" - + " endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT}\n" - + " - batch:\n" - + " exporter:\n" - + " otlp_http:\n" - + " endpoint: ${UNSET_ENV_VAR}\n"; - Map envVars = new HashMap<>(); - envVars.put("OTEL_EXPORTER_OTLP_ENDPOINT", "http://collector:4317"); - OpenTelemetryConfigurationModel model = - DeclarativeConfigurationParser.parse( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), - envVars, - Collections.emptyMap()); - assertThat(model) - .isEqualTo( - new OpenTelemetryConfigurationModel() - .withFileFormat("1.0") - .withTracerProvider( - new TracerProviderModel() - .withProcessors( - Arrays.asList( - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel() - .withOtlpHttp( - new OtlpHttpExporterModel() - .withEndpoint( - "http://collector:4317")))), - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel() - .withOtlpHttp( - new OtlpHttpExporterModel()))))))); - } - - @Test - void read_WithSystemProperties() { - String yaml = - "file_format: \"1.0\"\n" - + "tracer_provider:\n" - + " processors:\n" - + " - batch:\n" - + " exporter:\n" - + " otlp_http:\n" - + " endpoint: ${sys:otel.exporter.otlp.endpoint}\n" - + " - batch:\n" - + " exporter:\n" - + " otlp_http:\n" - + " endpoint: ${sys:unset.sys.prop}\n"; - Map sysProps = new HashMap<>(); - sysProps.put("otel.exporter.otlp.endpoint", "http://collector:4318"); - OpenTelemetryConfigurationModel model = - DeclarativeConfigurationParser.parse( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), - Collections.emptyMap(), - sysProps); - assertThat(model) - .isEqualTo( - new OpenTelemetryConfigurationModel() - .withFileFormat("1.0") - .withTracerProvider( - new TracerProviderModel() - .withProcessors( - Arrays.asList( - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel() - .withOtlpHttp( - new OtlpHttpExporterModel() - .withEndpoint( - "http://collector:4318")))), - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel() - .withOtlpHttp( - new OtlpHttpExporterModel()))))))); - } - - @Test - void read_WithMixedEnvVarsAndSystemProperties() { - String yaml = - "file_format: \"1.0\"\n" - + "resource:\n" - + " attributes:\n" - + " - name: service.name\n" - + " value: ${SERVICE_NAME}\n" - + " - name: service.version\n" - + " value: ${sys:app.version}\n" - + " - name: deployment.environment\n" - + " value: ${env:DEPLOYMENT_ENV:-production}\n"; - Map envVars = new HashMap<>(); - envVars.put("SERVICE_NAME", "my-service"); - Map sysProps = new HashMap<>(); - sysProps.put("app.version", "1.2.3"); - OpenTelemetryConfigurationModel model = - DeclarativeConfigurationParser.parse( - new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8)), envVars, sysProps); - assertThat(model) - .isEqualTo( - new OpenTelemetryConfigurationModel() - .withFileFormat("1.0") - .withResource( - new ResourceModel() - .withAttributes( - Arrays.asList( - new AttributeNameValueModel() - .withName("service.name") - .withValue("my-service"), - new AttributeNameValueModel() - .withName("service.version") - .withValue("1.2.3"), - new AttributeNameValueModel() - .withName("deployment.environment") - .withValue("production"))))); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java deleted file mode 100644 index 79fa0bbde45..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ExemplarFilterFactoryTest.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.mockito.Mockito.mock; - -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel; -import io.opentelemetry.sdk.metrics.ExemplarFilter; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class ExemplarFilterFactoryTest { - - @ParameterizedTest - @MethodSource("createTestCases") - void create(MeterProviderModel.ExemplarFilter model, ExemplarFilter expectedResult) { - ExemplarFilter exemplarFilter = - ExemplarFilterFactory.getInstance().create(model, mock(DeclarativeConfigContext.class)); - assertThat(exemplarFilter.toString()).isEqualTo(expectedResult.toString()); - } - - private static Stream createTestCases() { - return Stream.of( - Arguments.of(MeterProviderModel.ExemplarFilter.ALWAYS_ON, ExemplarFilter.alwaysOn()), - Arguments.of(MeterProviderModel.ExemplarFilter.ALWAYS_OFF, ExemplarFilter.alwaysOff()), - Arguments.of(MeterProviderModel.ExemplarFilter.TRACE_BASED, ExemplarFilter.traceBased())); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java deleted file mode 100644 index f98bf6e698c..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/FileConfigTestUtil.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -final class FileConfigTestUtil { - - private FileConfigTestUtil() {} - - static String createTempFileWithContent(Path dir, String filename, byte[] content) - throws IOException { - Path path = dir.resolve(filename); - Files.write(path, content); - return path.toString(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java deleted file mode 100644 index d0362c5e242..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/InstrumentSelectorFactoryTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewSelectorModel; -import io.opentelemetry.sdk.metrics.InstrumentSelector; -import io.opentelemetry.sdk.metrics.InstrumentType; -import org.junit.jupiter.api.Test; - -class InstrumentSelectorFactoryTest { - - @Test - void create_Defaults() { - assertThatThrownBy( - () -> - InstrumentSelectorFactory.getInstance() - .create(new ViewSelectorModel(), mock(DeclarativeConfigContext.class))) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage("Invalid selector"); - } - - @Test - void create() { - assertThat( - InstrumentSelectorFactory.getInstance() - .create( - new ViewSelectorModel() - .withInstrumentName("instrument-name") - .withInstrumentType(ViewSelectorModel.InstrumentType.COUNTER) - .withUnit("ms") - .withMeterName("meter-name") - .withMeterSchemaUrl("https://opentelemetry.io/schemas/1.16.0") - .withMeterVersion("1.0.0"), - mock(DeclarativeConfigContext.class))) - .isEqualTo( - InstrumentSelector.builder() - .setName("instrument-name") - .setType(InstrumentType.COUNTER) - .setUnit("ms") - .setMeterName("meter-name") - .setMeterSchemaUrl("https://opentelemetry.io/schemas/1.16.0") - .setMeterVersion("1.0.0") - .build()); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java deleted file mode 100644 index 5fab6df6d11..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogLimitsFactoryTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.mockito.Mockito.mock; - -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordLimitsModel; -import io.opentelemetry.sdk.logs.LogLimits; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class LogLimitsFactoryTest { - - @ParameterizedTest - @MethodSource("createArguments") - void create(LogRecordLimitsAndAttributeLimits model, LogLimits expectedLogLimits) { - assertThat(LogLimitsFactory.getInstance().create(model, mock(DeclarativeConfigContext.class))) - .isEqualTo(expectedLogLimits); - } - - private static Stream createArguments() { - return Stream.of( - Arguments.of( - LogRecordLimitsAndAttributeLimits.create(null, null), LogLimits.builder().build()), - Arguments.of( - LogRecordLimitsAndAttributeLimits.create( - new AttributeLimitsModel(), new LogRecordLimitsModel()), - LogLimits.builder().build()), - Arguments.of( - LogRecordLimitsAndAttributeLimits.create( - new AttributeLimitsModel() - .withAttributeValueLengthLimit(1) - .withAttributeCountLimit(2), - new LogRecordLimitsModel()), - LogLimits.builder().setMaxAttributeValueLength(1).setMaxNumberOfAttributes(2).build()), - Arguments.of( - LogRecordLimitsAndAttributeLimits.create( - new AttributeLimitsModel() - .withAttributeValueLengthLimit(1) - .withAttributeCountLimit(2), - new LogRecordLimitsModel() - .withAttributeValueLengthLimit(3) - .withAttributeCountLimit(4)), - LogLimits.builder().setMaxAttributeValueLength(3).setMaxNumberOfAttributes(4).build())); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java deleted file mode 100644 index d9e67056f06..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter; -import io.opentelemetry.exporter.logging.otlp.internal.logs.OtlpStdoutLogRecordExporter; -import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; -import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordExporterComponentProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalOtlpFileExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.GrpcTlsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HttpTlsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterPropertyModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpGrpcExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; -import io.opentelemetry.sdk.logs.export.LogRecordExporter; -import java.io.Closeable; -import java.io.IOException; -import java.nio.file.Path; -import java.security.cert.CertificateEncodingException; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.api.io.TempDir; - -class LogRecordExporterFactoryTest { - - @RegisterExtension - static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension(); - - @RegisterExtension - static final SelfSignedCertificateExtension clientTls = new SelfSignedCertificateExtension(); - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - private CapturingComponentLoader capturingComponentLoader; - private DeclarativeConfigContext context; - - @BeforeEach - void setup() { - capturingComponentLoader = new CapturingComponentLoader(); - context = new DeclarativeConfigContext(capturingComponentLoader); - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @Test - void create_OtlpHttpDefaults() { - List closeables = new ArrayList<>(); - OtlpHttpLogRecordExporter expectedExporter = - OtlpHttpLogRecordExporter.getDefault().toBuilder() - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - LogRecordExporter exporter = - LogRecordExporterFactory.getInstance() - .create( - new LogRecordExporterModel().withOtlpHttp(new OtlpHttpExporterModel()), context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_http"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("protocol")).isNull(); - assertThat(configProperties.getString("endpoint")).isNull(); - assertThat(configProperties.getStructured("headers")).isNull(); - assertThat(configProperties.getString("compression")).isNull(); - assertThat(configProperties.getInt("timeout")).isNull(); - assertThat(configProperties.getString("certificate_file")).isNull(); - assertThat(configProperties.getString("client_key_file")).isNull(); - assertThat(configProperties.getString("client_certificate_file")).isNull(); - } - - @Test - void create_OtlpHttpConfigured(@TempDir Path tempDir) - throws CertificateEncodingException, IOException { - List closeables = new ArrayList<>(); - OtlpHttpLogRecordExporter expectedExporter = - OtlpHttpLogRecordExporter.builder() - .setEndpoint("http://example:4318/v1/logs") - .addHeader("key1", "value1") - .addHeader("key2", "value2") - .setTimeout(Duration.ofSeconds(15)) - .setCompression("gzip") - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - // Write certificates to temp files - String certificatePath = - createTempFileWithContent( - tempDir, "certificate.cert", serverTls.certificate().getEncoded()); - String clientKeyPath = - createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); - String clientCertificatePath = - createTempFileWithContent( - tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); - - LogRecordExporter exporter = - LogRecordExporterFactory.getInstance() - .create( - new LogRecordExporterModel() - .withOtlpHttp( - new OtlpHttpExporterModel() - .withEndpoint("http://example:4318/v1/logs") - .withHeaders( - Arrays.asList( - new NameStringValuePairModel() - .withName("key1") - .withValue("value1"), - new NameStringValuePairModel() - .withName("key2") - .withValue("value2"))) - .withCompression("gzip") - .withTimeout(15_000) - .withTls( - new HttpTlsModel() - .withCaFile(certificatePath) - .withKeyFile(clientKeyPath) - .withCertFile(clientCertificatePath))), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_http"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/logs"); - List headers = configProperties.getStructuredList("headers"); - assertThat(headers) - .isNotNull() - .satisfiesExactly( - header -> { - assertThat(header.getString("name")).isEqualTo("key1"); - assertThat(header.getString("value")).isEqualTo("value1"); - }, - header -> { - assertThat(header.getString("name")).isEqualTo("key2"); - assertThat(header.getString("value")).isEqualTo("value2"); - }); - assertThat(configProperties.getString("compression")).isEqualTo("gzip"); - assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - DeclarativeConfigProperties tls = configProperties.getStructured("tls"); - assertThat(tls).isNotNull(); - assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); - assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); - assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); - } - - @Test - void create_OtlpGrpcDefaults() { - List closeables = new ArrayList<>(); - OtlpGrpcLogRecordExporter expectedExporter = - OtlpGrpcLogRecordExporter.getDefault().toBuilder() - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - LogRecordExporter exporter = - LogRecordExporterFactory.getInstance() - .create( - new LogRecordExporterModel().withOtlpGrpc(new OtlpGrpcExporterModel()), context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_grpc"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isNull(); - assertThat(configProperties.getStructured("headers")).isNull(); - assertThat(configProperties.getString("compression")).isNull(); - assertThat(configProperties.getInt("timeout")).isNull(); - assertThat(configProperties.getString("certificate_file")).isNull(); - assertThat(configProperties.getString("client_key_file")).isNull(); - assertThat(configProperties.getString("client_certificate_file")).isNull(); - } - - @Test - void create_OtlpGrpcConfigured(@TempDir Path tempDir) - throws CertificateEncodingException, IOException { - List closeables = new ArrayList<>(); - OtlpGrpcLogRecordExporter expectedExporter = - OtlpGrpcLogRecordExporter.builder() - .setEndpoint("http://example:4317") - .addHeader("key1", "value1") - .addHeader("key2", "value2") - .setTimeout(Duration.ofSeconds(15)) - .setCompression("gzip") - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - // Write certificates to temp files - String certificatePath = - createTempFileWithContent( - tempDir, "certificate.cert", serverTls.certificate().getEncoded()); - String clientKeyPath = - createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); - String clientCertificatePath = - createTempFileWithContent( - tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); - - LogRecordExporter exporter = - LogRecordExporterFactory.getInstance() - .create( - new LogRecordExporterModel() - .withOtlpGrpc( - new OtlpGrpcExporterModel() - .withEndpoint("http://example:4317") - .withHeaders( - Arrays.asList( - new NameStringValuePairModel() - .withName("key1") - .withValue("value1"), - new NameStringValuePairModel() - .withName("key2") - .withValue("value2"))) - .withCompression("gzip") - .withTimeout(15_000) - .withTls( - new GrpcTlsModel() - .withCaFile(certificatePath) - .withKeyFile(clientKeyPath) - .withCertFile(clientCertificatePath))), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_grpc"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4317"); - List headers = configProperties.getStructuredList("headers"); - assertThat(headers) - .isNotNull() - .satisfiesExactly( - header -> { - assertThat(header.getString("name")).isEqualTo("key1"); - assertThat(header.getString("value")).isEqualTo("value1"); - }, - header -> { - assertThat(header.getString("name")).isEqualTo("key2"); - assertThat(header.getString("value")).isEqualTo("value2"); - }); - assertThat(configProperties.getString("compression")).isEqualTo("gzip"); - assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - DeclarativeConfigProperties tls = configProperties.getStructured("tls"); - assertThat(tls).isNotNull(); - assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); - assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); - assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); - } - - @Test - void create_OtlpFile() { - List closeables = new ArrayList<>(); - OtlpStdoutLogRecordExporter expectedExporter = OtlpStdoutLogRecordExporter.builder().build(); - cleanup.addCloseable(expectedExporter); - - LogRecordExporter exporter = - LogRecordExporterFactory.getInstance() - .create( - new LogRecordExporterModel() - .withOtlpFileDevelopment(new ExperimentalOtlpFileExporterModel()), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_file/development"); - assertThat(configProperties).isNotNull(); - } - - @Test - void create_SpiExporter_Unknown() { - List closeables = new ArrayList<>(); - - assertThatThrownBy( - () -> - LogRecordExporterFactory.getInstance() - .create( - new LogRecordExporterModel() - .withAdditionalProperty( - "unknown_key", - new LogRecordExporterPropertyModel() - .withAdditionalProperty("key1", "value1")), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage( - "No component provider detected for io.opentelemetry.sdk.logs.export.LogRecordExporter with name \"unknown_key\"."); - cleanup.addCloseables(closeables); - } - - @Test - void create_SpiExporter_Valid() { - LogRecordExporter logRecordExporter = - LogRecordExporterFactory.getInstance() - .create( - new LogRecordExporterModel() - .withAdditionalProperty( - "test", - new LogRecordExporterPropertyModel() - .withAdditionalProperty("key1", "value1")), - context); - assertThat(logRecordExporter) - .isInstanceOf(LogRecordExporterComponentProvider.TestLogRecordExporter.class); - assertThat( - ((LogRecordExporterComponentProvider.TestLogRecordExporter) logRecordExporter) - .config.getString("key1")) - .isEqualTo("value1"); - } - - @Test - void create_Customizer() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addLogRecordExporterCustomizer( - LogRecordExporter.class, (exporter, properties) -> SystemOutLogRecordExporter.create()); - - LogRecordExporter result = - LogRecordExporterFactory.getInstance() - .create(new LogRecordExporterModel().withConsole(new ConsoleExporterModel()), context); - cleanup.addCloseable(result); - - assertThat(result).isInstanceOf(SystemOutLogRecordExporter.class); - } - - @Test - void create_Customizer_TypeSafe() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addLogRecordExporterCustomizer( - OtlpGrpcLogRecordExporter.class, - (exporter, properties) -> - exporter.toBuilder().setTimeout(Duration.ofSeconds(42)).build()); - - LogRecordExporter result = - LogRecordExporterFactory.getInstance() - .create( - new LogRecordExporterModel().withOtlpGrpc(new OtlpGrpcExporterModel()), context); - cleanup.addCloseable(result); - - assertThat(result).isInstanceOf(OtlpGrpcLogRecordExporter.class); - assertThat(result.toString()).contains("timeoutNanos=42000000000"); - } - - @Test - void create_Customizer_TypeMismatch() { - AtomicInteger callCount = new AtomicInteger(0); - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addLogRecordExporterCustomizer( - OtlpGrpcLogRecordExporter.class, - (exporter, properties) -> { - callCount.incrementAndGet(); - return exporter; - }); - - LogRecordExporter result = - LogRecordExporterFactory.getInstance() - .create(new LogRecordExporterModel().withConsole(new ConsoleExporterModel()), context); - cleanup.addCloseable(result); - - assertThat(callCount.get()).isEqualTo(0); - } - - @Test - void create_Customizer_ReturnsNull() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addLogRecordExporterCustomizer(LogRecordExporter.class, (exporter, properties) -> null); - - assertThatThrownBy( - () -> - LogRecordExporterFactory.getInstance() - .create( - new LogRecordExporterModel().withConsole(new ConsoleExporterModel()), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessageContaining("Customizer returned null for LogRecordExporter: console"); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java deleted file mode 100644 index 8a863f238f7..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordProcessorComponentProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorPropertyModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleLogRecordProcessorModel; -import io.opentelemetry.sdk.logs.LogRecordProcessor; -import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; -import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; -import java.io.Closeable; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -class LogRecordProcessorFactoryTest { - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - private final DeclarativeConfigContext context = - new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); - - @BeforeEach - void setup() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @Test - void create_BatchNullExporter() { - assertThatThrownBy( - () -> - LogRecordProcessorFactory.getInstance() - .create( - new LogRecordProcessorModel().withBatch(new BatchLogRecordProcessorModel()), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage("batch log record processor exporter is required but is null"); - } - - @Test - void create_BatchDefaults() { - List closeables = new ArrayList<>(); - BatchLogRecordProcessor expectedProcessor = - BatchLogRecordProcessor.builder( - OtlpHttpLogRecordExporter.builder().setComponentLoader(context).build()) - .build(); - cleanup.addCloseable(expectedProcessor); - - LogRecordProcessor processor = - LogRecordProcessorFactory.getInstance() - .create( - new LogRecordProcessorModel() - .withBatch( - new BatchLogRecordProcessorModel() - .withExporter( - new LogRecordExporterModel() - .withOtlpHttp(new OtlpHttpExporterModel()))), - context); - cleanup.addCloseable(processor); - cleanup.addCloseables(closeables); - - assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); - } - - @Test - void create_BatchConfigured() { - List closeables = new ArrayList<>(); - BatchLogRecordProcessor expectedProcessor = - BatchLogRecordProcessor.builder( - OtlpHttpLogRecordExporter.builder().setComponentLoader(context).build()) - .setScheduleDelay(Duration.ofMillis(1)) - .setMaxExportBatchSize(2) - .setExporterTimeout(Duration.ofMillis(3)) - .build(); - cleanup.addCloseable(expectedProcessor); - - LogRecordProcessor processor = - LogRecordProcessorFactory.getInstance() - .create( - new LogRecordProcessorModel() - .withBatch( - new BatchLogRecordProcessorModel() - .withExporter( - new LogRecordExporterModel() - .withOtlpHttp(new OtlpHttpExporterModel())) - .withScheduleDelay(1) - .withMaxExportBatchSize(2) - .withExportTimeout(3)), - context); - cleanup.addCloseable(processor); - cleanup.addCloseables(closeables); - - assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); - } - - @Test - void create_SimpleNullExporter() { - assertThatThrownBy( - () -> - LogRecordProcessorFactory.getInstance() - .create( - new LogRecordProcessorModel() - .withSimple(new SimpleLogRecordProcessorModel()), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage("simple log record processor exporter is required but is null"); - } - - @Test - void create_SimpleConfigured() { - List closeables = new ArrayList<>(); - LogRecordProcessor expectedProcessor = - SimpleLogRecordProcessor.create( - OtlpHttpLogRecordExporter.builder().setComponentLoader(context).build()); - cleanup.addCloseable(expectedProcessor); - - LogRecordProcessor processor = - LogRecordProcessorFactory.getInstance() - .create( - new LogRecordProcessorModel() - .withSimple( - new SimpleLogRecordProcessorModel() - .withExporter( - new LogRecordExporterModel() - .withOtlpHttp(new OtlpHttpExporterModel()))), - context); - cleanup.addCloseable(processor); - cleanup.addCloseables(closeables); - - assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); - } - - @Test - void create_SpiProcessor_Unknown() { - assertThatThrownBy( - () -> - LogRecordProcessorFactory.getInstance() - .create( - new LogRecordProcessorModel() - .withAdditionalProperty( - "unknown_key", - new LogRecordProcessorPropertyModel() - .withAdditionalProperty("key1", "value1")), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage( - "No component provider detected for io.opentelemetry.sdk.logs.LogRecordProcessor with name \"unknown_key\"."); - } - - @Test - void create_SpiExporter_Valid() { - LogRecordProcessor logRecordProcessor = - LogRecordProcessorFactory.getInstance() - .create( - new LogRecordProcessorModel() - .withAdditionalProperty( - "test", - new LogRecordProcessorPropertyModel() - .withAdditionalProperty("key1", "value1")), - context); - assertThat(logRecordProcessor) - .isInstanceOf(LogRecordProcessorComponentProvider.TestLogRecordProcessor.class); - Assertions.assertThat( - ((LogRecordProcessorComponentProvider.TestLogRecordProcessor) logRecordProcessor) - .config.getString("key1")) - .isEqualTo("value1"); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java deleted file mode 100644 index 3381b3ea5e5..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LoggerProviderFactoryTest.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil.setLoggerConfigurator; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; - -import io.opentelemetry.api.logs.Severity; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.sdk.common.internal.ScopeConfigurator; -import io.opentelemetry.sdk.common.internal.ScopeConfiguratorBuilder; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLoggerConfigModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLoggerConfiguratorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLoggerMatcherAndConfigModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel.SeverityNumber; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; -import io.opentelemetry.sdk.logs.LogLimits; -import io.opentelemetry.sdk.logs.SdkLoggerProvider; -import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; -import io.opentelemetry.sdk.logs.internal.LoggerConfig; -import java.io.Closeable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class LoggerProviderFactoryTest { - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - private static final DeclarativeConfigContext context = - new DeclarativeConfigContext( - ComponentLoader.forClassLoader(LoggerProviderFactoryTest.class.getClassLoader())); - - @BeforeEach - void setup() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @ParameterizedTest - @MethodSource("createArguments") - void create(LoggerProviderAndAttributeLimits model, SdkLoggerProvider expectedProvider) { - List closeables = new ArrayList<>(); - cleanup.addCloseable(expectedProvider); - - SdkLoggerProvider provider = LoggerProviderFactory.getInstance().create(model, context).build(); - cleanup.addCloseable(provider); - cleanup.addCloseables(closeables); - - assertThat(provider.toString()).isEqualTo(expectedProvider.toString()); - } - - private static Stream createArguments() { - return Stream.of( - Arguments.of( - LoggerProviderAndAttributeLimits.create(null, null), - SdkLoggerProvider.builder().build()), - Arguments.of( - LoggerProviderAndAttributeLimits.create( - new AttributeLimitsModel(), new LoggerProviderModel()), - SdkLoggerProvider.builder().build()), - Arguments.of( - LoggerProviderAndAttributeLimits.create( - new AttributeLimitsModel(), - new LoggerProviderModel() - .withLimits( - new LogRecordLimitsModel() - .withAttributeCountLimit(1) - .withAttributeValueLengthLimit(2)) - .withProcessors( - Collections.singletonList( - new LogRecordProcessorModel() - .withBatch( - new BatchLogRecordProcessorModel() - .withExporter( - new LogRecordExporterModel() - .withOtlpHttp(new OtlpHttpExporterModel()))))) - .withLoggerConfiguratorDevelopment( - new ExperimentalLoggerConfiguratorModel() - .withDefaultConfig( - new ExperimentalLoggerConfigModel().withEnabled(false)) - .withLoggers( - Collections.singletonList( - new ExperimentalLoggerMatcherAndConfigModel() - .withName("foo") - .withConfig( - new ExperimentalLoggerConfigModel() - .withEnabled(true) - .withTraceBased(true) - .withMinimumSeverity(SeverityNumber.INFO)))))), - setLoggerConfigurator( - SdkLoggerProvider.builder(), - ScopeConfigurator.builder() - .setDefault(LoggerConfig.disabled()) - .addCondition( - ScopeConfiguratorBuilder.nameMatchesGlob("foo"), - LoggerConfig.builder() - .setEnabled(true) - .setTraceBased(true) - .setMinimumSeverity(Severity.INFO) - .build()) - .build()) - .setLogLimits( - () -> - LogLimits.builder() - .setMaxNumberOfAttributes(1) - .setMaxAttributeValueLength(2) - .build()) - .addLogRecordProcessor( - BatchLogRecordProcessor.builder( - OtlpHttpLogRecordExporter.builder().setComponentLoader(context).build()) - .build()) - .build())); - } - - @ParameterizedTest - @MethodSource("severityNumberArguments") - void severityNumber(SeverityNumber model, Severity expectedSeverity) { - assertThat(LoggerProviderFactory.severityNumberToSeverity(model)).isEqualTo(expectedSeverity); - } - - private static Stream severityNumberArguments() { - return Stream.of( - Arguments.of(SeverityNumber.TRACE, Severity.TRACE), - Arguments.of(SeverityNumber.TRACE_2, Severity.TRACE2), - Arguments.of(SeverityNumber.TRACE_3, Severity.TRACE3), - Arguments.of(SeverityNumber.TRACE_4, Severity.TRACE4), - Arguments.of(SeverityNumber.DEBUG, Severity.DEBUG), - Arguments.of(SeverityNumber.DEBUG_2, Severity.DEBUG2), - Arguments.of(SeverityNumber.DEBUG_3, Severity.DEBUG3), - Arguments.of(SeverityNumber.DEBUG_4, Severity.DEBUG4), - Arguments.of(SeverityNumber.INFO, Severity.INFO), - Arguments.of(SeverityNumber.INFO_2, Severity.INFO2), - Arguments.of(SeverityNumber.INFO_3, Severity.INFO3), - Arguments.of(SeverityNumber.INFO_4, Severity.INFO4), - Arguments.of(SeverityNumber.WARN, Severity.WARN), - Arguments.of(SeverityNumber.WARN_2, Severity.WARN2), - Arguments.of(SeverityNumber.WARN_3, Severity.WARN3), - Arguments.of(SeverityNumber.WARN_4, Severity.WARN4), - Arguments.of(SeverityNumber.ERROR, Severity.ERROR), - Arguments.of(SeverityNumber.ERROR_2, Severity.ERROR2), - Arguments.of(SeverityNumber.ERROR_3, Severity.ERROR3), - Arguments.of(SeverityNumber.ERROR_4, Severity.ERROR4), - Arguments.of(SeverityNumber.FATAL, Severity.FATAL), - Arguments.of(SeverityNumber.FATAL_2, Severity.FATAL2), - Arguments.of(SeverityNumber.FATAL_3, Severity.FATAL3), - Arguments.of(SeverityNumber.FATAL_4, Severity.FATAL4)); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java deleted file mode 100644 index 1254b411992..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MeterProviderFactoryTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil.setMeterConfigurator; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; - -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.sdk.common.internal.ScopeConfigurator; -import io.opentelemetry.sdk.common.internal.ScopeConfiguratorBuilder; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalMeterConfigModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalMeterConfiguratorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalMeterMatcherAndConfigModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewSelectorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewStreamModel; -import io.opentelemetry.sdk.metrics.ExemplarFilter; -import io.opentelemetry.sdk.metrics.InstrumentSelector; -import io.opentelemetry.sdk.metrics.SdkMeterProvider; -import io.opentelemetry.sdk.metrics.View; -import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; -import io.opentelemetry.sdk.metrics.internal.MeterConfig; -import java.io.Closeable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class MeterProviderFactoryTest { - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - private static final DeclarativeConfigContext context = - new DeclarativeConfigContext( - ComponentLoader.forClassLoader(MeterProviderFactoryTest.class.getClassLoader())); - - @BeforeEach - void setup() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @ParameterizedTest - @MethodSource("createArguments") - void create(MeterProviderModel model, SdkMeterProvider expectedProvider) { - List closeables = new ArrayList<>(); - cleanup.addCloseable(expectedProvider); - - SdkMeterProvider provider = MeterProviderFactory.getInstance().create(model, context).build(); - cleanup.addCloseable(provider); - cleanup.addCloseables(closeables); - - assertThat(provider.toString()).isEqualTo(expectedProvider.toString()); - } - - private static Stream createArguments() { - return Stream.of( - Arguments.of(new MeterProviderModel(), SdkMeterProvider.builder().build()), - Arguments.of( - new MeterProviderModel() - .withReaders( - Collections.singletonList( - new MetricReaderModel() - .withPeriodic( - new PeriodicMetricReaderModel() - .withExporter( - new PushMetricExporterModel() - .withOtlpHttp(new OtlpHttpMetricExporterModel()))))) - .withViews( - Collections.singletonList( - new ViewModel() - .withSelector( - new ViewSelectorModel().withInstrumentName("instrument-name")) - .withStream( - new ViewStreamModel() - .withName("stream-name") - .withAttributeKeys(null)))) - .withMeterConfiguratorDevelopment( - new ExperimentalMeterConfiguratorModel() - .withDefaultConfig(new ExperimentalMeterConfigModel().withEnabled(false)) - .withMeters( - Collections.singletonList( - new ExperimentalMeterMatcherAndConfigModel() - .withName("foo") - .withConfig( - new ExperimentalMeterConfigModel().withEnabled(true))))) - .withExemplarFilter(MeterProviderModel.ExemplarFilter.ALWAYS_ON), - setMeterConfigurator( - SdkMeterProvider.builder(), - ScopeConfigurator.builder() - .setDefault(MeterConfig.disabled()) - .addCondition( - ScopeConfiguratorBuilder.nameMatchesGlob("foo"), MeterConfig.enabled()) - .build()) - .setExemplarFilter(ExemplarFilter.alwaysOn()) - .registerMetricReader( - PeriodicMetricReader.builder( - OtlpHttpMetricExporter.builder().setComponentLoader(context).build()) - .build()) - .registerView( - InstrumentSelector.builder().setName("instrument-name").build(), - View.builder().setName("stream-name").build()) - .build())); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java deleted file mode 100644 index 62e48f337f7..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.exporter.logging.LoggingMetricExporter; -import io.opentelemetry.exporter.logging.otlp.internal.metrics.OtlpStdoutMetricExporter; -import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; -import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.sdk.extension.incubator.fileconfig.component.MetricExporterComponentProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalOtlpFileMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.GrpcTlsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HttpTlsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpGrpcMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterPropertyModel; -import io.opentelemetry.sdk.metrics.Aggregation; -import io.opentelemetry.sdk.metrics.InstrumentType; -import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; -import io.opentelemetry.sdk.metrics.export.DefaultAggregationSelector; -import io.opentelemetry.sdk.metrics.export.MetricExporter; -import java.io.Closeable; -import java.io.IOException; -import java.nio.file.Path; -import java.security.cert.CertificateEncodingException; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.api.io.TempDir; - -class MetricExporterFactoryTest { - - @RegisterExtension - static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension(); - - @RegisterExtension - static final SelfSignedCertificateExtension clientTls = new SelfSignedCertificateExtension(); - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - private CapturingComponentLoader capturingComponentLoader; - private DeclarativeConfigContext context; - - @BeforeEach - void setup() { - capturingComponentLoader = new CapturingComponentLoader(); - context = new DeclarativeConfigContext(capturingComponentLoader); - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @Test - void create_OtlpHttpDefaults() { - List closeables = new ArrayList<>(); - OtlpHttpMetricExporter expectedExporter = - OtlpHttpMetricExporter.getDefault().toBuilder() - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - MetricExporter exporter = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel().withOtlpHttp(new OtlpHttpMetricExporterModel()), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_http"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("protocol")).isNull(); - assertThat(configProperties.getString("endpoint")).isNull(); - assertThat(configProperties.getStructured("headers")).isNull(); - assertThat(configProperties.getString("compression")).isNull(); - assertThat(configProperties.getInt("timeout")).isNull(); - assertThat(configProperties.getString("certificate_file")).isNull(); - assertThat(configProperties.getString("client_key_file")).isNull(); - assertThat(configProperties.getString("client_certificate_file")).isNull(); - assertThat(configProperties.getString("temporality_preference")).isNull(); - assertThat(configProperties.getString("default_histogram_aggregation")).isNull(); - } - - @Test - void create_OtlpHttpConfigured(@TempDir Path tempDir) - throws CertificateEncodingException, IOException { - List closeables = new ArrayList<>(); - OtlpHttpMetricExporter expectedExporter = - OtlpHttpMetricExporter.builder() - .setEndpoint("http://example:4318/v1/metrics") - .addHeader("key1", "value1") - .addHeader("key2", "value2") - .setTimeout(Duration.ofSeconds(15)) - .setCompression("gzip") - .setAggregationTemporalitySelector(AggregationTemporalitySelector.deltaPreferred()) - .setDefaultAggregationSelector( - DefaultAggregationSelector.getDefault() - .with(InstrumentType.HISTOGRAM, Aggregation.base2ExponentialBucketHistogram())) - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - // Write certificates to temp files - String certificatePath = - createTempFileWithContent( - tempDir, "certificate.cert", serverTls.certificate().getEncoded()); - String clientKeyPath = - createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); - String clientCertificatePath = - createTempFileWithContent( - tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); - - MetricExporter exporter = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel() - .withOtlpHttp( - new OtlpHttpMetricExporterModel() - .withEndpoint("http://example:4318/v1/metrics") - .withHeaders( - Arrays.asList( - new NameStringValuePairModel() - .withName("key1") - .withValue("value1"), - new NameStringValuePairModel() - .withName("key2") - .withValue("value2"))) - .withCompression("gzip") - .withTimeout(15_000) - .withTls( - new HttpTlsModel() - .withCaFile(certificatePath) - .withKeyFile(clientKeyPath) - .withCertFile(clientCertificatePath)) - .withTemporalityPreference( - OtlpHttpMetricExporterModel.ExporterTemporalityPreference.DELTA) - .withDefaultHistogramAggregation( - OtlpHttpMetricExporterModel.ExporterDefaultHistogramAggregation - .BASE_2_EXPONENTIAL_BUCKET_HISTOGRAM)), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_http"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/metrics"); - List headers = configProperties.getStructuredList("headers"); - assertThat(headers) - .isNotNull() - .satisfiesExactly( - header -> { - assertThat(header.getString("name")).isEqualTo("key1"); - assertThat(header.getString("value")).isEqualTo("value1"); - }, - header -> { - assertThat(header.getString("name")).isEqualTo("key2"); - assertThat(header.getString("value")).isEqualTo("value2"); - }); - assertThat(configProperties.getString("compression")).isEqualTo("gzip"); - assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - assertThat(configProperties.getString("temporality_preference")).isEqualTo("delta"); - assertThat(configProperties.getString("default_histogram_aggregation")) - .isEqualTo("base2_exponential_bucket_histogram"); - DeclarativeConfigProperties tls = configProperties.getStructured("tls"); - assertThat(tls).isNotNull(); - assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); - assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); - assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); - } - - @Test - void create_OtlpGrpcDefaults() { - List closeables = new ArrayList<>(); - OtlpGrpcMetricExporter expectedExporter = - OtlpGrpcMetricExporter.getDefault().toBuilder() - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - MetricExporter exporter = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel().withOtlpGrpc(new OtlpGrpcMetricExporterModel()), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_grpc"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isNull(); - assertThat(configProperties.getStructured("headers")).isNull(); - assertThat(configProperties.getString("compression")).isNull(); - assertThat(configProperties.getInt("timeout")).isNull(); - assertThat(configProperties.getString("certificate_file")).isNull(); - assertThat(configProperties.getString("client_key_file")).isNull(); - assertThat(configProperties.getString("client_certificate_file")).isNull(); - assertThat(configProperties.getString("temporality_preference")).isNull(); - assertThat(configProperties.getString("default_histogram_aggregation")).isNull(); - } - - @Test - void create_OtlpGrpcConfigured(@TempDir Path tempDir) - throws CertificateEncodingException, IOException { - List closeables = new ArrayList<>(); - OtlpGrpcMetricExporter expectedExporter = - OtlpGrpcMetricExporter.builder() - .setEndpoint("http://example:4317") - .addHeader("key1", "value1") - .addHeader("key2", "value2") - .setTimeout(Duration.ofSeconds(15)) - .setCompression("gzip") - .setAggregationTemporalitySelector(AggregationTemporalitySelector.deltaPreferred()) - .setDefaultAggregationSelector( - DefaultAggregationSelector.getDefault() - .with(InstrumentType.HISTOGRAM, Aggregation.base2ExponentialBucketHistogram())) - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - // Write certificates to temp files - String certificatePath = - createTempFileWithContent( - tempDir, "certificate.cert", serverTls.certificate().getEncoded()); - String clientKeyPath = - createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); - String clientCertificatePath = - createTempFileWithContent( - tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); - - MetricExporter exporter = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel() - .withOtlpGrpc( - new OtlpGrpcMetricExporterModel() - .withEndpoint("http://example:4317") - .withHeaders( - Arrays.asList( - new NameStringValuePairModel() - .withName("key1") - .withValue("value1"), - new NameStringValuePairModel() - .withName("key2") - .withValue("value2"))) - .withCompression("gzip") - .withTimeout(15_000) - .withTls( - new GrpcTlsModel() - .withCaFile(certificatePath) - .withKeyFile(clientKeyPath) - .withCertFile(clientCertificatePath)) - .withTemporalityPreference( - OtlpHttpMetricExporterModel.ExporterTemporalityPreference.DELTA) - .withDefaultHistogramAggregation( - OtlpHttpMetricExporterModel.ExporterDefaultHistogramAggregation - .BASE_2_EXPONENTIAL_BUCKET_HISTOGRAM)), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_grpc"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4317"); - List headers = configProperties.getStructuredList("headers"); - assertThat(headers) - .isNotNull() - .satisfiesExactly( - header -> { - assertThat(header.getString("name")).isEqualTo("key1"); - assertThat(header.getString("value")).isEqualTo("value1"); - }, - header -> { - assertThat(header.getString("name")).isEqualTo("key2"); - assertThat(header.getString("value")).isEqualTo("value2"); - }); - assertThat(configProperties.getString("compression")).isEqualTo("gzip"); - assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - assertThat(configProperties.getString("temporality_preference")).isEqualTo("delta"); - assertThat(configProperties.getString("default_histogram_aggregation")) - .isEqualTo("base2_exponential_bucket_histogram"); - DeclarativeConfigProperties tls = configProperties.getStructured("tls"); - assertThat(tls).isNotNull(); - assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); - assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); - assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); - } - - @Test - void create_Console() { - List closeables = new ArrayList<>(); - LoggingMetricExporter expectedExporter = LoggingMetricExporter.create(); - cleanup.addCloseable(expectedExporter); - - MetricExporter exporter = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel().withConsole(new ConsoleMetricExporterModel()), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - } - - @Test - void create_OtlpFile() { - List closeables = new ArrayList<>(); - OtlpStdoutMetricExporter expectedExporter = OtlpStdoutMetricExporter.builder().build(); - cleanup.addCloseable(expectedExporter); - - MetricExporter exporter = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel() - .withOtlpFileDevelopment(new ExperimentalOtlpFileMetricExporterModel()), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_file/development"); - assertThat(configProperties).isNotNull(); - } - - @Test - void create_SpiExporter_Unknown() { - assertThatThrownBy( - () -> - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel() - .withAdditionalProperty( - "unknown_key", - new PushMetricExporterPropertyModel() - .withAdditionalProperty("key1", "value1")), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage( - "No component provider detected for io.opentelemetry.sdk.metrics.export.MetricExporter with name \"unknown_key\"."); - } - - @Test - void create_SpiExporter_Valid() { - MetricExporter metricExporter = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel() - .withAdditionalProperty( - "test", - new PushMetricExporterPropertyModel() - .withAdditionalProperty("key1", "value1")), - context); - assertThat(metricExporter) - .isInstanceOf(MetricExporterComponentProvider.TestMetricExporter.class); - assertThat( - ((MetricExporterComponentProvider.TestMetricExporter) metricExporter) - .config.getString("key1")) - .isEqualTo("value1"); - } - - @Test - void create_Customizer() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addMetricExporterCustomizer( - MetricExporter.class, (exporter, properties) -> LoggingMetricExporter.create()); - - MetricExporter result = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel().withConsole(new ConsoleMetricExporterModel()), - context); - cleanup.addCloseable(result); - - assertThat(result).isInstanceOf(LoggingMetricExporter.class); - } - - @Test - void create_Customizer_TypeSafe() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addMetricExporterCustomizer( - OtlpGrpcMetricExporter.class, - (exporter, properties) -> - exporter.toBuilder().setTimeout(Duration.ofSeconds(42)).build()); - - MetricExporter result = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel().withOtlpGrpc(new OtlpGrpcMetricExporterModel()), - context); - cleanup.addCloseable(result); - - assertThat(result).isInstanceOf(OtlpGrpcMetricExporter.class); - assertThat(result.toString()).contains("timeoutNanos=42000000000"); - } - - @Test - void create_Customizer_TypeMismatch() { - AtomicInteger callCount = new AtomicInteger(0); - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addMetricExporterCustomizer( - OtlpGrpcMetricExporter.class, - (exporter, properties) -> { - callCount.incrementAndGet(); - return exporter; - }); - - MetricExporter result = - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel().withConsole(new ConsoleMetricExporterModel()), - context); - cleanup.addCloseable(result); - - assertThat(callCount.get()).isEqualTo(0); - } - - @Test - void create_Customizer_ReturnsNull() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addMetricExporterCustomizer(MetricExporter.class, (exporter, properties) -> null); - - assertThatThrownBy( - () -> - MetricExporterFactory.getInstance() - .create( - new PushMetricExporterModel().withConsole(new ConsoleMetricExporterModel()), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessageContaining("Customizer returned null for MetricExporter: console"); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java deleted file mode 100644 index 3882003aa8d..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import io.github.netmikey.logunit.api.LogCapturer; -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; -import io.opentelemetry.exporter.prometheus.PrometheusHttpServer; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.CardinalityLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalPrometheusMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricReaderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; -import io.opentelemetry.sdk.metrics.InstrumentType; -import io.opentelemetry.sdk.metrics.export.MetricReader; -import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; -import java.io.Closeable; -import java.io.IOException; -import java.net.ServerSocket; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -class MetricReaderFactoryTest { - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - @RegisterExtension - LogCapturer logCapturer = - LogCapturer.create().captureForLogger(DeclarativeConfiguration.class.getName()); - - private final DeclarativeConfigContext context = - spy( - new DeclarativeConfigContext( - ComponentLoader.forClassLoader(getClass().getClassLoader()))); - - @BeforeEach - void setup() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @Test - void create_PeriodicNullExporter() { - assertThatThrownBy( - () -> - MetricReaderFactory.getInstance() - .create( - new MetricReaderModel().withPeriodic(new PeriodicMetricReaderModel()), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage("periodic metric reader exporter is required but is null"); - } - - @Test - void create_PeriodicDefaults() { - List closeables = new ArrayList<>(); - PeriodicMetricReader expectedReader = - PeriodicMetricReader.builder( - OtlpHttpMetricExporter.builder().setComponentLoader(context).build()) - .build(); - cleanup.addCloseable(expectedReader); - - MetricReaderAndCardinalityLimits readerAndCardinalityLimits = - MetricReaderFactory.getInstance() - .create( - new MetricReaderModel() - .withPeriodic( - new PeriodicMetricReaderModel() - .withExporter( - new PushMetricExporterModel() - .withOtlpHttp(new OtlpHttpMetricExporterModel()))), - context); - MetricReader reader = readerAndCardinalityLimits.getMetricReader(); - cleanup.addCloseable(reader); - cleanup.addCloseables(closeables); - - assertThat(reader.toString()).isEqualTo(expectedReader.toString()); - assertThat(readerAndCardinalityLimits.getCardinalityLimitsSelector()).isNull(); - } - - @Test - void create_PeriodicConfigured() { - List closeables = new ArrayList<>(); - MetricReader expectedReader = - PeriodicMetricReader.builder( - OtlpHttpMetricExporter.builder().setComponentLoader(context).build()) - .setInterval(Duration.ofMillis(1)) - .build(); - cleanup.addCloseable(expectedReader); - - MetricReaderAndCardinalityLimits readerAndCardinalityLimits = - MetricReaderFactory.getInstance() - .create( - new MetricReaderModel() - .withPeriodic( - new PeriodicMetricReaderModel() - .withExporter( - new PushMetricExporterModel() - .withOtlpHttp(new OtlpHttpMetricExporterModel())) - .withInterval(1) - .withCardinalityLimits(new CardinalityLimitsModel().withDefault(100))), - context); - MetricReader reader = readerAndCardinalityLimits.getMetricReader(); - cleanup.addCloseable(reader); - cleanup.addCloseables(closeables); - - assertThat(reader.toString()).isEqualTo(expectedReader.toString()); - assertThat( - readerAndCardinalityLimits - .getCardinalityLimitsSelector() - .getCardinalityLimit(InstrumentType.COUNTER)) - .isEqualTo(100); - } - - @Test - void create_PullPrometheusDefault() throws IOException { - int port = randomAvailablePort(); - List closeables = new ArrayList<>(); - PrometheusHttpServer expectedReader = PrometheusHttpServer.builder().setPort(port).build(); - // Close the reader to avoid port conflict with the new instance created by MetricReaderFactory - expectedReader.close(); - - MetricReaderAndCardinalityLimits readerAndCardinalityLimits = - MetricReaderFactory.getInstance() - .create( - new MetricReaderModel() - .withPull( - new PullMetricReaderModel() - .withExporter( - new PullMetricExporterModel() - .withPrometheusDevelopment( - new ExperimentalPrometheusMetricExporterModel() - .withPort(port)))), - context); - MetricReader reader = readerAndCardinalityLimits.getMetricReader(); - cleanup.addCloseable(reader); - cleanup.addCloseables(closeables); - - assertThat(reader.toString()).isEqualTo(expectedReader.toString()); - assertThat(readerAndCardinalityLimits.getCardinalityLimitsSelector()).isNull(); - // TODO(jack-berg): validate prometheus component provider was invoked with correct arguments - verify(context).loadComponent(eq(MetricReader.class), any(ConfigKeyValue.class)); - } - - @Test - void create_PullPrometheusConfigured() throws IOException { - int port = randomAvailablePort(); - - List closeables = new ArrayList<>(); - PrometheusHttpServer expectedReader = - PrometheusHttpServer.builder() - .setHost("localhost") - .setPort(port) - .setAllowedResourceAttributesFilter( - IncludeExcludePredicate.createPatternMatching( - singletonList("foo"), singletonList("bar"))) - .build(); - // Close the reader to avoid port conflict with the new instance created by MetricReaderFactory - expectedReader.close(); - - MetricReaderAndCardinalityLimits readerAndCardinalityLimits = - MetricReaderFactory.getInstance() - .create( - new MetricReaderModel() - .withPull( - new PullMetricReaderModel() - .withCardinalityLimits(new CardinalityLimitsModel().withDefault(100)) - .withExporter( - new PullMetricExporterModel() - .withPrometheusDevelopment( - new ExperimentalPrometheusMetricExporterModel() - .withHost("localhost") - .withPort(port) - .withWithResourceConstantLabels( - new IncludeExcludeModel() - .withIncluded(singletonList("foo")) - .withExcluded(singletonList("bar"))) - .withWithoutScopeInfo(false) - .withWithoutTargetInfoDevelopment(false) - .withTranslationStrategy( - ExperimentalPrometheusMetricExporterModel - .ExperimentalPrometheusTranslationStrategy - .UNDERSCORE_ESCAPING_WITHOUT_SUFFIXES_DEVELOPMENT)))), - context); - MetricReader reader = readerAndCardinalityLimits.getMetricReader(); - cleanup.addCloseable(reader); - cleanup.addCloseables(closeables); - - assertThat(reader.toString()).isEqualTo(expectedReader.toString()); - assertThat( - readerAndCardinalityLimits - .getCardinalityLimitsSelector() - .getCardinalityLimit(InstrumentType.COUNTER)) - .isEqualTo(100); - // TODO(jack-berg): validate prometheus component provider was invoked with correct arguments - verify(context).loadComponent(eq(MetricReader.class), any(ConfigKeyValue.class)); - } - - @Test - void create_InvalidPullReader() { - assertThatThrownBy( - () -> - MetricReaderFactory.getInstance() - .create(new MetricReaderModel().withPull(new PullMetricReaderModel()), context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage("pull metric reader exporter is required but is null"); - - assertThatThrownBy( - () -> - MetricReaderFactory.getInstance() - .create( - new MetricReaderModel() - .withPull( - new PullMetricReaderModel() - .withExporter(new PullMetricExporterModel())), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage("metric reader must have exactly one entry but has 0"); - } - - /** - * Find a random unused port. There's a small race if another process takes it before we - * initialize. Consider adding retries to this test if it flakes, presumably it never will on CI - * since there's no prometheus there blocking the well-known port. - */ - private static int randomAvailablePort() throws IOException { - try (ServerSocket socket2 = new ServerSocket(0)) { - return socket2.getLocalPort(); - } - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java deleted file mode 100644 index 0b822a4d983..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/OpenTelemetryConfigurationFactoryTest.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import io.github.netmikey.logunit.api.LogCapturer; -import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.context.propagation.TextMapPropagator; -import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; -import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter; -import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; -import io.opentelemetry.extension.trace.propagation.B3Propagator; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.internal.testing.slf4j.SuppressLogger; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchLogRecordProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LoggerProviderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MeterProviderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PropagatorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleLogRecordProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewSelectorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewStreamModel; -import io.opentelemetry.sdk.internal.ExtendedOpenTelemetrySdk; -import io.opentelemetry.sdk.internal.OpenTelemetrySdkBuilderUtil; -import io.opentelemetry.sdk.internal.SdkConfigProvider; -import io.opentelemetry.sdk.logs.LogLimits; -import io.opentelemetry.sdk.logs.SdkLoggerProvider; -import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; -import io.opentelemetry.sdk.metrics.InstrumentSelector; -import io.opentelemetry.sdk.metrics.SdkMeterProvider; -import io.opentelemetry.sdk.metrics.View; -import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; -import io.opentelemetry.sdk.resources.Resource; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.SpanLimits; -import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; -import java.io.Closeable; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.slf4j.event.Level; - -class OpenTelemetryConfigurationFactoryTest { - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - @RegisterExtension - LogCapturer logCapturer = - LogCapturer.create() - .captureForLogger(OpenTelemetryConfigurationFactory.class.getName(), Level.WARN); - - private final DeclarativeConfigContext context = - new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); - - @BeforeEach - void setup() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @ParameterizedTest - @MethodSource("fileFormatArgs") - @SuppressLogger(OpenTelemetryConfigurationFactory.class) - void create_FileFormat(String fileFormat, boolean isValid) { - OpenTelemetryConfigurationModel model = - new OpenTelemetryConfigurationModel().withFileFormat(fileFormat); - - if (isValid) { - assertThatCode(() -> OpenTelemetryConfigurationFactory.getInstance().create(model, context)) - .doesNotThrowAnyException(); - } else { - assertThatThrownBy( - () -> OpenTelemetryConfigurationFactory.getInstance().create(model, context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessageMatching( - "Unsupported file format '.+'\\. Supported formats include 0\\.4, 1\\.0\\*"); - } - } - - private static Stream fileFormatArgs() { - return Stream.of( - // Invalid file formats - Arguments.of(null, false), - Arguments.of("0.3", false), - Arguments.of("a0.4", false), - Arguments.of("0.4a", false), - Arguments.of("foo", false), - Arguments.of("1.0-rc.a", false), - Arguments.of("1.0.0", false), - Arguments.of("1.0.3", false), - Arguments.of("1.0.0-rc.3", false), - // Valid file formats - Arguments.of("0.4", true), - Arguments.of("1.0-rc.1", true), - Arguments.of("1.0-rc.2", true), - Arguments.of("1.0-rc.3", true), - Arguments.of("1.0", true)); - } - - @Test - void create_FileFormatVersionMismatch_LogsWarning() { - OpenTelemetryConfigurationModel model = - new OpenTelemetryConfigurationModel().withFileFormat("1.0-rc.3"); - - ExtendedOpenTelemetrySdk sdk = - OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); - cleanup.addCloseable(sdk); - - logCapturer.assertContains( - "Configuration file_format '1.0-rc.3' does not exactly match expected version '1.0'"); - } - - @Test - void create_FileFormatExactMatch_NoWarning() { - OpenTelemetryConfigurationModel model = - new OpenTelemetryConfigurationModel().withFileFormat("1.0"); - - ExtendedOpenTelemetrySdk sdk = - OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); - cleanup.addCloseable(sdk); - - assertThat(logCapturer.size()).isEqualTo(0); - } - - @Test - void create_Defaults() { - List closeables = new ArrayList<>(); - OpenTelemetryConfigurationModel model = - new OpenTelemetryConfigurationModel().withFileFormat("1.0"); - OpenTelemetrySdk expectedSdk = - OpenTelemetrySdkBuilderUtil.setConfigProvider( - OpenTelemetrySdk.builder(), - SdkConfigProvider.create(DeclarativeConfigurationParser.toConfigProperties(model))) - .build(); - cleanup.addCloseable(expectedSdk); - - ExtendedOpenTelemetrySdk sdk = - OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); - cleanup.addCloseable(sdk); - cleanup.addCloseables(closeables); - - assertThat(sdk).hasToString(expectedSdk.toString()); - } - - @Test - void create_Disabled() { - List closeables = new ArrayList<>(); - OpenTelemetryConfigurationModel model = - new OpenTelemetryConfigurationModel() - .withFileFormat("1.0") - .withDisabled(true) - // Logger provider configuration should be ignored since SDK is disabled - .withLoggerProvider( - new LoggerProviderModel() - .withProcessors( - Collections.singletonList( - new LogRecordProcessorModel() - .withSimple( - new SimpleLogRecordProcessorModel() - .withExporter( - new LogRecordExporterModel() - .withOtlpHttp(new OtlpHttpExporterModel())))))); - OpenTelemetrySdk expectedSdk = - OpenTelemetrySdkBuilderUtil.setConfigProvider( - OpenTelemetrySdk.builder(), - SdkConfigProvider.create(DeclarativeConfigurationParser.toConfigProperties(model))) - .build(); - cleanup.addCloseable(expectedSdk); - - ExtendedOpenTelemetrySdk sdk = - OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); - cleanup.addCloseable(sdk); - cleanup.addCloseables(closeables); - - assertThat(sdk).hasToString(expectedSdk.toString()); - } - - @Test - void create_Configured() throws NoSuchFieldException { - List closeables = new ArrayList<>(); - Resource expectedResource = - Resource.getDefault().toBuilder() - .put("service.name", "my-service") - .put("key", "val") - // resource attributes from resource ComponentProviders - .put("color", "red") - .put("shape", "square") - .put("order", "second") - .build(); - - OpenTelemetryConfigurationModel model = - new OpenTelemetryConfigurationModel() - .withFileFormat("1.0") - .withPropagator( - new PropagatorModel().withCompositeList("tracecontext,baggage,b3multi,b3")) - .withResource( - new ResourceModel() - .withDetectionDevelopment( - new ExperimentalResourceDetectionModel() - .withDetectors( - Arrays.asList( - new ExperimentalResourceDetectorModel() - .withAdditionalProperty("order_first", null), - new ExperimentalResourceDetectorModel() - .withAdditionalProperty("order_second", null), - new ExperimentalResourceDetectorModel() - .withAdditionalProperty("shape_color", null)))) - .withAttributes( - Arrays.asList( - new AttributeNameValueModel() - .withName("service.name") - .withValue("my-service"), - new AttributeNameValueModel().withName("key").withValue("val")))) - .withLoggerProvider( - new LoggerProviderModel() - .withLimits( - new LogRecordLimitsModel() - .withAttributeValueLengthLimit(1) - .withAttributeCountLimit(2)) - .withProcessors( - Collections.singletonList( - new LogRecordProcessorModel() - .withBatch( - new BatchLogRecordProcessorModel() - .withExporter( - new LogRecordExporterModel() - .withOtlpHttp(new OtlpHttpExporterModel())))))) - .withTracerProvider( - new TracerProviderModel() - .withLimits( - new SpanLimitsModel() - .withAttributeCountLimit(1) - .withAttributeValueLengthLimit(2) - .withEventCountLimit(3) - .withLinkCountLimit(4) - .withEventAttributeCountLimit(5) - .withLinkAttributeCountLimit(6)) - .withSampler(new SamplerModel().withAlwaysOn(new AlwaysOnSamplerModel())) - .withProcessors( - Collections.singletonList( - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel() - .withOtlpHttp(new OtlpHttpExporterModel())))))) - .withMeterProvider( - new MeterProviderModel() - .withReaders( - Collections.singletonList( - new MetricReaderModel() - .withPeriodic( - new PeriodicMetricReaderModel() - .withExporter( - new PushMetricExporterModel() - .withOtlpHttp(new OtlpHttpMetricExporterModel()))))) - .withViews( - Collections.singletonList( - new ViewModel() - .withSelector( - new ViewSelectorModel().withInstrumentName("instrument-name")) - .withStream( - new ViewStreamModel() - .withName("stream-name") - .withAttributeKeys(null))))); - - OpenTelemetrySdk expectedSdk = - OpenTelemetrySdkBuilderUtil.setConfigProvider( - OpenTelemetrySdk.builder() - .setPropagators( - ContextPropagators.create( - TextMapPropagator.composite( - W3CTraceContextPropagator.getInstance(), - W3CBaggagePropagator.getInstance(), - B3Propagator.injectingMultiHeaders(), - B3Propagator.injectingSingleHeader()))) - .setLoggerProvider( - SdkLoggerProvider.builder() - .setResource(expectedResource) - .setLogLimits( - () -> - LogLimits.builder() - .setMaxAttributeValueLength(1) - .setMaxNumberOfAttributes(2) - .build()) - .addLogRecordProcessor( - BatchLogRecordProcessor.builder( - OtlpHttpLogRecordExporter.builder() - .setComponentLoader(context) - .build()) - .build()) - .build()) - .setTracerProvider( - SdkTracerProvider.builder() - .setResource(expectedResource) - .setSpanLimits( - SpanLimits.builder() - .setMaxNumberOfAttributes(1) - .setMaxAttributeValueLength(2) - .setMaxNumberOfEvents(3) - .setMaxNumberOfLinks(4) - .setMaxNumberOfAttributesPerEvent(5) - .setMaxNumberOfAttributesPerLink(6) - .build()) - .setSampler(alwaysOn()) - .addSpanProcessor( - BatchSpanProcessor.builder( - OtlpHttpSpanExporter.builder() - .setComponentLoader(context) - .build()) - .build()) - .build()) - .setMeterProvider( - SdkMeterProvider.builder() - .setResource(expectedResource) - .registerMetricReader( - PeriodicMetricReader.builder( - OtlpHttpMetricExporter.builder() - .setComponentLoader(context) - .build()) - .build()) - .registerView( - InstrumentSelector.builder().setName("instrument-name").build(), - View.builder().setName("stream-name").build()) - .build()), - SdkConfigProvider.create(DeclarativeConfigurationParser.toConfigProperties(model))) - .build(); - - cleanup.addCloseable(expectedSdk); - - ExtendedOpenTelemetrySdk sdk = - OpenTelemetryConfigurationFactory.getInstance().create(model, context).getSdk(); - cleanup.addCloseable(sdk); - cleanup.addCloseables(closeables); - - assertThat(sdk).hasToString(expectedSdk.toString()); - - // test that the meter provider is wired through to the tracer and logger providers - Field field = SdkMeterProvider.class.getDeclaredField("sharedState"); - field.setAccessible(true); - - // Lazily initialized - assertThat(sdk) - .extracting("loggerProvider") - .extracting("delegate") - .extracting("sharedState") - .extracting("logRecordProcessor") - .extracting("worker") - .extracting("logProcessorInstrumentation") - .extracting("processedLogs") - .isNull(); - - // Lazily initialized - assertThat(sdk) - .extracting("tracerProvider") - .extracting("delegate") - .extracting("sharedState") - .extracting("activeSpanProcessor") - .extracting("worker") - .extracting("spanProcessorInstrumentation") - .extracting("processedSpans") - .isNull(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java deleted file mode 100644 index d3072f4aa31..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/PropagatorFactoryTest.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.context.propagation.TextMapPropagator; -import io.opentelemetry.extension.trace.propagation.B3Propagator; -import io.opentelemetry.sdk.extension.incubator.fileconfig.component.TextMapPropagatorComponentProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.B3MultiPropagatorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.B3PropagatorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BaggagePropagatorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PropagatorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TextMapPropagatorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TraceContextPropagatorModel; -import java.util.Arrays; -import java.util.Collections; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class PropagatorFactoryTest { - - private final DeclarativeConfigContext context = - new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); - - @ParameterizedTest - @MethodSource("createArguments") - void create(PropagatorModel model, ContextPropagators expectedPropagators) { - ContextPropagators propagators = PropagatorFactory.getInstance().create(model, context); - - assertThat(propagators.toString()).isEqualTo(expectedPropagators.toString()); - } - - private static Stream createArguments() { - return Stream.of( - // structured list - Arguments.of( - new PropagatorModel() - .withComposite( - Arrays.asList( - new TextMapPropagatorModel() - .withTracecontext(new TraceContextPropagatorModel()), - new TextMapPropagatorModel().withBaggage(new BaggagePropagatorModel()), - new TextMapPropagatorModel().withB3multi(new B3MultiPropagatorModel()), - new TextMapPropagatorModel().withB3(new B3PropagatorModel()))), - ContextPropagators.create( - TextMapPropagator.composite( - W3CTraceContextPropagator.getInstance(), - W3CBaggagePropagator.getInstance(), - B3Propagator.injectingMultiHeaders(), - B3Propagator.injectingSingleHeader()))), - // string list - Arguments.of( - new PropagatorModel().withCompositeList("tracecontext,baggage,b3multi,b3 ,none"), - ContextPropagators.create( - TextMapPropagator.composite( - W3CTraceContextPropagator.getInstance(), - W3CBaggagePropagator.getInstance(), - B3Propagator.injectingMultiHeaders(), - B3Propagator.injectingSingleHeader()))), - // structured list and string list - Arguments.of( - new PropagatorModel() - .withComposite( - Arrays.asList( - new TextMapPropagatorModel() - .withTracecontext(new TraceContextPropagatorModel()), - new TextMapPropagatorModel().withBaggage(new BaggagePropagatorModel()))) - .withCompositeList("b3multi,b3"), - ContextPropagators.create( - TextMapPropagator.composite( - W3CTraceContextPropagator.getInstance(), - W3CBaggagePropagator.getInstance(), - B3Propagator.injectingMultiHeaders(), - B3Propagator.injectingSingleHeader()))), - // structured list and string list with overlap - Arguments.of( - new PropagatorModel() - .withComposite( - Arrays.asList( - new TextMapPropagatorModel() - .withTracecontext(new TraceContextPropagatorModel()), - new TextMapPropagatorModel().withBaggage(new BaggagePropagatorModel()))) - .withCompositeList("tracecontext,b3multi,b3"), - ContextPropagators.create( - TextMapPropagator.composite( - W3CTraceContextPropagator.getInstance(), - W3CBaggagePropagator.getInstance(), - B3Propagator.injectingMultiHeaders(), - B3Propagator.injectingSingleHeader()))), - // spi - Arguments.of( - new PropagatorModel() - .withComposite( - Collections.singletonList( - new TextMapPropagatorModel().withAdditionalProperty("test", null))), - ContextPropagators.create( - TextMapPropagator.composite( - new TextMapPropagatorComponentProvider.TestTextMapPropagator( - DeclarativeConfigProperties.empty())))), - Arguments.of( - new PropagatorModel().withCompositeList("test"), - ContextPropagators.create( - TextMapPropagator.composite( - new TextMapPropagatorComponentProvider.TestTextMapPropagator( - DeclarativeConfigProperties.empty()))))); - } - - @Test - void create_SpiPropagator_Unknown() { - assertThatThrownBy( - () -> - PropagatorFactory.getInstance() - .create(new PropagatorModel().withCompositeList("foo"), context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage( - "No component provider detected for io.opentelemetry.context.propagation.TextMapPropagator with name \"foo\"."); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java deleted file mode 100644 index 4b74b25c382..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel; -import io.opentelemetry.sdk.resources.Resource; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Stream; -import javax.annotation.Nullable; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class ResourceFactoryTest { - - private final DeclarativeConfigContext context = - new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); - - @ParameterizedTest - @MethodSource("createArgs") - void create(ResourceModel model, Resource expectedResource) { - assertThat(ResourceFactory.getInstance().create(model, context)).isEqualTo(expectedResource); - } - - private static Stream createArgs() { - return Stream.of( - Arguments.of( - new ResourceModel() - .withAttributes( - Arrays.asList( - new AttributeNameValueModel() - .withName("service.name") - .withValue("my-service"), - new AttributeNameValueModel().withName("key").withValue("val"), - new AttributeNameValueModel().withName("shape").withValue("circle"))), - Resource.getDefault().toBuilder() - .put("shape", "circle") - .put("service.name", "my-service") - .put("key", "val") - .build()), - Arguments.of( - new ResourceModel().withSchemaUrl("http://foo"), - Resource.getDefault().toBuilder().setSchemaUrl("http://foo").build()), - Arguments.of( - new ResourceModel().withAttributesList("key1=val1,key2=val2"), - Resource.getDefault().toBuilder().put("key1", "val1").put("key2", "val2").build())); - } - - @ParameterizedTest - @MethodSource("createWithDetectorsArgs") - void createWithDetectors( - @Nullable List included, @Nullable List excluded, Resource expectedResource) { - ResourceModel resourceModel = - new ResourceModel() - .withDetectionDevelopment( - new ExperimentalResourceDetectionModel() - .withDetectors( - Arrays.asList( - new ExperimentalResourceDetectorModel() - .withAdditionalProperty("order_first", null), - new ExperimentalResourceDetectorModel() - .withAdditionalProperty("order_second", null), - new ExperimentalResourceDetectorModel() - .withAdditionalProperty("shape_color", null))) - .withAttributes( - new IncludeExcludeModel().withIncluded(included).withExcluded(excluded))); - Resource resource = ResourceFactory.getInstance().create(resourceModel, context); - assertThat(resource).isEqualTo(expectedResource); - } - - private static Stream createWithDetectorsArgs() { - return Stream.of( - Arguments.of( - null, - null, - Resource.getDefault().toBuilder() - .put("color", "red") - .put("shape", "square") - .put("order", "second") - .build()), - Arguments.of( - Collections.singletonList("color"), - null, - Resource.getDefault().toBuilder().put("color", "red").build()), - Arguments.of( - Arrays.asList("color", "shape"), - null, - Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build()), - Arguments.of( - null, - Collections.singletonList("color"), - Resource.getDefault().toBuilder() - .put("shape", "square") - .put("order", "second") - .build()), - Arguments.of( - null, - Arrays.asList("color", "shape"), - Resource.getDefault().toBuilder().put("order", "second").build()), - Arguments.of( - Collections.singletonList("color"), - Collections.singletonList("color"), - Resource.getDefault().toBuilder().build()), - Arguments.of( - Arrays.asList("color", "shape"), - Collections.singletonList("color"), - Resource.getDefault().toBuilder().put("shape", "square").build()), - Arguments.of( - Collections.singletonList("c*"), - null, - Resource.getDefault().toBuilder().put("color", "red").build()), - Arguments.of( - Collections.singletonList("c?lor"), - null, - Resource.getDefault().toBuilder().put("color", "red").build()), - Arguments.of( - null, - Collections.singletonList("c*"), - Resource.getDefault().toBuilder() - .put("shape", "square") - .put("order", "second") - .build()), - Arguments.of( - null, - Collections.singletonList("c?lor"), - Resource.getDefault().toBuilder() - .put("shape", "square") - .put("order", "second") - .build()), - Arguments.of( - Collections.singletonList("*o*"), - Collections.singletonList("order"), - Resource.getDefault().toBuilder().put("color", "red").build()), - Arguments.of( - null, - Collections.singletonList("order"), - Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build())); - } - - @ParameterizedTest - @MethodSource("createInvalidDetectorsArgs") - void createWithDetectors_Invalid(ResourceModel model, String expectedMessage) { - assertThatThrownBy(() -> ResourceFactory.getInstance().create(model, context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage(expectedMessage); - } - - private static Stream createInvalidDetectorsArgs() { - return Stream.of( - Arguments.of( - new ResourceModel() - .withDetectionDevelopment( - new ExperimentalResourceDetectionModel() - .withDetectors( - Collections.singletonList( - new ExperimentalResourceDetectorModel() - .withAdditionalProperty("foo", null)))), - "No component provider detected for io.opentelemetry.sdk.resources.Resource with name \"foo\"."), - Arguments.of( - new ResourceModel() - .withDetectionDevelopment( - new ExperimentalResourceDetectionModel() - .withDetectors( - Collections.singletonList( - new ExperimentalResourceDetectorModel() - .withAdditionalProperty("foo", null) - .withAdditionalProperty("bar", null)))), - "resource detector must have exactly one entry but has 2: [foo,bar]"), - Arguments.of( - new ResourceModel() - .withDetectionDevelopment( - new ExperimentalResourceDetectionModel() - .withDetectors( - Collections.singletonList(new ExperimentalResourceDetectorModel()))), - "resource detector must have exactly one entry but has 0"), - Arguments.of( - new ResourceModel() - .withDetectionDevelopment( - new ExperimentalResourceDetectionModel() - .withAttributes( - new IncludeExcludeModel() - .withIncluded(Collections.emptyList()) - .withExcluded(null))), - "included must not be empty"), - Arguments.of( - new ResourceModel() - .withDetectionDevelopment( - new ExperimentalResourceDetectionModel() - .withAttributes( - new IncludeExcludeModel() - .withIncluded(null) - .withExcluded(Collections.emptyList()))), - "excluded must not be empty")); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java deleted file mode 100644 index 52775f1abe4..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * 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.assertThatThrownBy; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.internal.testing.slf4j.SuppressLogger; -import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SamplerComponentProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOffSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableAlwaysOffSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableAlwaysOnSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableParentThresholdSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableProbabilitySamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableRuleBasedSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalJaegerRemoteSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ParentBasedSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerPropertyModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TraceIdRatioBasedSamplerModel; -import io.opentelemetry.sdk.extension.incubator.trace.samplers.ComposableSampler; -import io.opentelemetry.sdk.extension.incubator.trace.samplers.CompositeSampler; -import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler; -import io.opentelemetry.sdk.trace.samplers.ParentBasedSamplerBuilder; -import io.opentelemetry.sdk.trace.samplers.Sampler; -import java.io.Closeable; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; -import javax.annotation.Nullable; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -// Suppress logs from JaegerRemoteSampler -@SuppressLogger( - loggerName = "io.opentelemetry.sdk.extension.trace.jaeger.sampler.OkHttpGrpcService") -@SuppressLogger(ParentBasedSamplerBuilder.class) -@SuppressLogger(JaegerRemoteSampler.class) -class SamplerFactoryTest { - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - private final DeclarativeConfigContext context = - new DeclarativeConfigContext(ComponentLoader.forClassLoader(getClass().getClassLoader())); - - @ParameterizedTest - @MethodSource("createArguments") - void create(@Nullable SamplerModel model, Sampler expectedSampler) { - // Some samplers like JaegerRemoteSampler are Closeable - ensure these get cleaned up - if (expectedSampler instanceof Closeable) { - cleanup.addCloseable((Closeable) expectedSampler); - } - - List closeables = new ArrayList<>(); - Sampler sampler = SamplerFactory.getInstance().create(model, context); - cleanup.addCloseables(closeables); - - assertThat(sampler.toString()).isEqualTo(expectedSampler.toString()); - } - - private static Stream createArguments() { - return Stream.of( - Arguments.of( - new SamplerModel().withAlwaysOn(new AlwaysOnSamplerModel()), Sampler.alwaysOn()), - Arguments.of( - new SamplerModel().withAlwaysOff(new AlwaysOffSamplerModel()), Sampler.alwaysOff()), - Arguments.of( - new SamplerModel().withTraceIdRatioBased(new TraceIdRatioBasedSamplerModel()), - Sampler.traceIdRatioBased(1.0d)), - Arguments.of( - new SamplerModel() - .withTraceIdRatioBased(new TraceIdRatioBasedSamplerModel().withRatio(0.5d)), - Sampler.traceIdRatioBased(0.5)), - Arguments.of( - new SamplerModel().withParentBased(new ParentBasedSamplerModel()), - Sampler.parentBased(Sampler.alwaysOn())), - Arguments.of( - new SamplerModel() - .withParentBased( - new ParentBasedSamplerModel() - .withRoot( - new SamplerModel() - .withTraceIdRatioBased( - new TraceIdRatioBasedSamplerModel().withRatio(0.1d))) - .withRemoteParentSampled( - new SamplerModel() - .withTraceIdRatioBased( - new TraceIdRatioBasedSamplerModel().withRatio(0.2d))) - .withRemoteParentNotSampled( - new SamplerModel() - .withTraceIdRatioBased( - new TraceIdRatioBasedSamplerModel().withRatio(0.3d))) - .withLocalParentSampled( - new SamplerModel() - .withTraceIdRatioBased( - new TraceIdRatioBasedSamplerModel().withRatio(0.4d))) - .withLocalParentNotSampled( - new SamplerModel() - .withTraceIdRatioBased( - new TraceIdRatioBasedSamplerModel().withRatio(0.5d)))), - Sampler.parentBasedBuilder(Sampler.traceIdRatioBased(0.1d)) - .setRemoteParentSampled(Sampler.traceIdRatioBased(0.2d)) - .setRemoteParentNotSampled(Sampler.traceIdRatioBased(0.3d)) - .setLocalParentSampled(Sampler.traceIdRatioBased(0.4d)) - .setLocalParentNotSampled(Sampler.traceIdRatioBased(0.5d)) - .build()), - Arguments.of( - new SamplerModel() - .withJaegerRemoteDevelopment( - new ExperimentalJaegerRemoteSamplerModel() - .withEndpoint("http://jaeger-remote-endpoint") - .withInterval(10_000) - .withInitialSampler( - new SamplerModel().withAlwaysOff(new AlwaysOffSamplerModel()))), - JaegerRemoteSampler.builder() - .setEndpoint("http://jaeger-remote-endpoint") - .setPollingInterval(Duration.ofSeconds(10)) - .setInitialSampler(Sampler.alwaysOff()) - .build()), - Arguments.of( - new SamplerModel() - .withCompositeDevelopment( - new ExperimentalComposableSamplerModel() - .withAlwaysOn(new ExperimentalComposableAlwaysOnSamplerModel())), - CompositeSampler.wrap(ComposableSampler.alwaysOn())), - Arguments.of( - new SamplerModel() - .withCompositeDevelopment( - new ExperimentalComposableSamplerModel() - .withAlwaysOff(new ExperimentalComposableAlwaysOffSamplerModel())), - CompositeSampler.wrap(ComposableSampler.alwaysOff())), - Arguments.of( - new SamplerModel() - .withCompositeDevelopment( - new ExperimentalComposableSamplerModel() - .withProbability( - new ExperimentalComposableProbabilitySamplerModel().withRatio(0.5))), - CompositeSampler.wrap(ComposableSampler.probability(0.5))), - Arguments.of( - new SamplerModel() - .withCompositeDevelopment( - new ExperimentalComposableSamplerModel() - .withRuleBased(new ExperimentalComposableRuleBasedSamplerModel())), - CompositeSampler.wrap(ComposableSampler.ruleBasedBuilder().build())), - Arguments.of( - new SamplerModel() - .withCompositeDevelopment( - new ExperimentalComposableSamplerModel() - .withParentThreshold( - new ExperimentalComposableParentThresholdSamplerModel() - .withRoot( - new ExperimentalComposableSamplerModel() - .withAlwaysOn( - new ExperimentalComposableAlwaysOnSamplerModel())))), - CompositeSampler.wrap( - ComposableSampler.parentThreshold(ComposableSampler.alwaysOn())))); - } - - @ParameterizedTest - @MethodSource("createInvalidArguments") - void createInvalid(SamplerModel model, String expectedMessage) { - assertThatThrownBy(() -> SamplerFactory.getInstance().create(model, context)) - .isInstanceOf(DeclarativeConfigException.class) - .extracting(throwable -> throwable.getCause() == null ? throwable : throwable.getCause()) - .extracting(Throwable::getMessage) - .isEqualTo(expectedMessage); - } - - private static Stream createInvalidArguments() { - return Stream.of( - Arguments.of( - new SamplerModel() - .withJaegerRemoteDevelopment(new ExperimentalJaegerRemoteSamplerModel()), - "jaeger remote sampler endpoint is required"), - Arguments.of( - new SamplerModel() - .withJaegerRemoteDevelopment( - new ExperimentalJaegerRemoteSamplerModel() - .withEndpoint("http://jaeger-remote-endpoint")), - "jaeger remote sampler initial_sampler is required"), - Arguments.of( - new SamplerModel() - .withCompositeDevelopment( - new ExperimentalComposableSamplerModel() - .withParentThreshold( - new ExperimentalComposableParentThresholdSamplerModel())), - "parent threshold sampler root is required but is null")); - } - - @Test - void create_SpiExporter_Unknown() { - List closeables = new ArrayList<>(); - - assertThatThrownBy( - () -> - SamplerFactory.getInstance() - .create( - new SamplerModel() - .withAdditionalProperty( - "unknown_key", - new SamplerPropertyModel() - .withAdditionalProperty("key1", "value1")), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage( - "No component provider detected for io.opentelemetry.sdk.trace.samplers.Sampler with name \"unknown_key\"."); - cleanup.addCloseables(closeables); - } - - @Test - void create_SpiExporter_Valid() { - Sampler sampler = - SamplerFactory.getInstance() - .create( - new SamplerModel() - .withAdditionalProperty( - "test", - new SamplerPropertyModel().withAdditionalProperty("key1", "value1")), - context); - assertThat(sampler).isInstanceOf(SamplerComponentProvider.TestSampler.class); - assertThat(((SamplerComponentProvider.TestSampler) sampler).config.getString("key1")) - .isEqualTo("value1"); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java deleted file mode 100644 index 4778fe1b614..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ServiceResourceDetectorTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.resources.Resource; -import java.util.Objects; -import java.util.UUID; -import org.junit.jupiter.api.Test; -import org.junitpioneer.jupiter.ClearSystemProperty; - -class ServiceResourceDetectorTest { - - @Test - void getTypeAndName() { - ServiceResourceDetector detector = new ServiceResourceDetector(); - - assertThat(detector.getType()).isEqualTo(Resource.class); - assertThat(detector.getName()).isEqualTo("service"); - } - - @Test - @ClearSystemProperty(key = "otel.service.name") - void create_SystemPropertySet() { - System.setProperty("otel.service.name", "test"); - - assertThat(new ServiceResourceDetector().create(DeclarativeConfigProperties.empty())) - .satisfies( - resource -> { - Attributes attributes = resource.getAttributes(); - assertThat(attributes.get(AttributeKey.stringKey("service.name"))).isEqualTo("test"); - assertThatCode( - () -> - UUID.fromString( - Objects.requireNonNull( - attributes.get(AttributeKey.stringKey("service.instance.id"))))) - .doesNotThrowAnyException(); - }); - } - - @Test - void create_NoSystemProperty() { - assertThat(new ServiceResourceDetector().create(DeclarativeConfigProperties.empty())) - .satisfies( - resource -> { - Attributes attributes = resource.getAttributes(); - assertThat(attributes.get(AttributeKey.stringKey("service.name"))).isNull(); - assertThatCode( - () -> - UUID.fromString( - Objects.requireNonNull( - attributes.get(AttributeKey.stringKey("service.instance.id"))))) - .doesNotThrowAnyException(); - }); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java deleted file mode 100644 index 906ced22056..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigTestUtil.createTempFileWithContent; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.exporter.logging.LoggingSpanExporter; -import io.opentelemetry.exporter.logging.otlp.internal.traces.OtlpStdoutSpanExporter; -import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; -import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanExporterComponentProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalOtlpFileExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.GrpcTlsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HttpTlsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpGrpcExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterPropertyModel; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.io.Closeable; -import java.io.IOException; -import java.nio.file.Path; -import java.security.cert.CertificateEncodingException; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.api.io.TempDir; - -class SpanExporterFactoryTest { - - @RegisterExtension - static final SelfSignedCertificateExtension serverTls = new SelfSignedCertificateExtension(); - - @RegisterExtension - static final SelfSignedCertificateExtension clientTls = new SelfSignedCertificateExtension(); - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - private CapturingComponentLoader capturingComponentLoader; - private DeclarativeConfigContext context; - - @BeforeEach - void setup() { - capturingComponentLoader = new CapturingComponentLoader(); - context = new DeclarativeConfigContext(capturingComponentLoader); - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @Test - void create_OtlpHttpDefaults() { - List closeables = new ArrayList<>(); - OtlpHttpSpanExporter expectedExporter = - OtlpHttpSpanExporter.getDefault().toBuilder() - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - SpanExporter exporter = - SpanExporterFactory.getInstance() - .create(new SpanExporterModel().withOtlpHttp(new OtlpHttpExporterModel()), context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_http"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("protocol")).isNull(); - assertThat(configProperties.getString("endpoint")).isNull(); - assertThat(configProperties.getStructured("headers")).isNull(); - assertThat(configProperties.getString("compression")).isNull(); - assertThat(configProperties.getInt("timeout")).isNull(); - assertThat(configProperties.getString("certificate_file")).isNull(); - assertThat(configProperties.getString("client_key_file")).isNull(); - assertThat(configProperties.getString("client_certificate_file")).isNull(); - } - - @Test - void create_OtlpHttpConfigured(@TempDir Path tempDir) - throws CertificateEncodingException, IOException { - List closeables = new ArrayList<>(); - OtlpHttpSpanExporter expectedExporter = - OtlpHttpSpanExporter.builder() - .setEndpoint("http://example:4318/v1/traces") - .addHeader("key1", "value1") - .addHeader("key2", "value2") - .setTimeout(Duration.ofSeconds(15)) - .setCompression("gzip") - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - // Write certificates to temp files - String certificatePath = - createTempFileWithContent( - tempDir, "certificate.cert", serverTls.certificate().getEncoded()); - String clientKeyPath = - createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); - String clientCertificatePath = - createTempFileWithContent( - tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); - - SpanExporter exporter = - SpanExporterFactory.getInstance() - .create( - new SpanExporterModel() - .withOtlpHttp( - new OtlpHttpExporterModel() - .withEndpoint("http://example:4318/v1/traces") - .withHeaders( - Arrays.asList( - new NameStringValuePairModel() - .withName("key1") - .withValue("value1"), - new NameStringValuePairModel() - .withName("key2") - .withValue("value2"))) - .withCompression("gzip") - .withTimeout(15_000) - .withTls( - new HttpTlsModel() - .withCaFile(certificatePath) - .withKeyFile(clientKeyPath) - .withCertFile(clientCertificatePath))), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_http"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4318/v1/traces"); - List headers = configProperties.getStructuredList("headers"); - assertThat(headers) - .isNotNull() - .satisfiesExactly( - header -> { - assertThat(header.getString("name")).isEqualTo("key1"); - assertThat(header.getString("value")).isEqualTo("value1"); - }, - header -> { - assertThat(header.getString("name")).isEqualTo("key2"); - assertThat(header.getString("value")).isEqualTo("value2"); - }); - assertThat(configProperties.getString("compression")).isEqualTo("gzip"); - assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - DeclarativeConfigProperties tls = configProperties.getStructured("tls"); - assertThat(tls).isNotNull(); - assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); - assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); - assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); - } - - @Test - void create_OtlpGrpcDefaults() { - List closeables = new ArrayList<>(); - OtlpGrpcSpanExporter expectedExporter = - OtlpGrpcSpanExporter.getDefault().toBuilder() - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - SpanExporter exporter = - SpanExporterFactory.getInstance() - .create(new SpanExporterModel().withOtlpGrpc(new OtlpGrpcExporterModel()), context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_grpc"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isNull(); - assertThat(configProperties.getStructured("headers")).isNull(); - assertThat(configProperties.getString("compression")).isNull(); - assertThat(configProperties.getInt("timeout")).isNull(); - assertThat(configProperties.getString("certificate_file")).isNull(); - assertThat(configProperties.getString("client_key_file")).isNull(); - assertThat(configProperties.getString("client_certificate_file")).isNull(); - } - - @Test - void create_OtlpGrpcConfigured(@TempDir Path tempDir) - throws CertificateEncodingException, IOException { - List closeables = new ArrayList<>(); - OtlpGrpcSpanExporter expectedExporter = - OtlpGrpcSpanExporter.builder() - .setEndpoint("http://example:4317") - .addHeader("key1", "value1") - .addHeader("key2", "value2") - .setTimeout(Duration.ofSeconds(15)) - .setCompression("gzip") - .setComponentLoader(context) // needed for the toString() check to pass - .build(); - cleanup.addCloseable(expectedExporter); - - // Write certificates to temp files - String certificatePath = - createTempFileWithContent( - tempDir, "certificate.cert", serverTls.certificate().getEncoded()); - String clientKeyPath = - createTempFileWithContent(tempDir, "clientKey.key", clientTls.privateKey().getEncoded()); - String clientCertificatePath = - createTempFileWithContent( - tempDir, "clientCertificate.cert", clientTls.certificate().getEncoded()); - - SpanExporter exporter = - SpanExporterFactory.getInstance() - .create( - new SpanExporterModel() - .withOtlpGrpc( - new OtlpGrpcExporterModel() - .withEndpoint("http://example:4317") - .withHeaders( - Arrays.asList( - new NameStringValuePairModel() - .withName("key1") - .withValue("value1"), - new NameStringValuePairModel() - .withName("key2") - .withValue("value2"))) - .withCompression("gzip") - .withTimeout(15_000) - .withTls( - new GrpcTlsModel() - .withCaFile(certificatePath) - .withKeyFile(clientKeyPath) - .withCertFile(clientCertificatePath))), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_grpc"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isEqualTo("http://example:4317"); - List headers = configProperties.getStructuredList("headers"); - assertThat(headers) - .isNotNull() - .satisfiesExactly( - header -> { - assertThat(header.getString("name")).isEqualTo("key1"); - assertThat(header.getString("value")).isEqualTo("value1"); - }, - header -> { - assertThat(header.getString("name")).isEqualTo("key2"); - assertThat(header.getString("value")).isEqualTo("value2"); - }); - assertThat(configProperties.getString("compression")).isEqualTo("gzip"); - assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - DeclarativeConfigProperties tls = configProperties.getStructured("tls"); - assertThat(tls).isNotNull(); - assertThat(tls.getString("ca_file")).isEqualTo(certificatePath); - assertThat(tls.getString("key_file")).isEqualTo(clientKeyPath); - assertThat(tls.getString("cert_file")).isEqualTo(clientCertificatePath); - } - - @Test - void create_Console() { - List closeables = new ArrayList<>(); - LoggingSpanExporter expectedExporter = LoggingSpanExporter.create(); - cleanup.addCloseable(expectedExporter); - - SpanExporter exporter = - SpanExporterFactory.getInstance() - .create(new SpanExporterModel().withConsole(new ConsoleExporterModel()), context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - } - - @Test - void create_OtlpFile() { - List closeables = new ArrayList<>(); - OtlpStdoutSpanExporter expectedExporter = OtlpStdoutSpanExporter.builder().build(); - cleanup.addCloseable(expectedExporter); - - SpanExporter exporter = - SpanExporterFactory.getInstance() - .create( - new SpanExporterModel() - .withOtlpFileDevelopment(new ExperimentalOtlpFileExporterModel()), - context); - cleanup.addCloseable(exporter); - cleanup.addCloseables(closeables); - - assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); - - // Verify the configuration passed to the component provider - DeclarativeConfigProperties configProperties = - capturingComponentLoader.getCapturedConfig("otlp_file/development"); - assertThat(configProperties).isNotNull(); - } - - @Test - void create_SpiExporter_Unknown() { - List closeables = new ArrayList<>(); - - assertThatThrownBy( - () -> - SpanExporterFactory.getInstance() - .create( - new SpanExporterModel() - .withAdditionalProperty( - "unknown_key", - new SpanExporterPropertyModel() - .withAdditionalProperty("key1", "value1")), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage( - "No component provider detected for io.opentelemetry.sdk.trace.export.SpanExporter with name \"unknown_key\"."); - cleanup.addCloseables(closeables); - } - - @Test - void create_SpiExporter_Valid() { - SpanExporter spanExporter = - SpanExporterFactory.getInstance() - .create( - new SpanExporterModel() - .withAdditionalProperty( - "test", - new SpanExporterPropertyModel().withAdditionalProperty("key1", "value1")), - context); - assertThat(spanExporter).isInstanceOf(SpanExporterComponentProvider.TestSpanExporter.class); - assertThat( - ((SpanExporterComponentProvider.TestSpanExporter) spanExporter) - .config.getString("key1")) - .isEqualTo("value1"); - } - - @Test - void create_Customizer() { - // Generic customizer applied to all span exporters - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addSpanExporterCustomizer( - SpanExporter.class, - (exporter, properties) -> - SpanExporter.composite(exporter, LoggingSpanExporter.create())); - - SpanExporter result = - SpanExporterFactory.getInstance() - .create(new SpanExporterModel().withConsole(new ConsoleExporterModel()), context); - cleanup.addCloseable(result); - - // Result should be wrapped in composite - assertThat(result.toString()).contains("LoggingSpanExporter"); - } - - @Test - void create_Customizer_TypeSafe() { - // Customizer for specific type gets type-safe access to exporter builder methods - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addSpanExporterCustomizer( - OtlpGrpcSpanExporter.class, - (exporter, properties) -> - exporter.toBuilder().setTimeout(Duration.ofSeconds(42)).build()); - - SpanExporter result = - SpanExporterFactory.getInstance() - .create(new SpanExporterModel().withOtlpGrpc(new OtlpGrpcExporterModel()), context); - cleanup.addCloseable(result); - - assertThat(result).isInstanceOf(OtlpGrpcSpanExporter.class); - assertThat(result.toString()).contains("timeoutNanos=42000000000"); - } - - @Test - void create_Customizer_TypeMismatch() { - // Customizer registered for OtlpGrpcSpanExporter should NOT be called for other types - AtomicInteger callCount = new AtomicInteger(0); - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addSpanExporterCustomizer( - OtlpGrpcSpanExporter.class, - (exporter, properties) -> { - callCount.incrementAndGet(); - return exporter; - }); - - SpanExporter result = - SpanExporterFactory.getInstance() - .create(new SpanExporterModel().withConsole(new ConsoleExporterModel()), context); - cleanup.addCloseable(result); - - // Customizer should not have been called since types don't match - assertThat(callCount.get()).isEqualTo(0); - } - - @Test - void create_Customizer_ReturnsNull() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - context - .getBuilder() - .addSpanExporterCustomizer(SpanExporter.class, (exporter, properties) -> null); - - assertThatThrownBy( - () -> - SpanExporterFactory.getInstance() - .create( - new SpanExporterModel().withConsole(new ConsoleExporterModel()), context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessageContaining("Customizer returned null for SpanExporter: console"); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java deleted file mode 100644 index cfbec8b16eb..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanLimitsFactoryTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.mockito.Mockito.mock; - -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanLimitsModel; -import io.opentelemetry.sdk.trace.SpanLimits; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class SpanLimitsFactoryTest { - - @ParameterizedTest - @MethodSource("createArguments") - void create(SpanLimitsAndAttributeLimits model, SpanLimits expectedSpanLimits) { - assertThat(SpanLimitsFactory.getInstance().create(model, mock(DeclarativeConfigContext.class))) - .isEqualTo(expectedSpanLimits); - } - - private static Stream createArguments() { - return Stream.of( - Arguments.of(SpanLimitsAndAttributeLimits.create(null, null), SpanLimits.getDefault()), - Arguments.of( - SpanLimitsAndAttributeLimits.create(new AttributeLimitsModel(), new SpanLimitsModel()), - SpanLimits.getDefault()), - Arguments.of( - SpanLimitsAndAttributeLimits.create( - new AttributeLimitsModel() - .withAttributeCountLimit(1) - .withAttributeValueLengthLimit(2), - new SpanLimitsModel()), - SpanLimits.builder().setMaxNumberOfAttributes(1).setMaxAttributeValueLength(2).build()), - Arguments.of( - SpanLimitsAndAttributeLimits.create( - new AttributeLimitsModel() - .withAttributeCountLimit(1) - .withAttributeValueLengthLimit(2), - new SpanLimitsModel() - .withAttributeCountLimit(3) - .withAttributeValueLengthLimit(4) - .withEventCountLimit(5) - .withLinkCountLimit(6) - .withEventAttributeCountLimit(7) - .withLinkAttributeCountLimit(8)), - SpanLimits.builder() - .setMaxNumberOfAttributes(3) - .setMaxAttributeValueLength(4) - .setMaxNumberOfEvents(5) - .setMaxNumberOfLinks(6) - .setMaxNumberOfAttributesPerEvent(7) - .setMaxNumberOfAttributesPerLink(8) - .build())); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java deleted file mode 100644 index f56aedf746f..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigException; -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanProcessorComponentProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleSpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorPropertyModel; -import io.opentelemetry.sdk.trace.SpanProcessor; -import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; -import java.io.Closeable; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -class SpanProcessorFactoryTest { - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - private static final DeclarativeConfigContext context = - new DeclarativeConfigContext( - ComponentLoader.forClassLoader(SpanProcessorFactoryTest.class.getClassLoader())); - - @BeforeEach - void setup() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @Test - void create_BatchNullExporter() { - assertThatThrownBy( - () -> - SpanProcessorFactory.getInstance() - .create( - new SpanProcessorModel().withBatch(new BatchSpanProcessorModel()), context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage("batch span processor exporter is required but is null"); - } - - @Test - void create_BatchDefaults() { - List closeables = new ArrayList<>(); - BatchSpanProcessor expectedProcessor = - BatchSpanProcessor.builder( - OtlpHttpSpanExporter.builder().setComponentLoader(context).build()) - .build(); - cleanup.addCloseable(expectedProcessor); - - SpanProcessor processor = - SpanProcessorFactory.getInstance() - .create( - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel().withOtlpHttp(new OtlpHttpExporterModel()))), - context); - cleanup.addCloseable(processor); - cleanup.addCloseables(closeables); - - assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); - } - - @Test - void create_BatchConfigured() { - List closeables = new ArrayList<>(); - BatchSpanProcessor expectedProcessor = - BatchSpanProcessor.builder( - OtlpHttpSpanExporter.builder().setComponentLoader(context).build()) - .setScheduleDelay(Duration.ofMillis(1)) - .setMaxExportBatchSize(2) - .setExporterTimeout(Duration.ofMillis(3)) - .build(); - cleanup.addCloseable(expectedProcessor); - - SpanProcessor processor = - SpanProcessorFactory.getInstance() - .create( - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel().withOtlpHttp(new OtlpHttpExporterModel())) - .withScheduleDelay(1) - .withMaxExportBatchSize(2) - .withExportTimeout(3)), - context); - cleanup.addCloseable(processor); - cleanup.addCloseables(closeables); - - assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); - } - - @Test - void create_SimpleNullExporter() { - assertThatThrownBy( - () -> - SpanProcessorFactory.getInstance() - .create( - new SpanProcessorModel().withSimple(new SimpleSpanProcessorModel()), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage("simple span processor exporter is required but is null"); - } - - @Test - void create_SimpleConfigured() { - List closeables = new ArrayList<>(); - SpanProcessor expectedProcessor = - SimpleSpanProcessor.create( - OtlpHttpSpanExporter.builder().setComponentLoader(context).build()); - cleanup.addCloseable(expectedProcessor); - - SpanProcessor processor = - SpanProcessorFactory.getInstance() - .create( - new SpanProcessorModel() - .withSimple( - new SimpleSpanProcessorModel() - .withExporter( - new SpanExporterModel().withOtlpHttp(new OtlpHttpExporterModel()))), - context); - cleanup.addCloseable(processor); - cleanup.addCloseables(closeables); - - assertThat(processor.toString()).isEqualTo(expectedProcessor.toString()); - } - - @Test - void create_SpiProcessor_Unknown() { - assertThatThrownBy( - () -> - SpanProcessorFactory.getInstance() - .create( - new SpanProcessorModel() - .withAdditionalProperty( - "unknown_key", - new SpanProcessorPropertyModel() - .withAdditionalProperty("key1", "value1")), - context)) - .isInstanceOf(DeclarativeConfigException.class) - .hasMessage( - "No component provider detected for io.opentelemetry.sdk.trace.SpanProcessor with name \"unknown_key\"."); - } - - @Test - void create_SpiExporter_Valid() { - SpanProcessor spanProcessor = - SpanProcessorFactory.getInstance() - .create( - new SpanProcessorModel() - .withAdditionalProperty( - "test", - new SpanProcessorPropertyModel().withAdditionalProperty("key1", "value1")), - context); - assertThat(spanProcessor).isInstanceOf(SpanProcessorComponentProvider.TestSpanProcessor.class); - Assertions.assertThat( - ((SpanProcessorComponentProvider.TestSpanProcessor) spanProcessor) - .config.getString("key1")) - .isEqualTo("value1"); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java deleted file mode 100644 index ac80fa388da..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TestDeclarativeConfigurationCustomizerProvider.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel; -import java.util.ArrayList; -import java.util.List; - -public class TestDeclarativeConfigurationCustomizerProvider - implements DeclarativeConfigurationCustomizerProvider { - - @Override - public void customize(DeclarativeConfigurationCustomizer customizer) { - customizer.addModelCustomizer( - model -> { - ResourceModel resource = model.getResource(); - if (resource == null) { - resource = new ResourceModel(); - model.withResource(resource); - } - List attributes = resource.getAttributes(); - if (attributes == null) { - attributes = new ArrayList<>(); - resource.withAttributes(attributes); - } - attributes.add( - new AttributeNameValueModel() - .withName("foo") - .withType(AttributeNameValueModel.AttributeType.STRING) - .withValue("bar")); - attributes.add( - new AttributeNameValueModel() - .withName("color") - .withType(AttributeNameValueModel.AttributeType.STRING) - .withValue("blue")); - return model; - }); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java deleted file mode 100644 index b2610d678b9..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TracerProviderFactoryTest.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOn; - -import io.opentelemetry.common.ComponentLoader; -import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; -import io.opentelemetry.internal.testing.CleanupExtension; -import io.opentelemetry.sdk.common.internal.ScopeConfigurator; -import io.opentelemetry.sdk.common.internal.ScopeConfiguratorBuilder; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AlwaysOnSamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalTracerConfigModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalTracerConfiguratorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalTracerMatcherAndConfigModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessorModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProviderModel; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; -import io.opentelemetry.sdk.trace.SpanLimits; -import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; -import io.opentelemetry.sdk.trace.internal.SdkTracerProviderUtil; -import io.opentelemetry.sdk.trace.internal.TracerConfig; -import java.io.Closeable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class TracerProviderFactoryTest { - - @RegisterExtension CleanupExtension cleanup = new CleanupExtension(); - - private static final DeclarativeConfigContext context = - new DeclarativeConfigContext( - ComponentLoader.forClassLoader(TracerProviderFactoryTest.class.getClassLoader())); - - @BeforeEach - void setup() { - context.setBuilder(new DeclarativeConfigurationBuilder()); - } - - @ParameterizedTest - @MethodSource("createArguments") - void create(TracerProviderAndAttributeLimits model, SdkTracerProvider expectedProvider) { - List closeables = new ArrayList<>(); - cleanup.addCloseable(expectedProvider); - - SdkTracerProvider provider = TracerProviderFactory.getInstance().create(model, context).build(); - cleanup.addCloseable(provider); - cleanup.addCloseables(closeables); - - assertThat(provider.toString()).isEqualTo(expectedProvider.toString()); - } - - private static Stream createArguments() { - return Stream.of( - Arguments.of( - TracerProviderAndAttributeLimits.create(null, null), - SdkTracerProvider.builder().build()), - Arguments.of( - TracerProviderAndAttributeLimits.create( - new AttributeLimitsModel(), new TracerProviderModel()), - SdkTracerProvider.builder().build()), - Arguments.of( - TracerProviderAndAttributeLimits.create( - new AttributeLimitsModel(), - new TracerProviderModel() - .withLimits( - new SpanLimitsModel() - .withAttributeCountLimit(1) - .withAttributeValueLengthLimit(2) - .withEventCountLimit(3) - .withLinkCountLimit(4) - .withEventAttributeCountLimit(5) - .withLinkAttributeCountLimit(6)) - .withSampler(new SamplerModel().withAlwaysOn(new AlwaysOnSamplerModel())) - .withProcessors( - Collections.singletonList( - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel() - .withOtlpHttp(new OtlpHttpExporterModel()))))) - .withTracerConfiguratorDevelopment( - new ExperimentalTracerConfiguratorModel() - .withDefaultConfig( - new ExperimentalTracerConfigModel().withEnabled(false)) - .withTracers( - Collections.singletonList( - new ExperimentalTracerMatcherAndConfigModel() - .withName("foo") - .withConfig( - new ExperimentalTracerConfigModel() - .withEnabled(true)))))), - addTracerConfigurator( - SdkTracerProvider.builder(), - ScopeConfigurator.builder() - .setDefault(TracerConfig.disabled()) - .addCondition( - ScopeConfiguratorBuilder.nameMatchesGlob("foo"), TracerConfig.enabled()) - .build()) - .setSpanLimits( - SpanLimits.builder() - .setMaxNumberOfAttributes(1) - .setMaxAttributeValueLength(2) - .setMaxNumberOfEvents(3) - .setMaxNumberOfLinks(4) - .setMaxNumberOfAttributesPerEvent(5) - .setMaxNumberOfAttributesPerLink(6) - .build()) - .setSampler(alwaysOn()) - .addSpanProcessor( - BatchSpanProcessor.builder( - OtlpHttpSpanExporter.builder().setComponentLoader(context).build()) - .build()) - .build())); - } - - private static SdkTracerProviderBuilder addTracerConfigurator( - SdkTracerProviderBuilder builder, ScopeConfigurator tracerConfigurator) { - SdkTracerProviderUtil.setTracerConfigurator(builder, tracerConfigurator); - return builder; - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java deleted file mode 100644 index 32756b35bf2..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.mockito.Mockito.mock; - -import io.opentelemetry.sdk.common.internal.IncludeExcludePredicate; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AggregationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExplicitBucketHistogramAggregationModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewStreamModel; -import io.opentelemetry.sdk.metrics.Aggregation; -import io.opentelemetry.sdk.metrics.ExplicitBucketHistogramOptions; -import io.opentelemetry.sdk.metrics.View; -import java.util.Arrays; -import java.util.Collections; -import org.junit.jupiter.api.Test; - -class ViewFactoryTest { - - @Test - void create_Defaults() { - View expectedView = View.builder().build(); - - View view = - ViewFactory.getInstance() - .create( - new ViewStreamModel().withAttributeKeys(null), - mock(DeclarativeConfigContext.class)); - - assertThat(view.toString()).isEqualTo(expectedView.toString()); - } - - @Test - void create() { - View expectedView = - View.builder() - .setName("name") - .setDescription("description") - .setAttributeFilter( - IncludeExcludePredicate.createPatternMatching( - Arrays.asList("foo", "bar"), Collections.singletonList("baz"))) - .setAggregation( - Aggregation.explicitBucketHistogram( - ExplicitBucketHistogramOptions.builder() - .setBucketBoundaries(Arrays.asList(1.0, 2.0)) - .build())) - .build(); - - View view = - ViewFactory.getInstance() - .create( - new ViewStreamModel() - .withName("name") - .withDescription("description") - .withAttributeKeys( - new IncludeExcludeModel() - .withIncluded(Arrays.asList("foo", "bar")) - .withExcluded(Collections.singletonList("baz"))) - .withAggregation( - new AggregationModel() - .withExplicitBucketHistogram( - new ExplicitBucketHistogramAggregationModel() - .withBoundaries(Arrays.asList(1.0, 2.0)))), - mock(DeclarativeConfigContext.class)); - - assertThat(view.toString()).isEqualTo(expectedView.toString()); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java deleted file mode 100644 index c22835f2b5a..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/YamlDeclarativeConfigPropertiesTest.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig; - -import static io.opentelemetry.api.incubator.config.DeclarativeConfigProperties.empty; -import static org.assertj.core.api.Assertions.assertThat; - -import com.google.common.collect.ImmutableSet; -import io.github.netmikey.logunit.api.LogCapturer; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.internal.testing.slf4j.SuppressLogger; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -@SuppressLogger(YamlDeclarativeConfigProperties.class) -class YamlDeclarativeConfigPropertiesTest { - - @RegisterExtension - LogCapturer logs = LogCapturer.create().captureForType(YamlDeclarativeConfigProperties.class); - - private static final String extendedSchema = - "file_format: \"1.0\"\n" - + "disabled: false\n" - + "\n" - + "resource:\n" - + " attributes:\n" - + " - name: service.name\n" - + " value: \"unknown_service\"\n" - + "\n" - + "other:\n" - + " str_key: str_value\n" - + " int_key: 1\n" - + " float_key: 1.1\n" - + " bool_key: true\n" - + " null_key:\n" - + " str_list_key: [val1, val2]\n" - + " int_list_key: [1, 2]\n" - + " float_list_key: [1.1, 2.2]\n" - + " bool_list_key: [true, false]\n" - + " mixed_list_key: [val1, 1, 1.1, true]\n" - + " map_key:\n" - + " str_key1: str_value1\n" - + " int_key1: 2\n" - + " map_key1:\n" - + " str_key2: str_value2\n" - + " int_key2: 3\n" - + " list_key:\n" - + " - str_key1: str_value1\n" - + " int_key1: 2\n" - + " map_key1:\n" - + " str_key2: str_value2\n" - + " int_key2: 3\n" - + " - str_key1: str_value1\n" - + " int_key1: 2"; - - private DeclarativeConfigProperties structuredConfigProps; - - @BeforeEach - void setup() { - OpenTelemetryConfigurationModel configuration = - DeclarativeConfigurationParser.parse( - new ByteArrayInputStream(extendedSchema.getBytes(StandardCharsets.UTF_8))); - structuredConfigProps = DeclarativeConfigurationParser.toConfigProperties(configuration); - } - - @Test - void configurationSchema() { - // Validate can read declarative configuration schema properties - assertThat(structuredConfigProps.getString("file_format")).isEqualTo("1.0"); - DeclarativeConfigProperties resourceProps = structuredConfigProps.getStructured("resource"); - assertThat(resourceProps).isNotNull(); - List resourceAttributesList = - resourceProps.getStructuredList("attributes"); - assertThat(resourceAttributesList) - .isNotNull() - .satisfiesExactly( - attributeEntry -> { - assertThat(attributeEntry.getString("name")).isEqualTo("service.name"); - assertThat(attributeEntry.getString("value")).isEqualTo("unknown_service"); - }); - } - - @Test - void additionalProperties() { - assertThat(structuredConfigProps.getPropertyKeys()) - .isEqualTo(ImmutableSet.of("file_format", "disabled", "resource", "other")); - - // Validate can read properties not part of configuration schema - // .other - DeclarativeConfigProperties otherProps = structuredConfigProps.getStructured("other"); - assertThat(otherProps).isNotNull(); - assertThat(otherProps.getPropertyKeys()) - .isEqualTo( - ImmutableSet.of( - "str_key", - "int_key", - "float_key", - "bool_key", - "null_key", - "str_list_key", - "int_list_key", - "float_list_key", - "bool_list_key", - "mixed_list_key", - "map_key", - "list_key")); - assertThat(otherProps.getString("str_key")).isEqualTo("str_value"); - assertThat(otherProps.getInt("int_key")).isEqualTo(1); - assertThat(otherProps.getLong("int_key")).isEqualTo(1); - assertThat(otherProps.getDouble("float_key")).isEqualTo(1.1); - assertThat(otherProps.getString("null_key")).isNull(); - assertThat(otherProps.getInt("null_key")).isNull(); - assertThat(otherProps.getLong("null_key")).isNull(); - assertThat(otherProps.getBoolean("null_key")).isNull(); - assertThat(otherProps.getScalarList("str_list_key", String.class)) - .isEqualTo(Arrays.asList("val1", "val2")); - assertThat(otherProps.getScalarList("int_list_key", Long.class)) - .isEqualTo(Arrays.asList(1L, 2L)); - assertThat(otherProps.getScalarList("float_list_key", Double.class)) - .isEqualTo(Arrays.asList(1.1d, 2.2d)); - assertThat(otherProps.getScalarList("bool_list_key", Boolean.class)) - .isEqualTo(Arrays.asList(true, false)); - // If reading a scalar list which is mixed, entries which are not aligned with - // the requested - // type are filtered out - assertThat(otherProps.getScalarList("mixed_list_key", String.class)) - .isEqualTo(Collections.singletonList("val1")); - assertThat(otherProps.getScalarList("mixed_list_key", Long.class)) - .isEqualTo(Collections.singletonList(1L)); - assertThat(otherProps.getScalarList("mixed_list_key", Double.class)) - .isEqualTo(Collections.singletonList(1.1d)); - assertThat(otherProps.getScalarList("mixed_list_key", Boolean.class)) - .isEqualTo(Collections.singletonList(true)); - - // .other.map_key - DeclarativeConfigProperties otherMapKeyProps = otherProps.getStructured("map_key"); - assertThat(otherMapKeyProps).isNotNull(); - assertThat(otherMapKeyProps.getPropertyKeys()) - .isEqualTo(ImmutableSet.of("str_key1", "int_key1", "map_key1")); - assertThat(otherMapKeyProps.getString("str_key1")).isEqualTo("str_value1"); - assertThat(otherMapKeyProps.getInt("int_key1")).isEqualTo(2); - // other.map_key.map_key1 - DeclarativeConfigProperties otherMapKeyMapKey1Props = - otherMapKeyProps.getStructured("map_key1"); - assertThat(otherMapKeyMapKey1Props).isNotNull(); - assertThat(otherMapKeyMapKey1Props.getPropertyKeys()) - .isEqualTo(ImmutableSet.of("str_key2", "int_key2")); - assertThat(otherMapKeyMapKey1Props.getString("str_key2")).isEqualTo("str_value2"); - assertThat(otherMapKeyMapKey1Props.getInt("int_key2")).isEqualTo(3); - - // .other.list_key - List listKey = otherProps.getStructuredList("list_key"); - assertThat(listKey).hasSize(2); - DeclarativeConfigProperties listKeyProps1 = listKey.get(0); - assertThat(listKeyProps1.getPropertyKeys()) - .isEqualTo(ImmutableSet.of("str_key1", "int_key1", "map_key1")); - assertThat(listKeyProps1.getString("str_key1")).isEqualTo("str_value1"); - assertThat(listKeyProps1.getInt("int_key1")).isEqualTo(2); - // .other.list_key[0] - DeclarativeConfigProperties listKeyProps1MapKeyProps = listKeyProps1.getStructured("map_key1"); - assertThat(listKeyProps1MapKeyProps).isNotNull(); - assertThat(listKeyProps1MapKeyProps.getPropertyKeys()) - .isEqualTo(ImmutableSet.of("str_key2", "int_key2")); - assertThat(listKeyProps1MapKeyProps.getString("str_key2")).isEqualTo("str_value2"); - assertThat(listKeyProps1MapKeyProps.getInt("int_key2")).isEqualTo(3); - // .other.list_key[1] - DeclarativeConfigProperties listKeyProps2 = listKey.get(1); - assertThat(listKeyProps2.getPropertyKeys()).isEqualTo(ImmutableSet.of("str_key1", "int_key1")); - assertThat(listKeyProps2.getString("str_key1")).isEqualTo("str_value1"); - assertThat(listKeyProps2.getInt("int_key1")).isEqualTo(2); - } - - @Test - void treeWalking() { - // Validate common pattern of walking down tree path which is not defined - // Access string at .foo.bar.baz without null checking and without exception. - assertThat( - structuredConfigProps - .get("foo") // short for getStructured("foo", empty()) - .getStructured("bar", empty()) - .getString("baz")) - .isNull(); - } - - @Test - void defaults() { - assertThat(structuredConfigProps.getString("foo", "bar")).isEqualTo("bar"); - assertThat(structuredConfigProps.getInt("foo", 1)).isEqualTo(1); - assertThat(structuredConfigProps.getLong("foo", 1)).isEqualTo(1); - assertThat(structuredConfigProps.getDouble("foo", 1.1)).isEqualTo(1.1); - assertThat(structuredConfigProps.getBoolean("foo", true)).isTrue(); - assertThat( - structuredConfigProps.getScalarList( - "foo", String.class, Collections.singletonList("bar"))) - .isEqualTo(Collections.singletonList("bar")); - assertThat(structuredConfigProps.getStructured("foo", empty())).isEqualTo(empty()); - assertThat(structuredConfigProps.getStructuredList("foo", Collections.emptyList())) - .isEqualTo(Collections.emptyList()); - } - - @Test - void missingKeys() { - assertThat(structuredConfigProps.getString("foo")).isNull(); - assertThat(structuredConfigProps.getInt("foo")).isNull(); - assertThat(structuredConfigProps.getLong("foo")).isNull(); - assertThat(structuredConfigProps.getDouble("foo")).isNull(); - assertThat(structuredConfigProps.getBoolean("foo")).isNull(); - assertThat(structuredConfigProps.getScalarList("foo", String.class)).isNull(); - assertThat(structuredConfigProps.getStructured("foo")).isNull(); - assertThat(structuredConfigProps.getStructuredList("foo")).isNull(); - } - - @Test - void wrongType() { - DeclarativeConfigProperties otherProps = structuredConfigProps.getStructured("other"); - assertThat(otherProps).isNotNull(); - - assertThat(otherProps.getString("int_key")).isNull(); - assertThat(otherProps.getInt("str_key")).isNull(); - assertThat(otherProps.getLong("str_key")).isNull(); - assertThat(otherProps.getDouble("str_key")).isNull(); - assertThat(otherProps.getBoolean("str_key")).isNull(); - assertThat(otherProps.getScalarList("str_key", String.class)).isNull(); - assertThat(otherProps.getScalarList("str_list_key", Long.class)).isNull(); - assertThat(otherProps.getScalarList("str_list_key", Boolean.class)).isNull(); - assertThat(otherProps.getScalarList("str_list_key", Double.class)).isNull(); - assertThat(otherProps.getStructured("str_key")).isNull(); - assertThat(otherProps.getStructuredList("str_key")).isNull(); - assertThat(otherProps.getStructured("str_list_key")).isNull(); - assertThat(otherProps.getStructuredList("map_key")).isNull(); - - assertWarning("Ignoring value for key [int_key] because it is Integer instead of String: 1"); - assertWarning( - "Ignoring value for key [str_key] because it is String instead of Long: str_value"); - assertWarning( - "Ignoring value for key [str_key] because it is String instead of Double: str_value"); - assertWarning( - "Ignoring value for key [str_key] because it is String instead of Boolean: str_value"); - assertWarning( - "Ignoring value for key [str_list_key] because it is String instead of Long: val1"); - } - - @Test - void wrongTypeWithDefault() { - DeclarativeConfigProperties otherProps = structuredConfigProps.getStructured("other"); - assertThat(otherProps).isNotNull(); - - assertThat(otherProps.getString("int_key", "default")).isEqualTo("default"); - assertThat(otherProps.getInt("str_key", 100)).isEqualTo(100); - assertThat(otherProps.getLong("str_key", 100L)).isEqualTo(100L); - assertThat(otherProps.getDouble("str_key", 1.1)).isEqualTo(1.1); - assertThat(otherProps.getBoolean("str_key", true)).isTrue(); - assertThat( - otherProps.getScalarList("str_key", String.class, Collections.singletonList("default"))) - .isEqualTo(Collections.singletonList("default")); - assertThat(otherProps.getStructured("str_key", empty())).isEqualTo(empty()); - assertThat(otherProps.getStructuredList("str_key", Collections.emptyList())) - .isEqualTo(Collections.emptyList()); - } - - private void assertWarning(String message) { - logs.assertContains( - e -> - String.format(e.getMessage().replaceAll("\\{\\d}", "%s"), e.getArgumentArray()) - .contains(message), - message); - } - - @Test - void emptyProperties() { - assertThat(empty().getString("foo")).isNull(); - assertThat(empty().getInt("foo")).isNull(); - assertThat(empty().getLong("foo")).isNull(); - assertThat(empty().getDouble("foo")).isNull(); - assertThat(empty().getBoolean("foo")).isNull(); - assertThat(empty().getScalarList("foo", String.class)).isNull(); - assertThat(empty().getStructured("foo")).isNull(); - assertThat(empty().getStructuredList("foo")).isNull(); - assertThat(empty().getString("foo", "bar")).isEqualTo("bar"); - assertThat(empty().getInt("foo", 1)).isEqualTo(1); - assertThat(empty().getLong("foo", 1)).isEqualTo(1); - assertThat(empty().getDouble("foo", 1.1)).isEqualTo(1.1); - assertThat(empty().getBoolean("foo", true)).isTrue(); - assertThat(empty().getScalarList("foo", String.class, Collections.singletonList("bar"))) - .isEqualTo(Collections.singletonList("bar")); - assertThat(empty().getStructured("foo", empty())).isEqualTo(empty()); - assertThat(empty().getStructuredList("foo", Collections.emptyList())) - .isEqualTo(Collections.emptyList()); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java deleted file mode 100644 index 8c56339f578..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ContainerResourceProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.resources.Resource; - -// TODO(jack-berg): This allows DeclarativeConfigurationCreateTest to pass with kitchen-sink.yaml -// example. Delete after resource providers from opentelemetry-java-instrumentation are renamed to -// reflect declarative config naming -public class ContainerResourceProvider implements ComponentProvider { - @Override - public Class getType() { - return Resource.class; - } - - @Override - public String getName() { - return "container"; - } - - @Override - public Resource create(DeclarativeConfigProperties config) { - return Resource.empty(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java deleted file mode 100644 index 7bff673457d..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/HostResourceProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.resources.Resource; - -// TODO(jack-berg): This allows DeclarativeConfigurationCreateTest to pass with kitchen-sink.yaml -// example. Delete after resource providers from opentelemetry-java-instrumentation are renamed to -// reflect declarative config naming -public class HostResourceProvider implements ComponentProvider { - @Override - public Class getType() { - return Resource.class; - } - - @Override - public String getName() { - return "host"; - } - - @Override - public Resource create(DeclarativeConfigProperties config) { - return Resource.empty(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java deleted file mode 100644 index cae58c59540..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordExporterComponentProvider.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.logs.data.LogRecordData; -import io.opentelemetry.sdk.logs.export.LogRecordExporter; -import java.util.Collection; - -public class LogRecordExporterComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return LogRecordExporter.class; - } - - @Override - public String getName() { - return "test"; - } - - @Override - public LogRecordExporter create(DeclarativeConfigProperties config) { - return new TestLogRecordExporter(config); - } - - public static class TestLogRecordExporter implements LogRecordExporter { - - public final DeclarativeConfigProperties config; - - private TestLogRecordExporter(DeclarativeConfigProperties config) { - this.config = config; - } - - @Override - public CompletableResultCode export(Collection logs) { - return CompletableResultCode.ofSuccess(); - } - - @Override - public CompletableResultCode flush() { - return CompletableResultCode.ofSuccess(); - } - - @Override - public CompletableResultCode shutdown() { - return CompletableResultCode.ofSuccess(); - } - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java deleted file mode 100644 index 28724787319..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/LogRecordProcessorComponentProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.logs.LogRecordProcessor; -import io.opentelemetry.sdk.logs.ReadWriteLogRecord; - -public class LogRecordProcessorComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return LogRecordProcessor.class; - } - - @Override - public String getName() { - return "test"; - } - - @Override - public LogRecordProcessor create(DeclarativeConfigProperties config) { - return new TestLogRecordProcessor(config); - } - - public static class TestLogRecordProcessor implements LogRecordProcessor { - - public final DeclarativeConfigProperties config; - - private TestLogRecordProcessor(DeclarativeConfigProperties config) { - this.config = config; - } - - @Override - public void onEmit(Context context, ReadWriteLogRecord logRecord) {} - - @Override - public CompletableResultCode shutdown() { - return CompletableResultCode.ofSuccess(); - } - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java deleted file mode 100644 index f0860d2fd48..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/MetricExporterComponentProvider.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.metrics.InstrumentType; -import io.opentelemetry.sdk.metrics.data.AggregationTemporality; -import io.opentelemetry.sdk.metrics.data.MetricData; -import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector; -import io.opentelemetry.sdk.metrics.export.MetricExporter; -import java.util.Collection; - -public class MetricExporterComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return MetricExporter.class; - } - - @Override - public String getName() { - return "test"; - } - - @Override - public MetricExporter create(DeclarativeConfigProperties config) { - return new TestMetricExporter(config); - } - - public static class TestMetricExporter implements MetricExporter { - - public final DeclarativeConfigProperties config; - - private TestMetricExporter(DeclarativeConfigProperties config) { - this.config = config; - } - - @Override - public AggregationTemporality getAggregationTemporality(InstrumentType instrumentType) { - return AggregationTemporalitySelector.alwaysCumulative() - .getAggregationTemporality(instrumentType); - } - - @Override - public CompletableResultCode export(Collection metrics) { - return CompletableResultCode.ofSuccess(); - } - - @Override - public CompletableResultCode flush() { - return CompletableResultCode.ofSuccess(); - } - - @Override - public CompletableResultCode shutdown() { - return CompletableResultCode.ofSuccess(); - } - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java deleted file mode 100644 index a8a6801dca6..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/OsResourceProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.resources.Resource; - -// TODO(jack-berg): This allows DeclarativeConfigurationCreateTest to pass with kitchen-sink.yaml -// example. Delete after resource providers from opentelemetry-java-instrumentation are renamed to -// reflect declarative config naming -public class OsResourceProvider implements ComponentProvider { - @Override - public Class getType() { - return Resource.class; - } - - @Override - public String getName() { - return "os"; - } - - @Override - public Resource create(DeclarativeConfigProperties config) { - return Resource.empty(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java deleted file mode 100644 index 87718b791ba..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ProcessResourceProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.resources.Resource; - -// TODO(jack-berg): This allows DeclarativeConfigurationCreateTest to pass with kitchen-sink.yaml -// example. Delete after resource providers from opentelemetry-java-instrumentation are renamed to -// reflect declarative config naming -public class ProcessResourceProvider implements ComponentProvider { - @Override - public Class getType() { - return Resource.class; - } - - @Override - public String getName() { - return "process"; - } - - @Override - public Resource create(DeclarativeConfigProperties config) { - return Resource.empty(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java deleted file mode 100644 index f15d1919917..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceComponentProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.resources.Resource; - -public class ResourceComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return Resource.class; - } - - @Override - public String getName() { - return "shape_color"; - } - - @Override - public Resource create(DeclarativeConfigProperties config) { - return Resource.builder().put("shape", "square").put("color", "red").build(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java deleted file mode 100644 index 565dc1c4f96..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceFirstComponentProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.resources.Resource; - -public class ResourceFirstComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return Resource.class; - } - - @Override - public String getName() { - return "order_first"; - } - - @Override - public Resource create(DeclarativeConfigProperties config) { - return Resource.builder().put("order", "first").build(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java deleted file mode 100644 index f512e1e354f..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/ResourceSecondComponentProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.resources.Resource; - -public class ResourceSecondComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return Resource.class; - } - - @Override - public String getName() { - return "order_second"; - } - - @Override - public Resource create(DeclarativeConfigProperties config) { - return Resource.builder().put("order", "second").build(); - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java deleted file mode 100644 index e48a4a0ceab..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SamplerComponentProvider.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.trace.data.LinkData; -import io.opentelemetry.sdk.trace.samplers.Sampler; -import io.opentelemetry.sdk.trace.samplers.SamplingResult; -import java.util.List; - -public class SamplerComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return Sampler.class; - } - - @Override - public String getName() { - return "test"; - } - - @Override - public Sampler create(DeclarativeConfigProperties config) { - return new TestSampler(config); - } - - public static class TestSampler implements Sampler { - - public final DeclarativeConfigProperties config; - - private TestSampler(DeclarativeConfigProperties config) { - this.config = config; - } - - @Override - public SamplingResult shouldSample( - Context parentContext, - String traceId, - String name, - SpanKind spanKind, - Attributes attributes, - List parentLinks) { - return SamplingResult.recordOnly(); - } - - @Override - public String getDescription() { - return "test"; - } - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java deleted file mode 100644 index f1068a082b8..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanExporterComponentProvider.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.util.Collection; - -public class SpanExporterComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return SpanExporter.class; - } - - @Override - public String getName() { - return "test"; - } - - @Override - public SpanExporter create(DeclarativeConfigProperties config) { - return new TestSpanExporter(config); - } - - public static class TestSpanExporter implements SpanExporter { - - public final DeclarativeConfigProperties config; - - private TestSpanExporter(DeclarativeConfigProperties config) { - this.config = config; - } - - @Override - public CompletableResultCode export(Collection spans) { - return CompletableResultCode.ofSuccess(); - } - - @Override - public CompletableResultCode flush() { - return CompletableResultCode.ofSuccess(); - } - - @Override - public CompletableResultCode shutdown() { - return CompletableResultCode.ofSuccess(); - } - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java deleted file mode 100644 index b42a4795ef6..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/SpanProcessorComponentProvider.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.context.Context; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.common.CompletableResultCode; -import io.opentelemetry.sdk.trace.ReadWriteSpan; -import io.opentelemetry.sdk.trace.ReadableSpan; -import io.opentelemetry.sdk.trace.SpanProcessor; - -public class SpanProcessorComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return SpanProcessor.class; - } - - @Override - public String getName() { - return "test"; - } - - @Override - public SpanProcessor create(DeclarativeConfigProperties config) { - return new TestSpanProcessor(config); - } - - public static class TestSpanProcessor implements SpanProcessor { - - public final DeclarativeConfigProperties config; - - private TestSpanProcessor(DeclarativeConfigProperties config) { - this.config = config; - } - - @Override - public void onStart(Context parentContext, ReadWriteSpan span) {} - - @Override - public boolean isStartRequired() { - return true; - } - - @Override - public void onEnd(ReadableSpan span) {} - - @Override - public boolean isEndRequired() { - return true; - } - - @Override - public CompletableResultCode shutdown() { - return CompletableResultCode.ofSuccess(); - } - } -} diff --git a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java b/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java deleted file mode 100644 index e87c64feec1..00000000000 --- a/sdk-extensions/autoconfigure/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/component/TextMapPropagatorComponentProvider.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.extension.incubator.fileconfig.component; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.context.Context; -import io.opentelemetry.context.propagation.TextMapGetter; -import io.opentelemetry.context.propagation.TextMapPropagator; -import io.opentelemetry.context.propagation.TextMapSetter; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import java.util.Collection; -import java.util.Collections; -import javax.annotation.Nullable; - -public class TextMapPropagatorComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return TextMapPropagator.class; - } - - @Override - public String getName() { - return "test"; - } - - @Override - public TextMapPropagator create(DeclarativeConfigProperties config) { - return new TestTextMapPropagator(config); - } - - public static class TestTextMapPropagator implements TextMapPropagator { - - public final DeclarativeConfigProperties config; - - public TestTextMapPropagator(DeclarativeConfigProperties config) { - this.config = config; - } - - @Override - public Collection fields() { - return Collections.emptyList(); - } - - @Override - public void inject(Context context, @Nullable C carrier, TextMapSetter setter) {} - - @Override - public Context extract(Context context, @Nullable C carrier, TextMapGetter getter) { - return context; - } - - @Override - public String toString() { - return "TestTextMapPropagator{}"; - } - } -} diff --git a/sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider b/sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider deleted file mode 100644 index da5f7288070..00000000000 --- a/sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider +++ /dev/null @@ -1,14 +0,0 @@ -io.opentelemetry.sdk.extension.incubator.fileconfig.component.MetricExporterComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanExporterComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordExporterComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.TextMapPropagatorComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.SamplerComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanProcessorComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordProcessorComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.ResourceComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.ResourceFirstComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.ResourceSecondComponentProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.ContainerResourceProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.HostResourceProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.OsResourceProvider -io.opentelemetry.sdk.extension.incubator.fileconfig.component.ProcessResourceProvider diff --git a/sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider b/sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider deleted file mode 100644 index f60ca4e082e..00000000000 --- a/sdk-extensions/autoconfigure/src/test/resources/META-INF/services/io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationCustomizerProvider +++ /dev/null @@ -1 +0,0 @@ -io.opentelemetry.sdk.extension.incubator.fileconfig.TestDeclarativeConfigurationCustomizerProvider diff --git a/sdk-extensions/autoconfigure/src/test/resources/aggregation-args.yaml b/sdk-extensions/autoconfigure/src/test/resources/aggregation-args.yaml deleted file mode 100644 index 9ddf21b5c8d..00000000000 --- a/sdk-extensions/autoconfigure/src/test/resources/aggregation-args.yaml +++ /dev/null @@ -1,21 +0,0 @@ -- selector: - instrument_type: HISTOGRAM - view: - aggregation: explicit_bucket_histogram - aggregation_args: - bucket_boundaries: [1.0, 2.0, 5.0] -- selector: - instrument_type: HISTOGRAM - view: - aggregation: explicit_bucket_histogram - aggregation_args: - bucket_boundaries: - - 1.0 - - 2.0 - - 5.0 -- selector: - instrument_type: HISTOGRAM - view: - aggregation: exponential_bucket_histogram - aggregation_args: - max_buckets: 20 diff --git a/sdk-extensions/autoconfigure/src/test/resources/empty-selector-config.yaml b/sdk-extensions/autoconfigure/src/test/resources/empty-selector-config.yaml deleted file mode 100644 index 657a53c0f87..00000000000 --- a/sdk-extensions/autoconfigure/src/test/resources/empty-selector-config.yaml +++ /dev/null @@ -1,5 +0,0 @@ -- selector: - view: - name: name1 - description: description1 - aggregation: sum diff --git a/sdk-extensions/autoconfigure/src/test/resources/empty-view-config.yaml b/sdk-extensions/autoconfigure/src/test/resources/empty-view-config.yaml deleted file mode 100644 index 7b27e1e26a9..00000000000 --- a/sdk-extensions/autoconfigure/src/test/resources/empty-view-config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -- selector: - instrument_name: name1 - instrument_type: COUNTER - instrument_unit: ms - meter_name: meterName1 - meter_version: 1.0.0 - meter_schema_url: http://example1.com - view: diff --git a/sdk-extensions/autoconfigure/src/test/resources/full-config.yaml b/sdk-extensions/autoconfigure/src/test/resources/full-config.yaml deleted file mode 100644 index bf968c7e1d6..00000000000 --- a/sdk-extensions/autoconfigure/src/test/resources/full-config.yaml +++ /dev/null @@ -1,28 +0,0 @@ -- selector: - instrument_name: name1 - instrument_type: COUNTER - instrument_unit: ms - meter_name: meterName1 - meter_version: 1.0.0 - meter_schema_url: http://example1.com - view: - name: name1 - description: description1 - aggregation: sum - attribute_keys: - - foo - - bar -- selector: - instrument_name: name2 - instrument_type: COUNTER - instrument_unit: s - meter_name: meterName2 - meter_version: 2.0.0 - meter_schema_url: http://example2.com - view: - name: name2 - description: description2 - aggregation: last_value - attribute_keys: - - baz - - qux diff --git a/sdk-extensions/autoconfigure/src/test/resources/view-config-customizer-test.yaml b/sdk-extensions/autoconfigure/src/test/resources/view-config-customizer-test.yaml deleted file mode 100644 index afa6514b62b..00000000000 --- a/sdk-extensions/autoconfigure/src/test/resources/view-config-customizer-test.yaml +++ /dev/null @@ -1,6 +0,0 @@ -- selector: - instrument_type: OBSERVABLE_COUNTER - view: - attribute_keys: - - foo - - bar \ No newline at end of file diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java index 7e0c05e251d..0016992593b 100644 --- a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java @@ -13,9 +13,11 @@ import static io.opentelemetry.sdk.extension.incubator.fileconfig.ComposableRuleBasedSamplerFactory.DeclarativeConfigSamplingPredicate.toSpanParent; import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.TraceFlags; @@ -58,6 +60,76 @@ void create(ExperimentalComposableRuleBasedSamplerModel model, ComposableSampler assertThat(composableSampler.toString()).isEqualTo(expectedResult.toString()); } + @ParameterizedTest + @MethodSource("createInvalidTestCases") + void createInvalid(ExperimentalComposableRuleBasedSamplerModel model, String expectedMessage) { + assertThatThrownBy(() -> ComposableRuleBasedSamplerFactory.getInstance().create(model, context)) + .isInstanceOf(DeclarativeConfigException.class) + .hasMessage(expectedMessage); + } + + private static Stream createInvalidTestCases() { + return Stream.of( + Arguments.of( + new ExperimentalComposableRuleBasedSamplerModel() + .withRules( + Collections.singletonList( + new ExperimentalComposableRuleBasedSamplerRuleModel() + .withAttributePatterns( + new ExperimentalComposableRuleBasedSamplerRuleAttributePatternsModel() + .withKey("http.path") + .withIncluded(Collections.emptyList()) + .withExcluded(null)) + .withSampler( + new ExperimentalComposableSamplerModel() + .withAlwaysOn( + new ExperimentalComposableAlwaysOnSamplerModel())))), + "included must not be empty"), + Arguments.of( + new ExperimentalComposableRuleBasedSamplerModel() + .withRules( + Collections.singletonList( + new ExperimentalComposableRuleBasedSamplerRuleModel() + .withAttributePatterns( + new ExperimentalComposableRuleBasedSamplerRuleAttributePatternsModel() + .withKey("http.path") + .withIncluded(null) + .withExcluded(Collections.emptyList())) + .withSampler( + new ExperimentalComposableSamplerModel() + .withAlwaysOn( + new ExperimentalComposableAlwaysOnSamplerModel())))), + "excluded must not be empty"), + Arguments.of( + new ExperimentalComposableRuleBasedSamplerModel() + .withRules( + Collections.singletonList( + new ExperimentalComposableRuleBasedSamplerRuleModel() + .withAttributeValues( + new ExperimentalComposableRuleBasedSamplerRuleAttributeValuesModel() + .withKey("http.route") + .withValues(null)) + .withSampler( + new ExperimentalComposableSamplerModel() + .withAlwaysOn( + new ExperimentalComposableAlwaysOnSamplerModel())))), + ".values is required and must be non-empty"), + Arguments.of( + new ExperimentalComposableRuleBasedSamplerModel() + .withRules( + Collections.singletonList( + new ExperimentalComposableRuleBasedSamplerRuleModel() + .withAttributeValues( + new ExperimentalComposableRuleBasedSamplerRuleAttributeValuesModel() + .withKey("http.route") + .withValues(Collections.emptyList())) + .withSampler( + new ExperimentalComposableSamplerModel() + .withAlwaysOn( + new ExperimentalComposableAlwaysOnSamplerModel())))), + ".values is required and must be non-empty")); + } + private static Stream createTestCases() { return Stream.of( Arguments.of( diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java index 58b1bd6e7f5..4b74b25c382 100644 --- a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactoryTest.java @@ -145,11 +145,6 @@ private static Stream createWithDetectorsArgs() { Collections.singletonList("*o*"), Collections.singletonList("order"), Resource.getDefault().toBuilder().put("color", "red").build()), - // empty or missing include should be treated as include all - Arguments.of( - Collections.emptyList(), - Collections.singletonList("order"), - Resource.getDefault().toBuilder().put("color", "red").put("shape", "square").build()), Arguments.of( null, Collections.singletonList("order"), @@ -191,6 +186,24 @@ private static Stream createInvalidDetectorsArgs() { new ExperimentalResourceDetectionModel() .withDetectors( Collections.singletonList(new ExperimentalResourceDetectorModel()))), - "resource detector must have exactly one entry but has 0")); + "resource detector must have exactly one entry but has 0"), + Arguments.of( + new ResourceModel() + .withDetectionDevelopment( + new ExperimentalResourceDetectionModel() + .withAttributes( + new IncludeExcludeModel() + .withIncluded(Collections.emptyList()) + .withExcluded(null))), + "included must not be empty"), + Arguments.of( + new ResourceModel() + .withDetectionDevelopment( + new ExperimentalResourceDetectionModel() + .withAttributes( + new IncludeExcludeModel() + .withIncluded(null) + .withExcluded(Collections.emptyList()))), + "excluded must not be empty")); } } diff --git a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java index 1911c8fbbac..32756b35bf2 100644 --- a/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java +++ b/sdk-extensions/autoconfigure/src/testDeclarativeConfig/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java @@ -42,7 +42,7 @@ void create() { .setName("name") .setDescription("description") .setAttributeFilter( - IncludeExcludePredicate.createExactMatching( + IncludeExcludePredicate.createPatternMatching( Arrays.asList("foo", "bar"), Collections.singletonList("baz"))) .setAggregation( Aggregation.explicitBucketHistogram( diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfig.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfig.java index 30c28d6678d..552a4f19d21 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfig.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfig.java @@ -77,9 +77,8 @@ * @deprecated this mechanism is superseded by declarative config, which is now stable (spec and * schema at opentelemetry-configuration. - * Please uses {@link - * io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser#parseAndCreate(InputStream)} - * instead. + * Please use {@code DeclarativeConfigurationParser#parseAndCreate(InputStream)} from {@code + * opentelemetry-sdk-extension-autoconfigure} instead. */ @Deprecated public final class ViewConfig { diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfigCustomizer.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfigCustomizer.java index f84965034bd..0f95905034f 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfigCustomizer.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/metric/viewconfig/ViewConfigCustomizer.java @@ -23,9 +23,9 @@ * @deprecated this mechanism is superseded by declarative config, which is now stable (spec and * schema at opentelemetry-configuration) - * and will be removed after the 1.62.0 release. Please uses {@link - * io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfigurationParser#parseAndCreate(InputStream)} - * instead. + * and will be removed after the 1.62.0 release. Please use {@code + * DeclarativeConfigurationParser#parseAndCreate(InputStream)} from {@code + * opentelemetry-sdk-extension-autoconfigure} instead. */ @Deprecated public final class ViewConfigCustomizer implements AutoConfigurationCustomizerProvider { diff --git a/sdk-extensions/incubator/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider b/sdk-extensions/incubator/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider deleted file mode 100644 index a1a361a5f37..00000000000 --- a/sdk-extensions/incubator/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider +++ /dev/null @@ -1 +0,0 @@ -io.opentelemetry.sdk.extension.incubator.fileconfig.ServiceResourceDetector From 8efa7c98996df1646a6ec9ca910f55c2f360fc06 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 9 Apr 2026 13:10:54 +0000 Subject: [PATCH 06/11] Fix CI: handle empty jar in NoSharedInternalCodeTest, add snakeyaml to testConvertToModel - NoSharedInternalCodeTest: skip check when jar has no OpenTelemetry classes; autoconfigure-config is a dependency-only convenience module with no Java sources - api/incubator testConvertToModel: add snakeyaml-engine to runtime deps; DeclarativeConfigurationParser (now in autoconfigure) uses snakeyaml internally but autoconfigure declares it compileOnly so it doesn't flow transitively Signed-off-by: Gregor Zeitlinger --- .../java/io/opentelemetry/all/NoSharedInternalCodeTest.java | 5 +++++ api/incubator/build.gradle.kts | 1 + 2 files changed, 6 insertions(+) diff --git a/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java b/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java index fba0cd8cddb..a4bbd47bd0c 100644 --- a/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java +++ b/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java @@ -69,6 +69,11 @@ void noSharedInternalCode(String artifactId, String absolutePath) throws IOExcep .filter(packageName -> packageName.startsWith(OTEL_BASE_PACKAGE)) .collect(Collectors.toSet()); + if (artifactOtelPackages.isEmpty()) { + logger.log(Level.INFO, artifactId + " has no OpenTelemetry classes, skipping check"); + return; + } + ClassesShouldConjunction noSharedInternalCodeRule = noClasses() .that() diff --git a/api/incubator/build.gradle.kts b/api/incubator/build.gradle.kts index 0c31d7c66e7..2d13a5f04ee 100644 --- a/api/incubator/build.gradle.kts +++ b/api/incubator/build.gradle.kts @@ -36,6 +36,7 @@ testing { register("testConvertToModel") { dependencies { implementation("com.fasterxml.jackson.core:jackson-databind") + implementation("org.snakeyaml:snakeyaml-engine") implementation(project(":sdk-extensions:incubator")) implementation(project(":sdk-extensions:autoconfigure")) implementation("com.google.guava:guava") From 8fe978dc7147a138a16289ac1d3ba61535dc2367 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 9 Apr 2026 13:32:48 +0000 Subject: [PATCH 07/11] Make EnvironmentResource.ATTRIBUTE_PROPERTY and createEnvironmentResource package-private Both were public but only used within the autoconfigure module. ResourceFactory (different package, same module) now uses ResourceConfiguration.createEnvironmentResource and inlines the property name string instead. Signed-off-by: Gregor Zeitlinger --- .../sdk/autoconfigure/EnvironmentResource.java | 13 ++----------- .../incubator/fileconfig/ResourceFactory.java | 8 +++----- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java index 8ac6cfcdf81..da9e535f9a3 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java @@ -23,20 +23,11 @@ public final class EnvironmentResource { private static final AttributeKey SERVICE_NAME = AttributeKey.stringKey("service.name"); - // Visible for testing - public static final String ATTRIBUTE_PROPERTY = "otel.resource.attributes"; + static final String ATTRIBUTE_PROPERTY = "otel.resource.attributes"; static final String SERVICE_NAME_PROPERTY = "otel.service.name"; - /** - * Create a {@link Resource} from the environment. The resource contains attributes parsed from - * environment variables and system property keys {@code otel.resource.attributes} and {@code - * otel.service.name}. - * - * @param config the {@link ConfigProperties} used to obtain resource properties - * @return the resource. - */ @SuppressWarnings("JdkObsolete") // Recommended alternative was introduced in java 10 - public static Resource createEnvironmentResource(ConfigProperties config) { + static Resource createEnvironmentResource(ConfigProperties config) { AttributesBuilder resourceAttributes = Attributes.builder(); for (Map.Entry entry : config.getMap(ATTRIBUTE_PROPERTY).entrySet()) { resourceAttributes.put( diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java index f9db56d1835..3f0908cacc3 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java @@ -5,10 +5,8 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig; -import static io.opentelemetry.sdk.autoconfigure.EnvironmentResource.ATTRIBUTE_PROPERTY; -import static io.opentelemetry.sdk.autoconfigure.EnvironmentResource.createEnvironmentResource; - import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.sdk.autoconfigure.ResourceConfiguration; import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.AttributeNameValueModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectionModel; @@ -63,9 +61,9 @@ public Resource create(ResourceModel model, DeclarativeConfigContext context) { String attributeList = model.getAttributesList(); if (attributeList != null) { builder.putAll( - createEnvironmentResource( + ResourceConfiguration.createEnvironmentResource( DefaultConfigProperties.createFromMap( - Collections.singletonMap(ATTRIBUTE_PROPERTY, attributeList)))); + Collections.singletonMap("otel.resource.attributes", attributeList)))); } List attributeNameValueModel = model.getAttributes(); From fb19d7b3ca69b21ac3872c7cdadb42d1c0332671 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 9 Apr 2026 13:34:55 +0000 Subject: [PATCH 08/11] Make EnvironmentResource class package-private Signed-off-by: Gregor Zeitlinger --- .../io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java index da9e535f9a3..7212c6d24fc 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java @@ -19,7 +19,7 @@ *

This class is intentionally self-contained (no dependencies on other autoconfigure-internal * classes). Do not add dependencies on non-API, non-SPI classes. */ -public final class EnvironmentResource { +final class EnvironmentResource { private static final AttributeKey SERVICE_NAME = AttributeKey.stringKey("service.name"); From 31e53ac96feee608cf0bea2261c53b93774d5292 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 9 Apr 2026 13:41:06 +0000 Subject: [PATCH 09/11] Restore javadoc on EnvironmentResource.createEnvironmentResource Signed-off-by: Gregor Zeitlinger --- .../sdk/autoconfigure/EnvironmentResource.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java index 7212c6d24fc..0908f50760c 100644 --- a/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java +++ b/sdk-extensions/autoconfigure/src/main/java/io/opentelemetry/sdk/autoconfigure/EnvironmentResource.java @@ -26,6 +26,14 @@ final class EnvironmentResource { static final String ATTRIBUTE_PROPERTY = "otel.resource.attributes"; static final String SERVICE_NAME_PROPERTY = "otel.service.name"; + /** + * Create a {@link Resource} from the environment. The resource contains attributes parsed from + * environment variables and system property keys {@code otel.resource.attributes} and {@code + * otel.service.name}. + * + * @param config the {@link ConfigProperties} used to obtain resource properties + * @return the resource. + */ @SuppressWarnings("JdkObsolete") // Recommended alternative was introduced in java 10 static Resource createEnvironmentResource(ConfigProperties config) { AttributesBuilder resourceAttributes = Attributes.builder(); From 9bb00a5984014e16ea2720eaa678c68498d461e4 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 13 Apr 2026 13:41:49 +0000 Subject: [PATCH 10/11] Fix missing api:incubator test dependency in autoconfigure Signed-off-by: Gregor Zeitlinger --- sdk-extensions/autoconfigure/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk-extensions/autoconfigure/build.gradle.kts b/sdk-extensions/autoconfigure/build.gradle.kts index 60737cd04bd..35f45aed539 100644 --- a/sdk-extensions/autoconfigure/build.gradle.kts +++ b/sdk-extensions/autoconfigure/build.gradle.kts @@ -25,6 +25,7 @@ dependencies { compileOnly("com.fasterxml.jackson.core:jackson-databind") api("com.fasterxml.jackson.core:jackson-annotations") + testImplementation(project(":api:incubator")) testImplementation(project(":sdk:trace-shaded-deps")) testImplementation(project(":sdk:testing")) From e3ee5793cceea56c6198d4e48832b412e179d27d Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 13 Apr 2026 14:11:02 +0000 Subject: [PATCH 11/11] fix(test): unobfuscate via actual class to support ObfuscatedExtendedOpenTelemetry Signed-off-by: Gregor Zeitlinger --- .../autoconfigure/AutoConfiguredOpenTelemetrySdkTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 8ed8c578693..8b4b97a85e2 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 @@ -757,13 +757,11 @@ void globalOpenTelemetryLock() throws InterruptedException, ExecutionException, private static OpenTelemetry unobfuscate(OpenTelemetry openTelemetry) { try { - Field delegateField = - Class.forName("io.opentelemetry.api.GlobalOpenTelemetry$ObfuscatedOpenTelemetry") - .getDeclaredField("delegate"); + Field delegateField = openTelemetry.getClass().getDeclaredField("delegate"); delegateField.setAccessible(true); Object delegate = delegateField.get(openTelemetry); return (OpenTelemetry) delegate; - } catch (NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) { + } catch (NoSuchFieldException | IllegalAccessException e) { throw new IllegalStateException("Error unobfuscating OpenTelemetry", e); } }