From 3c0e39d5c0b1dc8917e71771c33c0c3bf01e3ed9 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Thu, 20 Nov 2025 16:30:54 +0900 Subject: [PATCH 1/9] Update to latest unreleased opentelemetry-configuration --- .../InstrumentationConfigUtilTest.java | 33 ++-- .../internal/OtlpDeclarativeConfigUtil.java | 8 +- sdk-extensions/incubator/build.gradle.kts | 7 +- .../fileconfig/ComposableSamplerFactory.java | 45 +++++ .../incubator/fileconfig/FileConfigUtil.java | 21 +- .../fileconfig/LogRecordExporterFactory.java | 42 +++- .../fileconfig/LogRecordProcessorFactory.java | 3 +- .../fileconfig/MetricExporterFactory.java | 45 +++-- .../fileconfig/ResourceDetectorFactory.java | 37 +++- .../incubator/fileconfig/SamplerFactory.java | 35 +++- .../fileconfig/SpanExporterFactory.java | 51 +++-- .../fileconfig/SpanProcessorFactory.java | 3 +- .../fileconfig/TextMapPropagatorFactory.java | 3 +- .../DeclarativeConfigurationCreateTest.java | 16 +- .../DeclarativeConfigurationParseTest.java | 180 ++++++++++++------ .../LogRecordExporterFactoryTest.java | 47 +++-- .../LogRecordProcessorFactoryTest.java | 11 +- .../fileconfig/MetricExporterFactoryTest.java | 53 ++++-- .../fileconfig/MetricReaderFactoryTest.java | 6 +- .../fileconfig/SamplerFactoryTest.java | 16 +- .../fileconfig/SpanExporterFactoryTest.java | 46 +++-- .../fileconfig/SpanProcessorFactoryTest.java | 10 +- .../JaegerRemoteSamplerComponentProvider.java | 2 +- 23 files changed, 523 insertions(+), 197 deletions(-) create mode 100644 sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java 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..fd0b6ce1ba8 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 @@ -17,6 +17,7 @@ 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.ExperimentalLanguageSpecificInstrumentationModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalLanguageSpecificInstrumentationPropertyModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import java.io.ByteArrayInputStream; @@ -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,7 +125,8 @@ void getInstrumentationConfigModel_KitchenSink() { } private static ConfigProvider withInstrumentationConfig( - String instrumentationName, Map instrumentationConfig) { + String instrumentationName, + ExperimentalLanguageSpecificInstrumentationPropertyModel instrumentationConfig) { ExperimentalLanguageSpecificInstrumentationModel javaConfig = new ExperimentalLanguageSpecificInstrumentationModel(); javaConfig.setAdditionalProperty(instrumentationName, instrumentationConfig); 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/sdk-extensions/incubator/build.gradle.kts b/sdk-extensions/incubator/build.gradle.kts index a3947db8715..a5644b5f852 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") @@ -59,7 +60,7 @@ dependencies { // ... proceed with normal sourcesJar, compileJava, etc val configurationTag = "1.0.0-rc.1" -val configurationRef = "refs/tags/v$configurationTag" // Replace with commit SHA to point to experiment with a specific commit +val configurationRef = "be1a43de6745da73ce1b6339c34b1e260e5b135b" // Replace with commit SHA to point to experiment with a specific commitco val configurationRepoZip = "https://github.com/open-telemetry/opentelemetry-configuration/archive/$configurationRef.zip" val buildDirectory = layout.buildDirectory.asFile.get() @@ -111,6 +112,10 @@ jsonSchema2Pojo { // Append Model as suffix to the generated classes. classNameSuffix = "Model" + + fileFilter = FileFilter { + it.path.endsWith(".json") + } } val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo") 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..38344a4ef71 --- /dev/null +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableSamplerFactory.java @@ -0,0 +1,45 @@ +/* + * 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.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); + } + 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..803c10285d2 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,21 @@ 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(",", "[", "]"))); + } + } + + static void requireNonNullResource(@Nullable Object resource, String resourceName) { + if (resource == null) { + throw new DeclarativeConfigException(resourceName + " must be set"); + } + } } 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..ff9bf3b84a5 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 (model.getZipkin() != null) { + requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); + key = "zipkin"; + resource = model.getZipkin(); + } + if (key == null || resource == null) { + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), RESOURCE_NAME); + key = keyValue.getKey(); + resource = keyValue.getValue(); + } + + 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/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..17b4b1a4545 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,18 @@ 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.ExperimentalComposableProbabilitySamplerModel; +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.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,13 +41,19 @@ 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.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; @@ -67,8 +80,6 @@ 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; @@ -114,7 +125,7 @@ void parse_BadInputStream() { void parse_KitchenSinkExampleFile() throws IOException { OpenTelemetryConfigurationModel expected = new OpenTelemetryConfigurationModel(); - expected.withFileFormat("1.0-rc.1"); + expected.withFileFormat("1.0-rc.2"); expected.withDisabled(false); expected.withLogLevel("info"); @@ -168,13 +179,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 +231,16 @@ 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() + .withProbability( + new ExperimentalComposableProbabilitySamplerModel() + .withRatio(0.001)))) .withLocalParentNotSampled( new SamplerModel().withAlwaysOff(new AlwaysOffSamplerModel()))); tracerProvider.withSampler(sampler); @@ -250,9 +268,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 +292,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 +305,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( @@ -343,7 +365,12 @@ void parse_KitchenSinkExampleFile() throws IOException { Collections.singletonList( new ExperimentalLoggerMatcherAndConfigModel() .withName("io.opentelemetry.contrib.*") - .withConfig(new ExperimentalLoggerConfigModel().withDisabled(false)))); + .withConfig( + new ExperimentalLoggerConfigModel() + .withDisabled(false) + .withMinimumSeverity( + ExperimentalLoggerConfigModel.ExperimentalSeverityNumber.INFO) + .withTraceBased(true)))); loggerProvider.withLoggerConfiguratorDevelopment(loggerConfigurator); LogRecordProcessorModel logRecordProcessor1 = @@ -359,9 +386,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 +410,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 +423,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 +472,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 +508,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 +531,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 +552,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 +566,6 @@ void parse_KitchenSinkExampleFile() throws IOException { .withHeadersList("api-key=1234") .withCompression("gzip") .withTimeout(10_000) - .withInsecure(false) .withTemporalityPreference( OtlpHttpMetricExporterModel.ExporterTemporalityPreference .DELTA) @@ -571,7 +610,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, @@ -634,22 +682,22 @@ void parse_KitchenSinkExampleFile() throws IOException { 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,47 +705,69 @@ 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 @@ -706,7 +776,7 @@ void parse_KitchenSinkExampleFile() throws IOException { OpenTelemetryConfigurationModel config = DeclarativeConfiguration.parse(configExampleFile); // General config - assertThat(config.getFileFormat()).isEqualTo("1.0-rc.1"); + assertThat(config.getFileFormat()).isEqualTo("1.0-rc.2"); assertThat(config.getResource()).isEqualTo(resource); assertThat(config.getAttributeLimits()).isEqualTo(attributeLimits); assertThat(config.getPropagator()).isEqualTo(propagator); 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/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..f4fbb98df4a 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; @@ -23,10 +22,13 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.component.SpanExporterComponentProvider; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ConsoleExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalOtlpFileExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.GrpcTlsModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.HttpTlsModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.NameStringValuePairModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpGrpcExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterPropertyModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ZipkinSpanExporterModel; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.io.Closeable; @@ -136,9 +138,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 +168,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 +247,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 +277,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 @@ -379,7 +387,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 +403,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 From c5a268f4e5df37acac4e0caa5dd448e9a3c1793b Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Thu, 20 Nov 2025 16:32:31 +0900 Subject: [PATCH 2/9] Drift --- sdk-extensions/incubator/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-extensions/incubator/build.gradle.kts b/sdk-extensions/incubator/build.gradle.kts index a5644b5f852..483ead70322 100644 --- a/sdk-extensions/incubator/build.gradle.kts +++ b/sdk-extensions/incubator/build.gradle.kts @@ -60,7 +60,7 @@ dependencies { // ... proceed with normal sourcesJar, compileJava, etc val configurationTag = "1.0.0-rc.1" -val configurationRef = "be1a43de6745da73ce1b6339c34b1e260e5b135b" // Replace with commit SHA to point to experiment with a specific commitco +val configurationRef = "be1a43de6745da73ce1b6339c34b1e260e5b135b" // 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() From b5e73dd05c0ca82ff65b88ac17d430b44adba201 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Thu, 20 Nov 2025 16:32:58 +0900 Subject: [PATCH 3/9] Cleanup --- .../sdk/extension/incubator/fileconfig/FileConfigUtil.java | 6 ------ 1 file changed, 6 deletions(-) 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 803c10285d2..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 @@ -59,10 +59,4 @@ static void requireNullResource( + additionalProperties.keySet().stream().collect(joining(",", "[", "]"))); } } - - static void requireNonNullResource(@Nullable Object resource, String resourceName) { - if (resource == null) { - throw new DeclarativeConfigException(resourceName + " must be set"); - } - } } From 02290c27b95b177a55db86ea33e9e635f3c05db1 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Tue, 25 Nov 2025 09:12:17 -0600 Subject: [PATCH 4/9] update to latest with single file schema --- .../api/incubator/InstrumentationConfigUtilTest.java | 5 +++-- sdk-extensions/incubator/build.gradle.kts | 8 ++------ .../fileconfig/DeclarativeConfigurationParseTest.java | 9 +++++---- 3 files changed, 10 insertions(+), 12 deletions(-) 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 fd0b6ce1ba8..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,9 +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.ExperimentalLanguageSpecificInstrumentationPropertyModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.InstrumentationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; @@ -133,7 +133,8 @@ private static ConfigProvider withInstrumentationConfig( return SdkConfigProvider.create( new OpenTelemetryConfigurationModel() - .withInstrumentationDevelopment(new InstrumentationModel().withJava(javaConfig))); + .withInstrumentationDevelopment( + new ExperimentalInstrumentationModel().withJava(javaConfig))); } private static class Model { diff --git a/sdk-extensions/incubator/build.gradle.kts b/sdk-extensions/incubator/build.gradle.kts index 483ead70322..2e7eb60fe53 100644 --- a/sdk-extensions/incubator/build.gradle.kts +++ b/sdk-extensions/incubator/build.gradle.kts @@ -60,7 +60,7 @@ dependencies { // ... proceed with normal sourcesJar, compileJava, etc val configurationTag = "1.0.0-rc.1" -val configurationRef = "be1a43de6745da73ce1b6339c34b1e260e5b135b" // Replace with commit SHA to point to experiment with a specific commit +val configurationRef = "8826969b88d4ec720c3ebfe5c95b27aca5c238a9" // 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() @@ -88,7 +88,7 @@ val deleteTypeDescriptions by tasks.registering(Delete::class) { } 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" @@ -112,10 +112,6 @@ jsonSchema2Pojo { // Append Model as suffix to the generated classes. classNameSuffix = "Model" - - fileFilter = FileFilter { - it.path.endsWith(".json") - } } val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo") 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 17b4b1a4545..9a0b9c89af9 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 @@ -30,6 +30,7 @@ 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; @@ -55,7 +56,6 @@ 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; @@ -674,8 +674,8 @@ void parse_KitchenSinkExampleFile() throws IOException { // end MeterProvider config // start instrumentation config - InstrumentationModel instrumentation = - new InstrumentationModel() + ExperimentalInstrumentationModel instrumentation = + new ExperimentalInstrumentationModel() .withGeneral( new ExperimentalGeneralInstrumentationModel() .withPeer( @@ -830,7 +830,8 @@ void parse_KitchenSinkExampleFile() throws IOException { assertThat(configMeterProvider).isEqualTo(meterProvider); // Instrumentation config - InstrumentationModel configInstrumentation = config.getInstrumentationDevelopment(); + ExperimentalInstrumentationModel configInstrumentation = + config.getInstrumentationDevelopment(); assertThat(configInstrumentation).isEqualTo(instrumentation); // All configuration From 61fe08caa8bc33b26bba2080a7e19fc227fe5cf3 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 10 Dec 2025 16:21:23 -0600 Subject: [PATCH 5/9] update to latest ref as of 12/10 --- .../ZipkinSpanExporterComponentProvider.java | 48 ---------- ...toconfigure.spi.internal.ComponentProvider | 1 - sdk-extensions/incubator/build.gradle.kts | 2 +- .../fileconfig/ComposableSamplerFactory.java | 6 ++ .../fileconfig/SpanExporterFactory.java | 10 +-- .../DeclarativeConfigurationParseTest.java | 88 ++++++++++++++++--- .../fileconfig/SpanExporterFactoryTest.java | 57 ------------ 7 files changed, 90 insertions(+), 122 deletions(-) delete mode 100644 exporters/zipkin/src/main/java/io/opentelemetry/exporter/zipkin/internal/ZipkinSpanExporterComponentProvider.java delete mode 100644 exporters/zipkin/src/main/resources/META-INF/services/io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider 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 2e7eb60fe53..0fc27584a67 100644 --- a/sdk-extensions/incubator/build.gradle.kts +++ b/sdk-extensions/incubator/build.gradle.kts @@ -60,7 +60,7 @@ dependencies { // ... proceed with normal sourcesJar, compileJava, etc val configurationTag = "1.0.0-rc.1" -val configurationRef = "8826969b88d4ec720c3ebfe5c95b27aca5c238a9" // Replace with commit SHA to point to experiment with a specific commit +val configurationRef = "447ff81a6dc566243813e6e45e378adf9a5b0bd7" // 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() 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 index 38344a4ef71..02e36737322 100644 --- 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 @@ -6,6 +6,7 @@ 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; @@ -38,6 +39,11 @@ public ComposableSampler create( } return ComposableSampler.probability(ratio); } + ExperimentalComposableRuleBasedSamplerModel ruleBased = model.getRuleBased(); + if (ruleBased != null) { + // TODO: interpret model + return ComposableSampler.ruleBasedBuilder().build(); + } 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/SpanExporterFactory.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactory.java index ff9bf3b84a5..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 @@ -48,17 +48,17 @@ public SpanExporter create(SpanExporterModel model, DeclarativeConfigContext con key = "console"; resource = model.getConsole(); } - if (model.getZipkin() != null) { - requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); - key = "zipkin"; - resource = model.getZipkin(); - } 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/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 9a0b9c89af9..fb554cef5dd 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 @@ -22,7 +22,15 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.CardinalityLimitsModel; 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; @@ -49,6 +57,7 @@ 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; @@ -83,6 +92,8 @@ 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.SpanExporterPropertyModel; +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; @@ -92,7 +103,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; @@ -127,7 +137,7 @@ void parse_KitchenSinkExampleFile() throws IOException { expected.withFileFormat("1.0-rc.2"); expected.withDisabled(false); - expected.withLogLevel("info"); + expected.withLogLevel(OpenTelemetryConfigurationModel.SeverityNumber.INFO); // General config ResourceModel resource = @@ -238,9 +248,53 @@ void parse_KitchenSinkExampleFile() throws IOException { new SamplerModel() .withCompositeDevelopment( new ExperimentalComposableSamplerModel() - .withProbability( - new ExperimentalComposableProbabilitySamplerModel() - .withRatio(0.001)))) + .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); @@ -330,10 +384,12 @@ void parse_KitchenSinkExampleFile() throws IOException { new BatchSpanProcessorModel() .withExporter( new SpanExporterModel() - .withZipkin( - new ZipkinSpanExporterModel() - .withEndpoint("http://localhost:9411/api/v2/spans") - .withTimeout(10_000)))); + .withAdditionalProperty( + "zipkin", + new SpanExporterPropertyModel() + .withAdditionalProperty( + "endpoint", "http://localhost:9411/api/v2/spans") + .withAdditionalProperty("timeout", 10_000)))); SpanProcessorModel spanProcessor6 = new SpanProcessorModel() .withSimple( @@ -369,7 +425,8 @@ void parse_KitchenSinkExampleFile() throws IOException { new ExperimentalLoggerConfigModel() .withDisabled(false) .withMinimumSeverity( - ExperimentalLoggerConfigModel.ExperimentalSeverityNumber.INFO) + // TODO: SeverityNumber should not be nested + OpenTelemetryConfigurationModel.SeverityNumber.INFO) .withTraceBased(true)))); loggerProvider.withLoggerConfiguratorDevelopment(loggerConfigurator); @@ -771,6 +828,13 @@ void parse_KitchenSinkExampleFile() throws IOException { 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); @@ -834,6 +898,10 @@ void parse_KitchenSinkExampleFile() throws IOException { 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/SpanExporterFactoryTest.java b/sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/SpanExporterFactoryTest.java index f4fbb98df4a..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 @@ -16,7 +16,6 @@ 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; @@ -29,7 +28,6 @@ import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporterPropertyModel; -import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ZipkinSpanExporterModel; import io.opentelemetry.sdk.trace.export.SpanExporter; import java.io.Closeable; import java.io.IOException; @@ -299,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<>(); From 20d944a58c8418fb40a6b02dfcef15d7055f42e8 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 10 Dec 2025 16:26:28 -0600 Subject: [PATCH 6/9] remove task for deleting type_descriptions.yaml --- sdk-extensions/incubator/build.gradle.kts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/sdk-extensions/incubator/build.gradle.kts b/sdk-extensions/incubator/build.gradle.kts index 0fc27584a67..a189fdd00db 100644 --- a/sdk-extensions/incubator/build.gradle.kts +++ b/sdk-extensions/incubator/build.gradle.kts @@ -52,11 +52,10 @@ 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" @@ -82,11 +81,6 @@ 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/opentelemetry_configuration.json")) targetDirectory = file("$buildDirectory/generated/sources/js2p/java/main") @@ -115,7 +109,7 @@ jsonSchema2Pojo { } val generateJsonSchema2Pojo = tasks.getByName("generateJsonSchema2Pojo") -generateJsonSchema2Pojo.dependsOn(deleteTypeDescriptions) +generateJsonSchema2Pojo.dependsOn(unzipConfigurationSchema) val jsonSchema2PojoPostProcessing by tasks.registering(Copy::class) { dependsOn(generateJsonSchema2Pojo) From 10b06bd9e4f6b39c76fa10a280b2df228b8425c4 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 11 Dec 2025 13:31:02 -0600 Subject: [PATCH 7/9] Add ExperimentalComposableRuleBasedSamplerModel implementation --- .../ComposableRuleBasedSamplerFactory.java | 262 ++++++++++++++++ .../fileconfig/ComposableSamplerFactory.java | 3 +- .../samplers/ComposableRuleBasedSampler.java | 5 + ...ComposableRuleBasedSamplerFactoryTest.java | 292 ++++++++++++++++++ 4 files changed, 560 insertions(+), 2 deletions(-) create mode 100644 sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactory.java create mode 100644 sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ComposableRuleBasedSamplerFactoryTest.java 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 index 02e36737322..4892e66b1c4 100644 --- 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 @@ -41,8 +41,7 @@ public ComposableSampler create( } ExperimentalComposableRuleBasedSamplerModel ruleBased = model.getRuleBased(); if (ruleBased != null) { - // TODO: interpret model - return ComposableSampler.ruleBasedBuilder().build(); + return ComposableRuleBasedSamplerFactory.getInstance().create(ruleBased, context); } Map.Entry keyValue = FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "composable sampler"); 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); + } +} From 3672a2df53b635e5191c2e49ffe41d5217d1bdd4 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Thu, 11 Dec 2025 14:33:52 -0600 Subject: [PATCH 8/9] Update to rc.3 --- sdk-extensions/incubator/build.gradle.kts | 4 +-- .../DeclarativeConfigurationParseTest.java | 31 +++---------------- ...OpenTelemetryConfigurationFactoryTest.java | 1 + 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/sdk-extensions/incubator/build.gradle.kts b/sdk-extensions/incubator/build.gradle.kts index a189fdd00db..443a89c7c9f 100644 --- a/sdk-extensions/incubator/build.gradle.kts +++ b/sdk-extensions/incubator/build.gradle.kts @@ -58,8 +58,8 @@ dependencies { // 6. deleteJs2pTmp - delete tmp directory // ... proceed with normal sourcesJar, compileJava, etc -val configurationTag = "1.0.0-rc.1" -val configurationRef = "447ff81a6dc566243813e6e45e378adf9a5b0bd7" // Replace with commit SHA to point to experiment with a specific commit +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() 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 fb554cef5dd..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 @@ -92,7 +92,6 @@ 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.SpanExporterPropertyModel; 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; @@ -135,7 +134,7 @@ void parse_BadInputStream() { void parse_KitchenSinkExampleFile() throws IOException { OpenTelemetryConfigurationModel expected = new OpenTelemetryConfigurationModel(); - expected.withFileFormat("1.0-rc.2"); + expected.withFileFormat("1.0-rc.3"); expected.withDisabled(false); expected.withLogLevel(OpenTelemetryConfigurationModel.SeverityNumber.INFO); @@ -379,30 +378,13 @@ void parse_KitchenSinkExampleFile() throws IOException { new ExperimentalOtlpFileExporterModel() .withOutputStream("stdout")))); SpanProcessorModel spanProcessor5 = - new SpanProcessorModel() - .withBatch( - new BatchSpanProcessorModel() - .withExporter( - new SpanExporterModel() - .withAdditionalProperty( - "zipkin", - new SpanExporterPropertyModel() - .withAdditionalProperty( - "endpoint", "http://localhost:9411/api/v2/spans") - .withAdditionalProperty("timeout", 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 @@ -840,7 +822,7 @@ void parse_KitchenSinkExampleFile() throws IOException { OpenTelemetryConfigurationModel config = DeclarativeConfiguration.parse(configExampleFile); // General config - assertThat(config.getFileFormat()).isEqualTo("1.0-rc.2"); + assertThat(config.getFileFormat()).isEqualTo("1.0-rc.3"); assertThat(config.getResource()).isEqualTo(resource); assertThat(config.getAttributeLimits()).isEqualTo(attributeLimits); assertThat(config.getPropagator()).isEqualTo(propagator); @@ -854,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 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)); } From bc11574c007155617815d334e7c80a8ec07de68a Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Fri, 19 Dec 2025 09:24:41 -0600 Subject: [PATCH 9/9] Fix exporter factory, resource detector factory validation --- sdk-extensions/incubator/build.gradle.kts | 3 +- .../fileconfig/LogRecordExporterFactory.java | 40 ++++++------------ .../fileconfig/MetricExporterFactory.java | 37 +++++------------ .../fileconfig/ResourceDetectorFactory.java | 35 +++++----------- .../fileconfig/SpanExporterFactory.java | 41 +++++-------------- 5 files changed, 46 insertions(+), 110 deletions(-) diff --git a/sdk-extensions/incubator/build.gradle.kts b/sdk-extensions/incubator/build.gradle.kts index c68458815bd..94761a964b5 100644 --- a/sdk-extensions/incubator/build.gradle.kts +++ b/sdk-extensions/incubator/build.gradle.kts @@ -38,7 +38,6 @@ dependencies { testImplementation(project(":exporters:logging-otlp")) testImplementation(project(":exporters:otlp:all")) testImplementation(project(":exporters:prometheus")) - testImplementation(project(":exporters:zipkin")) testImplementation(project(":sdk-extensions:jaeger-remote-sampler")) testImplementation(project(":extensions:trace-propagators")) testImplementation("edu.berkeley.cs.jqf:jqf-fuzz") @@ -199,9 +198,11 @@ val buildGraalVmReflectionJson = tasks.register("buildGraalVmReflectionJson") { tasks.getByName("compileJava").dependsOn(deleteJs2pTmp) tasks.getByName("sourcesJar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson) tasks.getByName("jar").dependsOn(deleteJs2pTmp, buildGraalVmReflectionJson) +tasks.getByName("javadoc").dependsOn(buildGraalVmReflectionJson) // Exclude jsonschema2pojo generated sources from checkstyle tasks.named("checkstyleMain") { + dependsOn(buildGraalVmReflectionJson) exclude("**/fileconfig/internal/model/**") } 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 7d89c2d0d7a..9ebf2e692f6 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,16 +5,12 @@ 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.LinkedHashMap; 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() {} @@ -25,38 +21,26 @@ static LogRecordExporterFactory getInstance() { @Override public LogRecordExporter create(LogRecordExporterModel model, DeclarativeConfigContext context) { - - String key = null; - Object resource = null; + Map exporterResourceByName = new LinkedHashMap<>(); if (model.getOtlpHttp() != null) { - key = "otlp_http"; - resource = model.getOtlpHttp(); + exporterResourceByName.put("otlp_http", model.getOtlpHttp()); } if (model.getOtlpGrpc() != null) { - requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); - key = "otlp_grpc"; - resource = model.getOtlpGrpc(); + exporterResourceByName.put("otlp_grpc", model.getOtlpGrpc()); } if (model.getOtlpFileDevelopment() != null) { - requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); - key = "otlp_file/development"; - resource = model.getOtlpFileDevelopment(); + exporterResourceByName.put("otlp_file/development", 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(); + exporterResourceByName.put("console", model.getConsole()); } + exporterResourceByName.putAll(model.getAdditionalProperties()); - LogRecordExporter logRecordExporter = - context.loadComponent(LogRecordExporter.class, key, resource); - return context.addCloseable(logRecordExporter); + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(exporterResourceByName, "log record exporter"); + LogRecordExporter metricExporter = + context.loadComponent(LogRecordExporter.class, keyValue.getKey(), keyValue.getValue()); + return context.addCloseable(metricExporter); } } 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 fefadc8d425..a7ab5eb7b10 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,16 +5,12 @@ 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.LinkedHashMap; 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() {} @@ -25,37 +21,26 @@ static MetricExporterFactory getInstance() { @Override public MetricExporter create(PushMetricExporterModel model, DeclarativeConfigContext context) { - - String key = null; - Object resource = null; + Map exporterResourceByName = new LinkedHashMap<>(); if (model.getOtlpHttp() != null) { - key = "otlp_http"; - resource = model.getOtlpHttp(); + exporterResourceByName.put("otlp_http", model.getOtlpHttp()); } if (model.getOtlpGrpc() != null) { - requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); - key = "otlp_grpc"; - resource = model.getOtlpGrpc(); + exporterResourceByName.put("otlp_grpc", model.getOtlpGrpc()); } if (model.getOtlpFileDevelopment() != null) { - requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); - key = "otlp_file/development"; - resource = model.getOtlpFileDevelopment(); + exporterResourceByName.put("otlp_file/development", 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(); + exporterResourceByName.put("console", model.getConsole()); } + exporterResourceByName.putAll(model.getAdditionalProperties()); - MetricExporter metricExporter = context.loadComponent(MetricExporter.class, key, resource); + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(exporterResourceByName, "metric exporter"); + MetricExporter metricExporter = + context.loadComponent(MetricExporter.class, keyValue.getKey(), keyValue.getValue()); 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 cd13b74845f..56966606e9b 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,17 +5,13 @@ 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.LinkedHashMap; import java.util.Map; final class ResourceDetectorFactory implements Factory { - private static final String RESOURCE_NAME = "resource detector"; - private static final ResourceDetectorFactory INSTANCE = new ResourceDetectorFactory(); private ResourceDetectorFactory() {} @@ -27,35 +23,24 @@ static ResourceDetectorFactory getInstance() { @Override public Resource create( ExperimentalResourceDetectorModel model, DeclarativeConfigContext context) { - String key = null; - Object value = null; + Map detectorResourceByName = new LinkedHashMap<>(); if (model.getContainer() != null) { - key = "container"; - value = model.getContainer(); + detectorResourceByName.put("container", model.getContainer()); } if (model.getHost() != null) { - requireNullResource(value, RESOURCE_NAME, model.getAdditionalProperties()); - key = "host"; - value = model.getHost(); + detectorResourceByName.put("host", model.getHost()); } if (model.getProcess() != null) { - requireNullResource(value, RESOURCE_NAME, model.getAdditionalProperties()); - key = "process"; - value = model.getProcess(); + detectorResourceByName.put("process", 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(); + detectorResourceByName.put("service", model.getService()); } + detectorResourceByName.putAll(model.getAdditionalProperties()); - return context.loadComponent(Resource.class, key, value); + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(detectorResourceByName, "resource detector"); + return context.loadComponent(Resource.class, keyValue.getKey(), keyValue.getValue()); } } 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 50664773a2d..08ac568fb60 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,16 +5,13 @@ 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.LinkedHashMap; 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() {} @@ -25,42 +22,26 @@ static SpanExporterFactory getInstance() { @Override public SpanExporter create(SpanExporterModel model, DeclarativeConfigContext context) { - - String key = null; - Object resource = null; + Map exporterResourceByName = new LinkedHashMap<>(); if (model.getOtlpHttp() != null) { - key = "otlp_http"; - resource = model.getOtlpHttp(); + exporterResourceByName.put("otlp_http", model.getOtlpHttp()); } if (model.getOtlpGrpc() != null) { - requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); - key = "otlp_grpc"; - resource = model.getOtlpGrpc(); + exporterResourceByName.put("otlp_grpc", model.getOtlpGrpc()); } if (model.getOtlpFileDevelopment() != null) { - requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties()); - key = "otlp_file/development"; - resource = model.getOtlpFileDevelopment(); + exporterResourceByName.put("otlp_file/development", 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(); + exporterResourceByName.put("console", model.getConsole()); } + exporterResourceByName.putAll(model.getAdditionalProperties()); - SpanExporter spanExporter = context.loadComponent(SpanExporter.class, key, resource); + Map.Entry keyValue = + FileConfigUtil.getSingletonMapEntry(exporterResourceByName, "span exporter"); + SpanExporter spanExporter = + context.loadComponent(SpanExporter.class, keyValue.getKey(), keyValue.getValue()); return context.addCloseable(spanExporter); } }