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 ef936a5fd56..56e1ad55922 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 @@ -16,8 +16,9 @@ import io.opentelemetry.api.incubator.config.InstrumentationConfigUtil; import io.opentelemetry.sdk.extension.incubator.fileconfig.DeclarativeConfiguration; import io.opentelemetry.sdk.extension.incubator.fileconfig.SdkConfigProvider; +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.InstrumentationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationPropertyModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; @@ -72,7 +73,9 @@ void getInstrumentationConfigModel_UnsetConfig() { @Test void getInstrumentationConfigModel_EmptyConfig() { ConfigProvider configProvider = - withInstrumentationConfig("my_instrumentation_library", Collections.emptyMap()); + withInstrumentationConfig( + "my_instrumentation_library", + new ExperimentalLanguageSpecificInstrumentationPropertyModel()); assertThat( InstrumentationConfigUtil.getInstrumentationConfigModel( @@ -85,21 +88,20 @@ void getInstrumentationConfigModel_KitchenSink() { ConfigProvider configProvider = withInstrumentationConfig( "my_instrumentation_library", - ImmutableMap.builder() - .put("string_property", "value") - .put("boolean_property", true) - .put("long_property", 1L) - .put("double_property", 1.1d) - .put("string_list_property", Arrays.asList("val1", "val2")) - .put("boolean_list_property", Arrays.asList(true, false)) - .put("long_list_property", Arrays.asList(1L, 2L)) - .put("double_list_property", Arrays.asList(1.1d, 2.2d)) - .put("map_property", Collections.singletonMap("childKey", "val")) - .put( + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("string_property", "value") + .withAdditionalProperty("boolean_property", true) + .withAdditionalProperty("long_property", 1L) + .withAdditionalProperty("double_property", 1.1d) + .withAdditionalProperty("string_list_property", Arrays.asList("val1", "val2")) + .withAdditionalProperty("boolean_list_property", Arrays.asList(true, false)) + .withAdditionalProperty("long_list_property", Arrays.asList(1L, 2L)) + .withAdditionalProperty("double_list_property", Arrays.asList(1.1d, 2.2d)) + .withAdditionalProperty("map_property", Collections.singletonMap("childKey", "val")) + .withAdditionalProperty( "structured_list_property", Collections.singletonList( - ImmutableMap.of("key", "the_key", "value", "the_value"))) - .build()); + ImmutableMap.of("key", "the_key", "value", "the_value")))); Model expected = new Model(); expected.stringProperty = "value"; @@ -123,14 +125,16 @@ void getInstrumentationConfigModel_KitchenSink() { } private static ConfigProvider withInstrumentationConfig( - String instrumentationName, Map instrumentationConfig) { + String instrumentationName, + ExperimentalLanguageSpecificInstrumentationPropertyModel instrumentationConfig) { ExperimentalLanguageSpecificInstrumentationModel javaConfig = new ExperimentalLanguageSpecificInstrumentationModel(); javaConfig.setAdditionalProperty(instrumentationName, instrumentationConfig); return SdkConfigProvider.create( new OpenTelemetryConfigurationModel() - .withInstrumentationDevelopment(new InstrumentationModel().withJava(javaConfig))); + .withInstrumentationDevelopment( + new ExperimentalInstrumentationModel().withJava(javaConfig))); } private static class Model { diff --git a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/OtlpDeclarativeConfigUtil.java b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/OtlpDeclarativeConfigUtil.java index b2f174ae3df..ef4e2b8a099 100644 --- a/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/OtlpDeclarativeConfigUtil.java +++ b/exporters/otlp/all/src/main/java/io/opentelemetry/exporter/otlp/internal/OtlpDeclarativeConfigUtil.java @@ -95,9 +95,11 @@ public static void configureOtlpExporterBuilder( setTimeout.accept(Duration.ofMillis(timeoutMs)); } - String certificatePath = config.getString("certificate_file"); - String clientKeyPath = config.getString("client_key_file"); - String clientKeyChainPath = config.getString("client_certificate_file"); + DeclarativeConfigProperties tls = + config.getStructured("tls", DeclarativeConfigProperties.empty()); + String certificatePath = tls.getString("ca_file"); + String clientKeyPath = tls.getString("key_file"); + String clientKeyChainPath = tls.getString("cert_file"); if (clientKeyPath != null && clientKeyChainPath == null) { throw new ConfigurationException( diff --git a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ZipkinSpanExporterComponentProvider.java b/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ZipkinSpanExporterComponentProvider.java deleted file mode 100644 index ec2d1624479..00000000000 --- a/exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ZipkinSpanExporterComponentProvider.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.exporter.zipkin.internal; - -import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; -import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter; -import io.opentelemetry.exporter.zipkin.ZipkinSpanExporterBuilder; -import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; -import io.opentelemetry.sdk.trace.export.SpanExporter; -import java.time.Duration; - -/** - * Declarative configuration SPI implementation for {@link ZipkinSpanExporter}. - * - *

This class is internal and is hence not for public use. Its APIs are unstable and can change - * at any time. - */ -public class ZipkinSpanExporterComponentProvider implements ComponentProvider { - @Override - public Class getType() { - return SpanExporter.class; - } - - @Override - public String getName() { - return "zipkin"; - } - - @Override - public SpanExporter create(DeclarativeConfigProperties config) { - ZipkinSpanExporterBuilder builder = ZipkinSpanExporter.builder(); - - String endpoint = config.getString("endpoint"); - if (endpoint != null) { - builder.setEndpoint(endpoint); - } - - Long timeoutMs = config.getLong("timeout"); - if (timeoutMs != null) { - builder.setReadTimeout(Duration.ofMillis(timeoutMs)); - } - - return builder.build(); - } -} diff --git a/exporters/zipkin/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider b/exporters/zipkin/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider deleted file mode 100644 index 08330b52dad..00000000000 --- a/exporters/zipkin/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider +++ /dev/null @@ -1 +0,0 @@ -io.opentelemetry.exporter.zipkin.internal.ZipkinSpanExporterComponentProvider diff --git a/sdk-extensions/incubator/build.gradle.kts b/sdk-extensions/incubator/build.gradle.kts index c654a47c348..c68458815bd 100644 --- a/sdk-extensions/incubator/build.gradle.kts +++ b/sdk-extensions/incubator/build.gradle.kts @@ -1,4 +1,5 @@ import de.undercouch.gradle.tasks.download.Download +import java.io.FileFilter plugins { id("otel.java-conventions") @@ -51,14 +52,13 @@ dependencies { // 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. deleteTypeDescriptions - delete type_descriptions.yaml $buildDir/configuration/schema, which is not part of core schema and causes problems resolving type refs -// 4. generateJsonSchema2Pojo - generate java POJOs from the configuration schema -// 5. jsonSchema2PojoPostProcessing - perform various post processing on the generated POJOs, e.g. replace javax.annotation.processing.Generated with javax.annotation.Generated, add @SuppressWarning("rawtypes") annotation -// 6. overwriteJs2p - overwrite original generated classes with versions containing updated @Generated annotation -// 7. deleteJs2pTmp - delete tmp directory +// 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-rc.1" +val configurationTag = "1.0.0-rc.3" 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() @@ -81,13 +81,8 @@ val unzipConfigurationSchema by tasks.registering(Copy::class) { into("$buildDirectory/configuration/") } -val deleteTypeDescriptions by tasks.registering(Delete::class) { - dependsOn(unzipConfigurationSchema) - delete("$buildDirectory/configuration/schema/type_descriptions.yaml") -} - jsonSchema2Pojo { - sourceFiles = setOf(file("$buildDirectory/configuration/schema")) + 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" @@ -114,7 +109,7 @@ jsonSchema2Pojo { } val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo") -generateJsonSchema2Pojo.dependsOn(deleteTypeDescriptions) +generateJsonSchema2Pojo.dependsOn(unzipConfigurationSchema) val jsonSchema2PojoPostProcessing by tasks.registering(Copy::class) { dependsOn(generateJsonSchema2Pojo) diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java new file mode 100644 index 00000000000..c090434deb7 --- /dev/null +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java @@ -0,0 +1,262 @@ +/* + * 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.FileConfigUtil.requireNonNull; +import static java.util.stream.Collectors.toSet; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.context.Context; +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.ExperimentalSpanParent; +import io.opentelemetry.sdk.extension.incubator.trace.samplers.ComposableRuleBasedSamplerBuilder; +import io.opentelemetry.sdk.extension.incubator.trace.samplers.ComposableSampler; +import io.opentelemetry.sdk.extension.incubator.trace.samplers.SamplingPredicate; +import io.opentelemetry.sdk.internal.IncludeExcludePredicate; +import io.opentelemetry.sdk.trace.data.LinkData; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.StringJoiner; +import java.util.function.Predicate; +import javax.annotation.Nullable; + +final class ComposableRuleBasedSamplerFactory + implements Factory { + + private static final ComposableRuleBasedSamplerFactory INSTANCE = + new ComposableRuleBasedSamplerFactory(); + + private ComposableRuleBasedSamplerFactory() {} + + static ComposableRuleBasedSamplerFactory getInstance() { + return INSTANCE; + } + + @Override + public ComposableSampler create( + ExperimentalComposableRuleBasedSamplerModel model, DeclarativeConfigContext context) { + ComposableRuleBasedSamplerBuilder builder = ComposableSampler.ruleBasedBuilder(); + + List rules = model.getRules(); + if (rules != null) { + rules.forEach( + rule -> { + AttributeMatcher valueMatcher = attributeValuesMatcher(rule.getAttributeValues()); + AttributeMatcher patternMatcher = attributePatternsMatcher(rule.getAttributePatterns()); + // TODO: should be null when omitted but is empty + Set matchingParents = + rule.getParent() != null && !rule.getParent().isEmpty() + ? new HashSet<>(rule.getParent()) + : null; + // TODO: should be null when omitted but is empty + Set matchingSpanKinds = + rule.getSpanKinds() != null && !rule.getSpanKinds().isEmpty() + ? rule.getSpanKinds().stream() + .map(DeclarativeConfigSamplingPredicate::toSpanKind) + .collect(toSet()) + : null; + + SamplingPredicate predicate = + new DeclarativeConfigSamplingPredicate( + valueMatcher, patternMatcher, matchingParents, matchingSpanKinds); + ComposableSampler sampler = + ComposableSamplerFactory.getInstance() + .create(requireNonNull(rule.getSampler(), "rule sampler"), context); + builder.add(predicate, sampler); + }); + } + + return builder.build(); + } + + @Nullable + private static AttributeMatcher attributeValuesMatcher( + @Nullable + ExperimentalComposableRuleBasedSamplerRuleAttributeValuesModel attributeValuesModel) { + if (attributeValuesModel == null) { + return null; + } + return new AttributeMatcher( + requireNonNull(attributeValuesModel.getKey(), "attribute_values key"), + IncludeExcludePredicate.createExactMatching(attributeValuesModel.getValues(), null)); + } + + @Nullable + private static AttributeMatcher attributePatternsMatcher( + @Nullable + ExperimentalComposableRuleBasedSamplerRuleAttributePatternsModel attributePatternsModel) { + if (attributePatternsModel == null) { + return null; + } + return new AttributeMatcher( + requireNonNull(attributePatternsModel.getKey(), "attribute_patterns key"), + IncludeExcludePredicate.createPatternMatching( + attributePatternsModel.getIncluded(), attributePatternsModel.getExcluded())); + } + + // Visible for testing + static final class DeclarativeConfigSamplingPredicate implements SamplingPredicate { + @Nullable private final AttributeMatcher attributeValuesMatcher; + @Nullable private final AttributeMatcher attributePatternsMatcher; + @Nullable private final Set matchingParents; + @Nullable private final Set matchingSpanKinds; + + DeclarativeConfigSamplingPredicate( + @Nullable AttributeMatcher attributeValuesMatcher, + @Nullable AttributeMatcher attributePatternsMatcher, + @Nullable Set matchingParents, + @Nullable Set matchingSpanKinds) { + this.attributeValuesMatcher = attributeValuesMatcher; + this.attributePatternsMatcher = attributePatternsMatcher; + this.matchingParents = matchingParents; + this.matchingSpanKinds = matchingSpanKinds; + } + + @Override + public boolean matches( + Context parentContext, + String traceId, + String name, + SpanKind spanKind, + Attributes attributes, + List parentLinks) { + // all conditions must match + + // check attribute value condition + if (attributeValuesMatcher != null && !attributesMatch(attributeValuesMatcher, attributes)) { + return false; + } + + // check attribute pattern condition + if (attributePatternsMatcher != null + && !attributesMatch(attributePatternsMatcher, attributes)) { + return false; + } + + // check parent condition + if (matchingParents != null + && !matchingParents.contains( + toSpanParent(Span.fromContext(parentContext).getSpanContext()))) { + return false; + } + + // check span kind conditions + if (matchingSpanKinds != null && !matchingSpanKinds.contains(spanKind)) { + return false; + } + + // If no conditions are specified, match all spans + return true; + } + + private static boolean attributesMatch(AttributeMatcher matcher, Attributes attributes) { + boolean[] match = new boolean[] {false}; + attributes.forEach( + (key, value) -> { + if (matcher.matchesKey(key.getKey()) && matcher.matchesValue(String.valueOf(value))) { + match[0] = true; + } + }); + return match[0]; + } + + @Override + public String toString() { + StringJoiner joiner = new StringJoiner(", ", "DeclarativeConfigSamplingPredicate{", "}"); + joiner.add("attributeValuesMatcher=" + attributeValuesMatcher); + joiner.add("attributePatterns=" + attributePatternsMatcher); + joiner.add("matchingParents=" + matchingParents); + joiner.add("matchingSpanKinds=" + matchingSpanKinds); + return joiner.toString(); + } + + private static SpanKind toSpanKind( + io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanKind spanKind) { + switch (spanKind) { + case INTERNAL: + return SpanKind.INTERNAL; + case SERVER: + return SpanKind.SERVER; + case CLIENT: + return SpanKind.CLIENT; + case PRODUCER: + return SpanKind.PRODUCER; + case CONSUMER: + return SpanKind.CONSUMER; + } + throw new IllegalArgumentException("Unrecognized span kind: " + spanKind); + } + + // Visible for testing + static ExperimentalSpanParent toSpanParent(SpanContext parentSpanContext) { + if (!parentSpanContext.isValid()) { + return ExperimentalSpanParent.NONE; + } + if (parentSpanContext.isRemote()) { + return ExperimentalSpanParent.REMOTE; + } + return ExperimentalSpanParent.LOCAL; + } + } + + // Visible for testing + static class AttributeMatcher { + private final Predicate attributeKeyMatcher; + private final Predicate attributeValueMatcher; + + AttributeMatcher(String attributeKey, Predicate attributeValueMatcher) { + this(new EqualsPredicate(attributeKey), attributeValueMatcher); + } + + AttributeMatcher( + Predicate attributeKeyMatcher, Predicate attributeValueMatcher) { + this.attributeKeyMatcher = attributeKeyMatcher; + this.attributeValueMatcher = attributeValueMatcher; + } + + boolean matchesKey(String attributeKey) { + return attributeKeyMatcher.test(attributeKey); + } + + boolean matchesValue(String attributeValue) { + return attributeValueMatcher.test(attributeValue); + } + + @Override + public String toString() { + return "AttributeMatcher{keyMatcher=" + + attributeKeyMatcher + + ", valueMatcher=" + + attributeValueMatcher + + '}'; + } + } + + private static class EqualsPredicate implements Predicate { + private final String value; + + private EqualsPredicate(String value) { + this.value = value; + } + + @Override + public boolean test(String s) { + return value.equals(s); + } + + @Override + public String toString() { + return "EqualsPredicate{" + value + '}'; + } + } +} diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java new file mode 100644 index 00000000000..4892e66b1c4 --- /dev/null +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java @@ -0,0 +1,50 @@ +/* + * 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.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.trace.samplers.ComposableSampler; +import java.util.Map; + +final class ComposableSamplerFactory + implements Factory { + + private static final ComposableSamplerFactory INSTANCE = new ComposableSamplerFactory(); + + private ComposableSamplerFactory() {} + + static ComposableSamplerFactory getInstance() { + return INSTANCE; + } + + @Override + public ComposableSampler create( + ExperimentalComposableSamplerModel model, DeclarativeConfigContext context) { + if (model.getAlwaysOn() != null) { + return ComposableSampler.alwaysOn(); + } + if (model.getAlwaysOff() != null) { + return ComposableSampler.alwaysOff(); + } + ExperimentalComposableProbabilitySamplerModel probability = model.getProbability(); + if (probability != null) { + Double ratio = probability.getRatio(); + if (ratio == null) { + ratio = 1.0d; + } + return ComposableSampler.probability(ratio); + } + ExperimentalComposableRuleBasedSamplerModel ruleBased = model.getRuleBased(); + if (ruleBased != null) { + return ComposableRuleBasedSamplerFactory.getInstance().create(ruleBased, context); + } + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "composable sampler"); + return context.loadComponent(ComposableSampler.class, keyValue.getKey(), keyValue.getValue()); + } +} 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 1a977a74efc..f79d7a54932 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 @@ -29,8 +29,8 @@ static T requireNonNull(@Nullable T object, String description) { return object; } - static Map.Entry getSingletonMapEntry( - Map additionalProperties, String resourceName) { + static Map.Entry getSingletonMapEntry( + Map additionalProperties, String resourceName) { if (additionalProperties.isEmpty()) { throw new DeclarativeConfigException(resourceName + " must be set"); } @@ -48,4 +48,15 @@ static Map.Entry getSingletonMapEntry( new IllegalStateException( "Missing " + resourceName + ". This is a programming error.")); } + + static void requireNullResource( + @Nullable Object resource, String resourceName, Map additionalProperties) { + if (resource != null) { + throw new DeclarativeConfigException( + "Invalid configuration - multiple " + + resourceName + + "s set: " + + additionalProperties.keySet().stream().collect(joining(",", "[", "]"))); + } + } } diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactory.java index f2c6db8d42d..7d89c2d0d7a 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactory.java @@ -5,12 +5,16 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig; +import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigUtil.requireNullResource; + import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; import io.opentelemetry.sdk.logs.export.LogRecordExporter; import java.util.Map; final class LogRecordExporterFactory implements Factory { + private static final String RESOURCE_NAME = "log record exporter"; + private static final LogRecordExporterFactory INSTANCE = new LogRecordExporterFactory(); private LogRecordExporterFactory() {} @@ -22,17 +26,37 @@ static LogRecordExporterFactory getInstance() { @Override public LogRecordExporter create(LogRecordExporterModel model, DeclarativeConfigContext context) { - model.getAdditionalProperties().compute("otlp_http", (k, v) -> model.getOtlpHttp()); - model.getAdditionalProperties().compute("otlp_grpc", (k, v) -> model.getOtlpGrpc()); - model - .getAdditionalProperties() - .compute("otlp_file/development", (k, v) -> model.getOtlpFileDevelopment()); - model.getAdditionalProperties().compute("console", (k, v) -> model.getConsole()); + String key = null; + Object resource = null; + + if (model.getOtlpHttp() != null) { + key = "otlp_http"; + resource = model.getOtlpHttp(); + } + if (model.getOtlpGrpc() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "otlp_grpc"; + resource = model.getOtlpGrpc(); + } + if (model.getOtlpFileDevelopment() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "otlp_file/development"; + resource = model.getOtlpFileDevelopment(); + } + if (model.getConsole() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "console"; + resource = model.getConsole(); + } + if (key == null || resource == null) { + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), RESOURCE_NAME); + key = keyValue.getKey(); + resource = keyValue.getValue(); + } - Map.Entry keyValue = - FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "log record exporter"); LogRecordExporter logRecordExporter = - context.loadComponent(LogRecordExporter.class, keyValue.getKey(), keyValue.getValue()); + context.loadComponent(LogRecordExporter.class, key, resource); return context.addCloseable(logRecordExporter); } } diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactory.java index e898fe6efe9..3714189a5e3 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactory.java @@ -9,6 +9,7 @@ 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.SimpleLogRecordProcessorModel; import io.opentelemetry.sdk.logs.LogRecordProcessor; import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; @@ -71,7 +72,7 @@ public LogRecordProcessor create( return context.addCloseable(SimpleLogRecordProcessor.create(logRecordExporter)); } - Map.Entry keyValue = + Map.Entry keyValue = FileConfigUtil.getSingletonMapEntry( model.getAdditionalProperties(), "log record processor"); LogRecordProcessor logRecordProcessor = diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactory.java index 6da48a4fef7..fefadc8d425 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactory.java @@ -5,12 +5,16 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig; +import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigUtil.requireNullResource; + import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel; import io.opentelemetry.sdk.metrics.export.MetricExporter; import java.util.Map; final class MetricExporterFactory implements Factory { + private static final String RESOURCE_NAME = "metric exporter"; + private static final MetricExporterFactory INSTANCE = new MetricExporterFactory(); private MetricExporterFactory() {} @@ -22,17 +26,36 @@ static MetricExporterFactory getInstance() { @Override public MetricExporter create(PushMetricExporterModel model, DeclarativeConfigContext context) { - model.getAdditionalProperties().compute("otlp_http", (k, v) -> model.getOtlpHttp()); - model.getAdditionalProperties().compute("otlp_grpc", (k, v) -> model.getOtlpGrpc()); - model - .getAdditionalProperties() - .compute("otlp_file/development", (k, v) -> model.getOtlpFileDevelopment()); - model.getAdditionalProperties().compute("console", (k, v) -> model.getConsole()); - - Map.Entry keyValue = - FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "metric exporter"); - MetricExporter metricExporter = - context.loadComponent(MetricExporter.class, keyValue.getKey(), keyValue.getValue()); + String key = null; + Object resource = null; + + if (model.getOtlpHttp() != null) { + key = "otlp_http"; + resource = model.getOtlpHttp(); + } + if (model.getOtlpGrpc() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "otlp_grpc"; + resource = model.getOtlpGrpc(); + } + if (model.getOtlpFileDevelopment() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "otlp_file/development"; + resource = model.getOtlpFileDevelopment(); + } + if (model.getConsole() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "console"; + resource = model.getConsole(); + } + if (key == null || resource == null) { + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), RESOURCE_NAME); + key = keyValue.getKey(); + resource = keyValue.getValue(); + } + + MetricExporter metricExporter = context.loadComponent(MetricExporter.class, key, resource); return context.addCloseable(metricExporter); } } diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceDetectorFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceDetectorFactory.java index d16686fb0db..cd13b74845f 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceDetectorFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceDetectorFactory.java @@ -5,12 +5,16 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig; +import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigUtil.requireNullResource; + import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorPropertyModel; import io.opentelemetry.sdk.resources.Resource; import java.util.Map; final class ResourceDetectorFactory implements Factory { + private static final String RESOURCE_NAME = "resource detector"; private static final ResourceDetectorFactory INSTANCE = new ResourceDetectorFactory(); @@ -23,8 +27,35 @@ static ResourceDetectorFactory getInstance() { @Override public Resource create( ExperimentalResourceDetectorModel model, DeclarativeConfigContext context) { - Map.Entry keyValue = - FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "resource detector"); - return context.loadComponent(Resource.class, keyValue.getKey(), keyValue.getValue()); + String key = null; + Object value = null; + + if (model.getContainer() != null) { + key = "container"; + value = model.getContainer(); + } + if (model.getHost() != null) { + requireNullResource(value, RESOURCE_NAME, model.getAdditionalProperties()); + key = "host"; + value = model.getHost(); + } + if (model.getProcess() != null) { + requireNullResource(value, RESOURCE_NAME, model.getAdditionalProperties()); + key = "process"; + value = model.getProcess(); + } + if (model.getService() != null) { + requireNullResource(value, RESOURCE_NAME, model.getAdditionalProperties()); + key = "service"; + value = model.getService(); + } + if (key == null || value == null) { + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "resource detector"); + key = keyValue.getKey(); + value = keyValue.getValue(); + } + + return context.loadComponent(Resource.class, key, value); } } diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactory.java index 67336966657..921eebe3670 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactory.java @@ -5,9 +5,13 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalComposableSamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalProbabilitySamplerModel; 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.TraceIdRatioBasedSamplerModel; +import io.opentelemetry.sdk.extension.incubator.trace.samplers.ComposableSampler; +import io.opentelemetry.sdk.extension.incubator.trace.samplers.CompositeSampler; import io.opentelemetry.sdk.trace.samplers.ParentBasedSamplerBuilder; import io.opentelemetry.sdk.trace.samplers.Sampler; import java.util.Map; @@ -63,11 +67,32 @@ public Sampler create(SamplerModel model, DeclarativeConfigContext context) { } return builder.build(); } + ExperimentalProbabilitySamplerModel probability = model.getProbabilityDevelopment(); + if (probability != null) { + Double ratio = probability.getRatio(); + if (ratio == null) { + ratio = 1.0d; + } + return CompositeSampler.wrap(ComposableSampler.probability(ratio)); + } + ExperimentalComposableSamplerModel composite = model.getCompositeDevelopment(); + if (composite != null) { + return CompositeSampler.wrap( + ComposableSamplerFactory.getInstance().create(composite, context)); + } - model.getAdditionalProperties().compute("jaeger_remote", (k, v) -> model.getJaegerRemote()); - - Map.Entry keyValue = - FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "sampler"); - return context.loadComponent(Sampler.class, keyValue.getKey(), keyValue.getValue()); + String key = null; + Object value = null; + if (model.getJaegerRemoteDevelopment() != null) { + key = "jaeger_remote/development"; + value = model.getJaegerRemoteDevelopment(); + } + if (key == null || value == null) { + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "sampler"); + key = keyValue.getKey(); + value = keyValue.getValue(); + } + return context.loadComponent(Sampler.class, key, value); } } diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java index 03b008320b4..50664773a2d 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java @@ -5,12 +5,16 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig; +import static io.opentelemetry.sdk.extension.incubator.fileconfig.FileConfigUtil.requireNullResource; + import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.util.Map; final class SpanExporterFactory implements Factory { + private static final String RESOURCE_NAME = "span exporter"; + private static final SpanExporterFactory INSTANCE = new SpanExporterFactory(); private SpanExporterFactory() {} @@ -22,18 +26,41 @@ static SpanExporterFactory getInstance() { @Override public SpanExporter create(SpanExporterModel model, DeclarativeConfigContext context) { - model.getAdditionalProperties().compute("otlp_http", (k, v) -> model.getOtlpHttp()); - model.getAdditionalProperties().compute("otlp_grpc", (k, v) -> model.getOtlpGrpc()); - model - .getAdditionalProperties() - .compute("otlp_file/development", (k, v) -> model.getOtlpFileDevelopment()); - model.getAdditionalProperties().compute("console", (k, v) -> model.getConsole()); - model.getAdditionalProperties().compute("zipkin", (k, v) -> model.getZipkin()); - - Map.Entry keyValue = - FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "span exporter"); - SpanExporter spanExporter = - context.loadComponent(SpanExporter.class, keyValue.getKey(), keyValue.getValue()); + String key = null; + Object resource = null; + + if (model.getOtlpHttp() != null) { + key = "otlp_http"; + resource = model.getOtlpHttp(); + } + if (model.getOtlpGrpc() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "otlp_grpc"; + resource = model.getOtlpGrpc(); + } + if (model.getOtlpFileDevelopment() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "otlp_file/development"; + resource = model.getOtlpFileDevelopment(); + } + if (model.getConsole() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "console"; + resource = model.getConsole(); + } + if (key == null || resource == null) { + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), RESOURCE_NAME); + key = keyValue.getKey(); + resource = keyValue.getValue(); + } + // TODO: remove after merging + // https://github.com/open-telemetry/opentelemetry-configuration/pull/460 + if ("zipkin".equals(key)) { + return SpanExporter.composite(); + } + + SpanExporter spanExporter = context.loadComponent(SpanExporter.class, key, resource); return context.addCloseable(spanExporter); } } diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java index d5b2c3970f6..fa90671d2fd 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactory.java @@ -10,6 +10,7 @@ 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.BatchSpanProcessorBuilder; @@ -65,7 +66,7 @@ public SpanProcessor create(SpanProcessorModel model, DeclarativeConfigContext c return context.addCloseable(SimpleSpanProcessor.create(spanExporter)); } - Map.Entry keyValue = + Map.Entry keyValue = FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "span processor"); SpanProcessor spanProcessor = context.loadComponent(SpanProcessor.class, keyValue.getKey(), keyValue.getValue()); diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorFactory.java index 6f0cb869bd1..ac85badb3fd 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorFactory.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/TextMapPropagatorFactory.java @@ -9,6 +9,7 @@ import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.propagation.TextMapPropagator; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TextMapPropagatorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TextMapPropagatorPropertyModel; import java.util.Collections; import java.util.Map; @@ -45,7 +46,7 @@ public TextMapPropagatorAndName create( return getPropagator(context, "ottrace"); } - Map.Entry keyValue = + Map.Entry keyValue = FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "propagator"); TextMapPropagator propagator = context.loadComponent(TextMapPropagator.class, keyValue.getKey(), keyValue.getValue()); diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/trace/samplers/ComposableRuleBasedSampler.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/trace/samplers/ComposableRuleBasedSampler.java index 2752f724e75..d3659572f57 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/trace/samplers/ComposableRuleBasedSampler.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/trace/samplers/ComposableRuleBasedSampler.java @@ -60,4 +60,9 @@ public SamplingIntent getSamplingIntent( public String getDescription() { return description; } + + @Override + public String toString() { + return this.getDescription(); + } } diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java new file mode 100644 index 00000000000..683acf3c9cd --- /dev/null +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java @@ -0,0 +1,292 @@ +/* + * 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.mockito.Mockito.mock; + +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.context.Context; +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.internal.IncludeExcludePredicate; +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 { + + @ParameterizedTest + @MethodSource("createTestCases") + void create(ExperimentalComposableRuleBasedSamplerModel model, ComposableSampler expectedResult) { + ComposableSampler composableSampler = + ComposableRuleBasedSamplerFactory.getInstance() + .create(model, mock(DeclarativeConfigContext.class)); + 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/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 b7e4756ce0f..b236c9e649d 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 @@ -80,18 +80,14 @@ void parseAndCreate_Examples(@TempDir Path tempDir) String rewrittenExampleContent = exampleContent .replaceAll( - "certificate_file: .*\n", - "certificate_file: " - + certificatePath.replace("\\", "\\\\") - + System.lineSeparator()) + "ca_file: .*\n", + "ca_file: " + certificatePath.replace("\\", "\\\\") + System.lineSeparator()) .replaceAll( - "client_key_file: .*\n", - "client_key_file: " - + clientKeyPath.replace("\\", "\\\\") - + System.lineSeparator()) + "key_file: .*\n", + "key_file: " + clientKeyPath.replace("\\", "\\\\") + System.lineSeparator()) .replaceAll( - "client_certificate_file: .*\n", - "client_certificate_file: " + "cert_file: .*\n", + "cert_file: " + clientCertificatePath.replace("\\", "\\\\") + System.lineSeparator()); InputStream is = 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 18284627324..ffc1322bcb1 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 @@ -20,11 +20,27 @@ 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.CardinalityLimitsModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ClientModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleMetricExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DistributionModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.DistributionPropertyModel; +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.ExperimentalContainerResourceDetectorModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalGeneralInstrumentationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalHostResourceDetectorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalHttpClientInstrumentationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalHttpInstrumentationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalHttpServerInstrumentationModel; +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; 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; @@ -34,15 +50,21 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalOtlpFileExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalOtlpFileMetricExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalPeerInstrumentationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalPeerServiceMappingModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalProbabilitySamplerModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalProcessResourceDetectorModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalPrometheusMetricExporterModel; 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.ExperimentalServiceResourceDetectorModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalSpanParent; 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.ExplicitBucketHistogramAggregationModel; +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.IncludeExcludeModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.JaegerPropagatorModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.LogRecordLimitsModel; @@ -67,11 +89,10 @@ 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.ServerModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ServiceMappingModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleLogRecordProcessorModel; 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.SpanKind; 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.TextMapPropagatorModel; @@ -81,7 +102,6 @@ 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.extension.incubator.fileconfig.internal.model.ZipkinSpanExporterModel; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.IOException; @@ -114,9 +134,9 @@ void parse_BadInputStream() { void parse_KitchenSinkExampleFile() throws IOException { OpenTelemetryConfigurationModel expected = new OpenTelemetryConfigurationModel(); - expected.withFileFormat("1.0-rc.1"); + expected.withFileFormat("1.0-rc.3"); expected.withDisabled(false); - expected.withLogLevel("info"); + expected.withLogLevel(OpenTelemetryConfigurationModel.SeverityNumber.INFO); // General config ResourceModel resource = @@ -168,13 +188,13 @@ void parse_KitchenSinkExampleFile() throws IOException { .withDetectors( Arrays.asList( new ExperimentalResourceDetectorModel() - .withAdditionalProperty("container", null), + .withContainer(new ExperimentalContainerResourceDetectorModel()), new ExperimentalResourceDetectorModel() - .withAdditionalProperty("host", null), + .withHost(new ExperimentalHostResourceDetectorModel()), new ExperimentalResourceDetectorModel() - .withAdditionalProperty("process", null), + .withProcess(new ExperimentalProcessResourceDetectorModel()), new ExperimentalResourceDetectorModel() - .withAdditionalProperty("service", null)))) + .withService(new ExperimentalServiceResourceDetectorModel())))) .withSchemaUrl("https://opentelemetry.io/schemas/1.16.0"); expected.withResource(resource); @@ -220,9 +240,60 @@ void parse_KitchenSinkExampleFile() throws IOException { .withRemoteParentSampled( new SamplerModel().withAlwaysOn(new AlwaysOnSamplerModel())) .withRemoteParentNotSampled( - new SamplerModel().withAlwaysOff(new AlwaysOffSamplerModel())) + new SamplerModel() + .withProbabilityDevelopment( + new ExperimentalProbabilitySamplerModel().withRatio(0.01))) .withLocalParentSampled( - new SamplerModel().withAlwaysOn(new AlwaysOnSamplerModel())) + new SamplerModel() + .withCompositeDevelopment( + new ExperimentalComposableSamplerModel() + .withRuleBased( + 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.001)))))))) .withLocalParentNotSampled( new SamplerModel().withAlwaysOff(new AlwaysOffSamplerModel()))); tracerProvider.withSampler(sampler); @@ -250,9 +321,11 @@ void parse_KitchenSinkExampleFile() throws IOException { .withOtlpHttp( new OtlpHttpExporterModel() .withEndpoint("http://localhost:4318/v1/traces") - .withCertificateFile("/app/cert.pem") - .withClientKeyFile("/app/cert.pem") - .withClientCertificateFile("/app/cert.pem") + .withTls( + new HttpTlsModel() + .withCaFile("/app/cert.pem") + .withKeyFile("/app/cert.pem") + .withCertFile("/app/cert.pem")) .withHeaders( Collections.singletonList( new NameStringValuePairModel() @@ -272,9 +345,12 @@ void parse_KitchenSinkExampleFile() throws IOException { .withOtlpGrpc( new OtlpGrpcExporterModel() .withEndpoint("http://localhost:4317") - .withCertificateFile("/app/cert.pem") - .withClientKeyFile("/app/cert.pem") - .withClientCertificateFile("/app/cert.pem") + .withTls( + new GrpcTlsModel() + .withCaFile("/app/cert.pem") + .withKeyFile("/app/cert.pem") + .withCertFile("/app/cert.pem") + .withInsecure(false)) .withHeaders( Collections.singletonList( new NameStringValuePairModel() @@ -282,8 +358,7 @@ void parse_KitchenSinkExampleFile() throws IOException { .withValue("1234"))) .withHeadersList("api-key=1234") .withCompression("gzip") - .withTimeout(10_000) - .withInsecure(false)))); + .withTimeout(10_000)))); SpanProcessorModel spanProcessor3 = new SpanProcessorModel() .withBatch( @@ -303,28 +378,13 @@ void parse_KitchenSinkExampleFile() throws IOException { new ExperimentalOtlpFileExporterModel() .withOutputStream("stdout")))); SpanProcessorModel spanProcessor5 = - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel() - .withZipkin( - new ZipkinSpanExporterModel() - .withEndpoint("http://localhost:9411/api/v2/spans") - .withTimeout(10_000)))); - SpanProcessorModel spanProcessor6 = new SpanProcessorModel() .withSimple( new SimpleSpanProcessorModel() .withExporter(new SpanExporterModel().withConsole(new ConsoleExporterModel()))); tracerProvider.withProcessors( Arrays.asList( - spanProcessor1, - spanProcessor2, - spanProcessor3, - spanProcessor4, - spanProcessor5, - spanProcessor6)); + spanProcessor1, spanProcessor2, spanProcessor3, spanProcessor4, spanProcessor5)); expected.withTracerProvider(tracerProvider); // end TracerProvider config @@ -343,7 +403,13 @@ void parse_KitchenSinkExampleFile() throws IOException { Collections.singletonList( new ExperimentalLoggerMatcherAndConfigModel() .withName("io.opentelemetry.contrib.*") - .withConfig(new ExperimentalLoggerConfigModel().withDisabled(false)))); + .withConfig( + new ExperimentalLoggerConfigModel() + .withDisabled(false) + .withMinimumSeverity( + // TODO: SeverityNumber should not be nested + OpenTelemetryConfigurationModel.SeverityNumber.INFO) + .withTraceBased(true)))); loggerProvider.withLoggerConfiguratorDevelopment(loggerConfigurator); LogRecordProcessorModel logRecordProcessor1 = @@ -359,9 +425,11 @@ void parse_KitchenSinkExampleFile() throws IOException { .withOtlpHttp( new OtlpHttpExporterModel() .withEndpoint("http://localhost:4318/v1/logs") - .withCertificateFile("/app/cert.pem") - .withClientKeyFile("/app/cert.pem") - .withClientCertificateFile("/app/cert.pem") + .withTls( + new HttpTlsModel() + .withCaFile("/app/cert.pem") + .withKeyFile("/app/cert.pem") + .withCertFile("/app/cert.pem")) .withHeaders( Collections.singletonList( new NameStringValuePairModel() @@ -381,9 +449,12 @@ void parse_KitchenSinkExampleFile() throws IOException { .withOtlpGrpc( new OtlpGrpcExporterModel() .withEndpoint("http://localhost:4317") - .withCertificateFile("/app/cert.pem") - .withClientKeyFile("/app/cert.pem") - .withClientCertificateFile("/app/cert.pem") + .withTls( + new GrpcTlsModel() + .withCaFile("/app/cert.pem") + .withKeyFile("/app/cert.pem") + .withCertFile("/app/cert.pem") + .withInsecure(false)) .withHeaders( Collections.singletonList( new NameStringValuePairModel() @@ -391,8 +462,7 @@ void parse_KitchenSinkExampleFile() throws IOException { .withValue("1234"))) .withHeadersList("api-key=1234") .withCompression("gzip") - .withTimeout(10_000) - .withInsecure(false)))); + .withTimeout(10_000)))); LogRecordProcessorModel logRecordProcessor3 = new LogRecordProcessorModel() .withBatch( @@ -441,14 +511,17 @@ void parse_KitchenSinkExampleFile() throws IOException { new ExperimentalPrometheusMetricExporterModel() .withHost("localhost") .withPort(9464) - .withWithoutUnits(false) - .withWithoutTypeSuffix(false) .withWithoutScopeInfo(false) + .withWithoutTargetInfo(false) .withWithResourceConstantLabels( new IncludeExcludeModel() .withIncluded(Collections.singletonList("service*")) .withExcluded( - Collections.singletonList("service.attr1"))))) + Collections.singletonList("service.attr1"))) + .withTranslationStrategy( + ExperimentalPrometheusMetricExporterModel + .ExperimentalPrometheusTranslationStrategy + .UNDERSCORE_ESCAPING_WITH_SUFFIXES))) .withProducers( Collections.singletonList( new MetricProducerModel() @@ -474,9 +547,11 @@ void parse_KitchenSinkExampleFile() throws IOException { .withOtlpHttp( new OtlpHttpMetricExporterModel() .withEndpoint("http://localhost:4318/v1/metrics") - .withCertificateFile("/app/cert.pem") - .withClientKeyFile("/app/cert.pem") - .withClientCertificateFile("/app/cert.pem") + .withTls( + new HttpTlsModel() + .withCaFile("/app/cert.pem") + .withKeyFile("/app/cert.pem") + .withCertFile("/app/cert.pem")) .withHeaders( Collections.singletonList( new NameStringValuePairModel() @@ -495,7 +570,8 @@ void parse_KitchenSinkExampleFile() throws IOException { .BASE_2_EXPONENTIAL_BUCKET_HISTOGRAM))) .withProducers( Collections.singletonList( - new MetricProducerModel().withAdditionalProperty("prometheus", null))) + new MetricProducerModel() + .withOpencensus(new OpenCensusMetricProducerModel()))) .withCardinalityLimits( new CardinalityLimitsModel() .withDefault(2000) @@ -515,9 +591,12 @@ void parse_KitchenSinkExampleFile() throws IOException { .withOtlpGrpc( new OtlpGrpcMetricExporterModel() .withEndpoint("http://localhost:4317") - .withCertificateFile("/app/cert.pem") - .withClientKeyFile("/app/cert.pem") - .withClientCertificateFile("/app/cert.pem") + .withTls( + new GrpcTlsModel() + .withCaFile("/app/cert.pem") + .withKeyFile("/app/cert.pem") + .withCertFile("/app/cert.pem") + .withInsecure(false)) .withHeaders( Collections.singletonList( new NameStringValuePairModel() @@ -526,7 +605,6 @@ void parse_KitchenSinkExampleFile() throws IOException { .withHeadersList("api-key=1234") .withCompression("gzip") .withTimeout(10_000) - .withInsecure(false) .withTemporalityPreference( OtlpHttpMetricExporterModel.ExporterTemporalityPreference .DELTA) @@ -571,7 +649,16 @@ void parse_KitchenSinkExampleFile() throws IOException { .withPeriodic( new PeriodicMetricReaderModel() .withExporter( - new PushMetricExporterModel().withConsole(new ConsoleExporterModel()))); + new PushMetricExporterModel() + .withConsole( + new ConsoleMetricExporterModel() + .withTemporalityPreference( + OtlpHttpMetricExporterModel.ExporterTemporalityPreference + .DELTA) + .withDefaultHistogramAggregation( + OtlpHttpMetricExporterModel + .ExporterDefaultHistogramAggregation + .BASE_2_EXPONENTIAL_BUCKET_HISTOGRAM)))); meterProvider.withReaders( Arrays.asList( metricReader1, @@ -626,30 +713,30 @@ void parse_KitchenSinkExampleFile() throws IOException { // end MeterProvider config // start instrumentation config - InstrumentationModel instrumentation = - new InstrumentationModel() + ExperimentalInstrumentationModel instrumentation = + new ExperimentalInstrumentationModel() .withGeneral( new ExperimentalGeneralInstrumentationModel() .withPeer( new ExperimentalPeerInstrumentationModel() .withServiceMapping( Arrays.asList( - new ServiceMappingModel() + new ExperimentalPeerServiceMappingModel() .withPeer("1.2.3.4") .withService("FooService"), - new ServiceMappingModel() + new ExperimentalPeerServiceMappingModel() .withPeer("2.3.4.5") .withService("BarService")))) .withHttp( new ExperimentalHttpInstrumentationModel() .withClient( - new ClientModel() + new ExperimentalHttpClientInstrumentationModel() .withRequestCapturedHeaders( Arrays.asList("Content-Type", "Accept")) .withResponseCapturedHeaders( Arrays.asList("Content-Type", "Content-Encoding"))) .withServer( - new ServerModel() + new ExperimentalHttpServerInstrumentationModel() .withRequestCapturedHeaders( Arrays.asList("Content-Type", "Accept")) .withResponseCapturedHeaders( @@ -657,56 +744,85 @@ void parse_KitchenSinkExampleFile() throws IOException { .withCpp( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withDotnet( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withErlang( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withGo( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withJava( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withJs( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withPhp( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withPython( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withRuby( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withRust( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))) + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))) .withSwift( new ExperimentalLanguageSpecificInstrumentationModel() .withAdditionalProperty( - "example", Collections.singletonMap("property", "value"))); + "example", + new ExperimentalLanguageSpecificInstrumentationPropertyModel() + .withAdditionalProperty("property", "value"))); expected.withInstrumentationDevelopment(instrumentation); // end instrumentation config + DistributionModel distribution = + new DistributionModel() + .withAdditionalProperty( + "example", + new DistributionPropertyModel().withAdditionalProperty("property", "value")); + expected.withDistribution(distribution); + try (FileInputStream configExampleFile = new FileInputStream(System.getenv("CONFIG_EXAMPLE_DIR") + "/kitchen-sink.yaml")) { OpenTelemetryConfigurationModel config = DeclarativeConfiguration.parse(configExampleFile); // General config - assertThat(config.getFileFormat()).isEqualTo("1.0-rc.1"); + assertThat(config.getFileFormat()).isEqualTo("1.0-rc.3"); assertThat(config.getResource()).isEqualTo(resource); assertThat(config.getAttributeLimits()).isEqualTo(attributeLimits); assertThat(config.getPropagator()).isEqualTo(propagator); @@ -720,12 +836,7 @@ void parse_KitchenSinkExampleFile() throws IOException { assertThat(configTracerProvider.getProcessors()) .isEqualTo( Arrays.asList( - spanProcessor1, - spanProcessor2, - spanProcessor3, - spanProcessor4, - spanProcessor5, - spanProcessor6)); + spanProcessor1, spanProcessor2, spanProcessor3, spanProcessor4, spanProcessor5)); assertThat(configTracerProvider).isEqualTo(tracerProvider); // LoggerProvider config @@ -760,9 +871,14 @@ void parse_KitchenSinkExampleFile() throws IOException { assertThat(configMeterProvider).isEqualTo(meterProvider); // Instrumentation config - InstrumentationModel configInstrumentation = config.getInstrumentationDevelopment(); + ExperimentalInstrumentationModel configInstrumentation = + config.getInstrumentationDevelopment(); assertThat(configInstrumentation).isEqualTo(instrumentation); + // Distribution config + DistributionModel configDistribution = config.getDistribution(); + assertThat(configDistribution).isEqualTo(distribution); + // All configuration assertThat(config).isEqualTo(expected); } diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java index 054e2c312d1..bd9ca17ce94 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordExporterFactoryTest.java @@ -9,7 +9,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.google.common.collect.ImmutableMap; import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; @@ -20,7 +19,10 @@ import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper; import io.opentelemetry.sdk.extension.incubator.fileconfig.component.LogRecordExporterComponentProvider; 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; @@ -133,9 +135,11 @@ void create_OtlpHttpConfigured(@TempDir Path tempDir) .withValue("value2"))) .withCompression("gzip") .withTimeout(15_000) - .withCertificateFile(certificatePath) - .withClientKeyFile(clientKeyPath) - .withClientCertificateFile(clientCertificatePath)), + .withTls( + new HttpTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath))), context); cleanup.addCloseable(exporter); cleanup.addCloseables(closeables); @@ -161,10 +165,11 @@ void create_OtlpHttpConfigured(@TempDir Path tempDir) }); assertThat(configProperties.getString("compression")).isEqualTo("gzip"); assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - assertThat(configProperties.getString("certificate_file")).isEqualTo(certificatePath); - assertThat(configProperties.getString("client_key_file")).isEqualTo(clientKeyPath); - assertThat(configProperties.getString("client_certificate_file")) - .isEqualTo(clientCertificatePath); + 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 @@ -240,9 +245,11 @@ void create_OtlpGrpcConfigured(@TempDir Path tempDir) .withValue("value2"))) .withCompression("gzip") .withTimeout(15_000) - .withCertificateFile(certificatePath) - .withClientKeyFile(clientKeyPath) - .withClientCertificateFile(clientCertificatePath)), + .withTls( + new GrpcTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath))), context); cleanup.addCloseable(exporter); cleanup.addCloseables(closeables); @@ -268,10 +275,11 @@ void create_OtlpGrpcConfigured(@TempDir Path tempDir) }); assertThat(configProperties.getString("compression")).isEqualTo("gzip"); assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - assertThat(configProperties.getString("certificate_file")).isEqualTo(certificatePath); - assertThat(configProperties.getString("client_key_file")).isEqualTo(clientKeyPath); - assertThat(configProperties.getString("client_certificate_file")) - .isEqualTo(clientCertificatePath); + 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 @@ -307,7 +315,9 @@ void create_SpiExporter_Unknown() { .create( new LogRecordExporterModel() .withAdditionalProperty( - "unknown_key", ImmutableMap.of("key1", "value1")), + "unknown_key", + new LogRecordExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), context)) .isInstanceOf(DeclarativeConfigException.class) .hasMessage( @@ -321,7 +331,10 @@ void create_SpiExporter_Valid() { LogRecordExporterFactory.getInstance() .create( new LogRecordExporterModel() - .withAdditionalProperty("test", ImmutableMap.of("key1", "value1")), + .withAdditionalProperty( + "test", + new LogRecordExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), context); assertThat(logRecordExporter) .isInstanceOf(LogRecordExporterComponentProvider.TestLogRecordExporter.class); diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java index b7e092da22a..7d60aaf02f6 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/LogRecordProcessorFactoryTest.java @@ -8,7 +8,6 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.google.common.collect.ImmutableMap; import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter; import io.opentelemetry.internal.testing.CleanupExtension; @@ -17,6 +16,7 @@ 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 java.io.Closeable; @@ -148,7 +148,9 @@ void create_SpiProcessor_Unknown() { .create( new LogRecordProcessorModel() .withAdditionalProperty( - "unknown_key", ImmutableMap.of("key1", "value1")), + "unknown_key", + new LogRecordProcessorPropertyModel() + .withAdditionalProperty("key1", "value1")), context)) .isInstanceOf(DeclarativeConfigException.class) .hasMessage( @@ -161,7 +163,10 @@ void create_SpiExporter_Valid() { LogRecordProcessorFactory.getInstance() .create( new LogRecordProcessorModel() - .withAdditionalProperty("test", ImmutableMap.of("key1", "value1")), + .withAdditionalProperty( + "test", + new LogRecordProcessorPropertyModel() + .withAdditionalProperty("key1", "value1")), context); assertThat(logRecordProcessor) .isInstanceOf(LogRecordProcessorComponentProvider.TestLogRecordProcessor.class); diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java index 5fe2da41942..14912dfb557 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricExporterFactoryTest.java @@ -9,7 +9,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.google.common.collect.ImmutableMap; import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; @@ -20,12 +19,15 @@ import io.opentelemetry.internal.testing.CleanupExtension; import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper; import io.opentelemetry.sdk.extension.incubator.fileconfig.component.MetricExporterComponentProvider; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleExporterModel; +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; @@ -146,9 +148,11 @@ void create_OtlpHttpConfigured(@TempDir Path tempDir) .withValue("value2"))) .withCompression("gzip") .withTimeout(15_000) - .withCertificateFile(certificatePath) - .withClientKeyFile(clientKeyPath) - .withClientCertificateFile(clientCertificatePath) + .withTls( + new HttpTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath)) .withTemporalityPreference( OtlpHttpMetricExporterModel.ExporterTemporalityPreference.DELTA) .withDefaultHistogramAggregation( @@ -179,13 +183,14 @@ void create_OtlpHttpConfigured(@TempDir Path tempDir) }); assertThat(configProperties.getString("compression")).isEqualTo("gzip"); assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - assertThat(configProperties.getString("certificate_file")).isEqualTo(certificatePath); - assertThat(configProperties.getString("client_key_file")).isEqualTo(clientKeyPath); - assertThat(configProperties.getString("client_certificate_file")) - .isEqualTo(clientCertificatePath); 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 @@ -268,9 +273,11 @@ void create_OtlpGrpcConfigured(@TempDir Path tempDir) .withValue("value2"))) .withCompression("gzip") .withTimeout(15_000) - .withCertificateFile(certificatePath) - .withClientKeyFile(clientKeyPath) - .withClientCertificateFile(clientCertificatePath) + .withTls( + new GrpcTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath)) .withTemporalityPreference( OtlpHttpMetricExporterModel.ExporterTemporalityPreference.DELTA) .withDefaultHistogramAggregation( @@ -301,13 +308,14 @@ void create_OtlpGrpcConfigured(@TempDir Path tempDir) }); assertThat(configProperties.getString("compression")).isEqualTo("gzip"); assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - assertThat(configProperties.getString("certificate_file")).isEqualTo(certificatePath); - assertThat(configProperties.getString("client_key_file")).isEqualTo(clientKeyPath); - assertThat(configProperties.getString("client_certificate_file")) - .isEqualTo(clientCertificatePath); 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 @@ -318,7 +326,9 @@ void create_Console() { io.opentelemetry.sdk.metrics.export.MetricExporter exporter = MetricExporterFactory.getInstance() - .create(new PushMetricExporterModel().withConsole(new ConsoleExporterModel()), context); + .create( + new PushMetricExporterModel().withConsole(new ConsoleMetricExporterModel()), + context); cleanup.addCloseable(exporter); cleanup.addCloseables(closeables); @@ -356,7 +366,9 @@ void create_SpiExporter_Unknown() { .create( new PushMetricExporterModel() .withAdditionalProperty( - "unknown_key", ImmutableMap.of("key1", "value1")), + "unknown_key", + new PushMetricExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), context)) .isInstanceOf(DeclarativeConfigException.class) .hasMessage( @@ -369,7 +381,10 @@ void create_SpiExporter_Valid() { MetricExporterFactory.getInstance() .create( new PushMetricExporterModel() - .withAdditionalProperty("test", ImmutableMap.of("key1", "value1")), + .withAdditionalProperty( + "test", + new PushMetricExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), context); assertThat(metricExporter) .isInstanceOf(MetricExporterComponentProvider.TestMetricExporter.class); diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java index 3fdc76e0dc8..bc63ca7bdcb 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java @@ -190,8 +190,10 @@ void create_PullPrometheusConfigured() throws IOException { .withIncluded(singletonList("foo")) .withExcluded(singletonList("bar"))) .withWithoutScopeInfo(true) - .withWithoutTypeSuffix(true) - .withWithoutUnits(true)))), + .withTranslationStrategy( + ExperimentalPrometheusMetricExporterModel + .ExperimentalPrometheusTranslationStrategy + .UNDERSCORE_ESCAPING_WITHOUT_SUFFIXES)))), context); MetricReader reader = readerAndCardinalityLimits.getMetricReader(); cleanup.addCloseable(reader); 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 d06e9164356..150c3875e85 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 @@ -114,6 +114,7 @@ private static Stream fileFormatArgs() { 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)); } diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java index 317091fbf19..8fb0ffda39a 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SamplerFactoryTest.java @@ -8,7 +8,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.google.common.collect.ImmutableMap; import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.internal.testing.CleanupExtension; import io.opentelemetry.internal.testing.slf4j.SuppressLogger; @@ -16,9 +15,10 @@ 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.JaegerRemoteSamplerModel; +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.trace.jaeger.sampler.JaegerRemoteSampler; import java.io.Closeable; @@ -116,8 +116,8 @@ private static Stream createArguments() { .build()), Arguments.of( new SamplerModel() - .withJaegerRemote( - new JaegerRemoteSamplerModel() + .withJaegerRemoteDevelopment( + new ExperimentalJaegerRemoteSamplerModel() .withEndpoint("http://jaeger-remote-endpoint") .withInterval(10_000) .withInitialSampler( @@ -139,7 +139,9 @@ void create_SpiExporter_Unknown() { .create( new SamplerModel() .withAdditionalProperty( - "unknown_key", ImmutableMap.of("key1", "value1")), + "unknown_key", + new SamplerPropertyModel() + .withAdditionalProperty("key1", "value1")), context)) .isInstanceOf(DeclarativeConfigException.class) .hasMessage( @@ -153,7 +155,9 @@ void create_SpiExporter_Valid() { SamplerFactory.getInstance() .create( new SamplerModel() - .withAdditionalProperty("test", ImmutableMap.of("key1", "value1")), + .withAdditionalProperty( + "test", + new SamplerPropertyModel().withAdditionalProperty("key1", "value1")), context); assertThat(sampler).isInstanceOf(SamplerComponentProvider.TestSampler.class); assertThat(((SamplerComponentProvider.TestSampler) sampler).config.getString("key1")) diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java index 2896cc55bd3..6cb853e4b69 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java @@ -9,7 +9,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.google.common.collect.ImmutableMap; import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; @@ -17,17 +16,18 @@ 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.exporter.zipkin.ZipkinSpanExporter; import io.opentelemetry.internal.testing.CleanupExtension; import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper; 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.ZipkinSpanExporterModel; +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; @@ -136,9 +136,11 @@ void create_OtlpHttpConfigured(@TempDir Path tempDir) .withValue("value2"))) .withCompression("gzip") .withTimeout(15_000) - .withCertificateFile(certificatePath) - .withClientKeyFile(clientKeyPath) - .withClientCertificateFile(clientCertificatePath)), + .withTls( + new HttpTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath))), context); cleanup.addCloseable(exporter); cleanup.addCloseables(closeables); @@ -164,10 +166,11 @@ void create_OtlpHttpConfigured(@TempDir Path tempDir) }); assertThat(configProperties.getString("compression")).isEqualTo("gzip"); assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - assertThat(configProperties.getString("certificate_file")).isEqualTo(certificatePath); - assertThat(configProperties.getString("client_key_file")).isEqualTo(clientKeyPath); - assertThat(configProperties.getString("client_certificate_file")) - .isEqualTo(clientCertificatePath); + 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 @@ -242,9 +245,11 @@ void create_OtlpGrpcConfigured(@TempDir Path tempDir) .withValue("value2"))) .withCompression("gzip") .withTimeout(15_000) - .withCertificateFile(certificatePath) - .withClientKeyFile(clientKeyPath) - .withClientCertificateFile(clientCertificatePath)), + .withTls( + new GrpcTlsModel() + .withCaFile(certificatePath) + .withKeyFile(clientKeyPath) + .withCertFile(clientCertificatePath))), context); cleanup.addCloseable(exporter); cleanup.addCloseables(closeables); @@ -270,10 +275,11 @@ void create_OtlpGrpcConfigured(@TempDir Path tempDir) }); assertThat(configProperties.getString("compression")).isEqualTo("gzip"); assertThat(configProperties.getInt("timeout")).isEqualTo(Duration.ofSeconds(15).toMillis()); - assertThat(configProperties.getString("certificate_file")).isEqualTo(certificatePath); - assertThat(configProperties.getString("client_key_file")).isEqualTo(clientKeyPath); - assertThat(configProperties.getString("client_certificate_file")) - .isEqualTo(clientCertificatePath); + 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 @@ -291,61 +297,6 @@ void create_Console() { assertThat(exporter.toString()).isEqualTo(expectedExporter.toString()); } - @Test - void create_ZipkinDefaults() { - List closeables = new ArrayList<>(); - ZipkinSpanExporter expectedExporter = ZipkinSpanExporter.builder().build(); - - cleanup.addCloseable(expectedExporter); - - SpanExporter exporter = - SpanExporterFactory.getInstance() - .create(new SpanExporterModel().withZipkin(new ZipkinSpanExporterModel()), 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("zipkin"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isNull(); - assertThat(configProperties.getLong("timeout")).isNull(); - } - - @Test - void create_ZipkinConfigured() { - List closeables = new ArrayList<>(); - ZipkinSpanExporter expectedExporter = - ZipkinSpanExporter.builder() - .setEndpoint("http://zipkin:9411/v1/v2/spans") - .setReadTimeout(Duration.ofSeconds(15)) - .build(); - cleanup.addCloseable(expectedExporter); - - SpanExporter exporter = - SpanExporterFactory.getInstance() - .create( - new SpanExporterModel() - .withZipkin( - new ZipkinSpanExporterModel() - .withEndpoint("http://zipkin:9411/v1/v2/spans") - .withTimeout(15_000)), - 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("zipkin"); - assertThat(configProperties).isNotNull(); - assertThat(configProperties.getString("endpoint")).isEqualTo("http://zipkin:9411/v1/v2/spans"); - assertThat(configProperties.getLong("timeout")).isEqualTo(15_000); - } - @Test void create_OtlpFile() { List closeables = new ArrayList<>(); @@ -379,7 +330,9 @@ void create_SpiExporter_Unknown() { .create( new SpanExporterModel() .withAdditionalProperty( - "unknown_key", ImmutableMap.of("key1", "value1")), + "unknown_key", + new SpanExporterPropertyModel() + .withAdditionalProperty("key1", "value1")), context)) .isInstanceOf(DeclarativeConfigException.class) .hasMessage( @@ -393,7 +346,9 @@ void create_SpiExporter_Valid() { SpanExporterFactory.getInstance() .create( new SpanExporterModel() - .withAdditionalProperty("test", ImmutableMap.of("key1", "value1")), + .withAdditionalProperty( + "test", + new SpanExporterPropertyModel().withAdditionalProperty("key1", "value1")), context); assertThat(spanExporter).isInstanceOf(SpanExporterComponentProvider.TestSpanExporter.class); assertThat( diff --git a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java index 87e9bba97f6..ffc0de8cb6e 100644 --- a/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java +++ b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanProcessorFactoryTest.java @@ -8,7 +8,6 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import com.google.common.collect.ImmutableMap; import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.internal.testing.CleanupExtension; @@ -19,6 +18,7 @@ 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 java.io.Closeable; import java.time.Duration; import java.util.ArrayList; @@ -143,7 +143,9 @@ void create_SpiProcessor_Unknown() { .create( new SpanProcessorModel() .withAdditionalProperty( - "unknown_key", ImmutableMap.of("key1", "value1")), + "unknown_key", + new SpanProcessorPropertyModel() + .withAdditionalProperty("key1", "value1")), context)) .isInstanceOf(DeclarativeConfigException.class) .hasMessage( @@ -156,7 +158,9 @@ void create_SpiExporter_Valid() { SpanProcessorFactory.getInstance() .create( new SpanProcessorModel() - .withAdditionalProperty("test", ImmutableMap.of("key1", "value1")), + .withAdditionalProperty( + "test", + new SpanProcessorPropertyModel().withAdditionalProperty("key1", "value1")), context); assertThat(spanProcessor).isInstanceOf(SpanProcessorComponentProvider.TestSpanProcessor.class); Assertions.assertThat( 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 667a659e91a..608604e1053 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 @@ -27,7 +27,7 @@ public Class getType() { @Override public String getName() { - return "jaeger_remote"; + return "jaeger_remote/development"; } @Override