Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(
Expand All @@ -85,21 +88,20 @@ void getInstrumentationConfigModel_KitchenSink() {
ConfigProvider configProvider =
withInstrumentationConfig(
"my_instrumentation_library",
ImmutableMap.<String, Object>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";
Expand All @@ -123,7 +125,8 @@ void getInstrumentationConfigModel_KitchenSink() {
}

private static ConfigProvider withInstrumentationConfig(
String instrumentationName, Map<String, Object> instrumentationConfig) {
String instrumentationName,
ExperimentalLanguageSpecificInstrumentationPropertyModel instrumentationConfig) {
ExperimentalLanguageSpecificInstrumentationModel javaConfig =
new ExperimentalLanguageSpecificInstrumentationModel();
javaConfig.setAdditionalProperty(instrumentationName, instrumentationConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
7 changes: 6 additions & 1 deletion sdk-extensions/incubator/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import de.undercouch.gradle.tasks.download.Download
import java.io.FileFilter

plugins {
id("otel.java-conventions")
Expand Down Expand Up @@ -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 commit
val configurationRepoZip = "https://github.com/open-telemetry/opentelemetry-configuration/archive/$configurationRef.zip"
val buildDirectory = layout.buildDirectory.asFile.get()

Expand Down Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ExperimentalComposableSamplerModel, ComposableSampler> {

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<String, ?> keyValue =
FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "composable sampler");
return context.loadComponent(ComposableSampler.class, keyValue.getKey(), keyValue.getValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ static <T> T requireNonNull(@Nullable T object, String description) {
return object;
}

static Map.Entry<String, Object> getSingletonMapEntry(
Map<String, Object> additionalProperties, String resourceName) {
static <T> Map.Entry<String, T> getSingletonMapEntry(
Map<String, T> additionalProperties, String resourceName) {
if (additionalProperties.isEmpty()) {
throw new DeclarativeConfigException(resourceName + " must be set");
}
Expand All @@ -48,4 +48,15 @@ static Map.Entry<String, Object> getSingletonMapEntry(
new IllegalStateException(
"Missing " + resourceName + ". This is a programming error."));
}

static void requireNullResource(
@Nullable Object resource, String resourceName, Map<String, ?> additionalProperties) {
if (resource != null) {
throw new DeclarativeConfigException(
"Invalid configuration - multiple "
+ resourceName
+ "s set: "
+ additionalProperties.keySet().stream().collect(joining(",", "[", "]")));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<LogRecordExporterModel, LogRecordExporter> {

private static final String RESOURCE_NAME = "log record exporter";

private static final LogRecordExporterFactory INSTANCE = new LogRecordExporterFactory();

private LogRecordExporterFactory() {}
Expand All @@ -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;
Comment thread
jack-berg marked this conversation as resolved.
Outdated
Object resource = null;

if (model.getOtlpHttp() != null) {
key = "otlp_http";
resource = model.getOtlpHttp();
}
if (model.getOtlpGrpc() != null) {
requireNullResource(resource, RESOURCE_NAME, model.getAdditionalProperties());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding strictness here to fail fast?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I understand the intent: if oitlp_http is present, make sure no other span exporters are set. But the implementation seems not quite right. requireNullResource produces an error message like Invalid configuration - multiple " + resourceName + "s set: " + additionalProperties.keySet().stream().collect(joining(",", "[", "]" based on additional properties, when its model.getOtlpHttp() which is causing the conflict.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old implementation works because I was sort of cheating and moving all the well known exporter model definitions to additionalProperties.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed bc11574 which sort of reverts this change but does it without polluting additionalProperties.

Thinking about this, I need to go apply this pattern to SamplerFactory, LgRecordProcessorFactory, SpanProcessorFactory, TextMapPropagatorFactory, AggregationFactory. In all these cases, exactly one key value pair is expected but the implementations tolerate multiple. Will do this in a followup PR.

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<String, ?> keyValue =
FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), RESOURCE_NAME);
key = keyValue.getKey();
resource = keyValue.getValue();
}

Map.Entry<String, Object> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -71,7 +72,7 @@ public LogRecordProcessor create(
return context.addCloseable(SimpleLogRecordProcessor.create(logRecordExporter));
}

Map.Entry<String, Object> keyValue =
Map.Entry<String, LogRecordProcessorPropertyModel> keyValue =
FileConfigUtil.getSingletonMapEntry(
model.getAdditionalProperties(), "log record processor");
LogRecordProcessor logRecordProcessor =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<PushMetricExporterModel, MetricExporter> {

private static final String RESOURCE_NAME = "metric exporter";

private static final MetricExporterFactory INSTANCE = new MetricExporterFactory();

private MetricExporterFactory() {}
Expand All @@ -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<String, Object> 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<String, ?> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<ExperimentalResourceDetectorModel, Resource> {
private static final String RESOURCE_NAME = "resource detector";

private static final ResourceDetectorFactory INSTANCE = new ResourceDetectorFactory();

Expand All @@ -23,8 +27,35 @@ static ResourceDetectorFactory getInstance() {
@Override
public Resource create(
ExperimentalResourceDetectorModel model, DeclarativeConfigContext context) {
Map.Entry<String, Object> 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<String, ExperimentalResourceDetectorPropertyModel> keyValue =
FileConfigUtil.getSingletonMapEntry(model.getAdditionalProperties(), "resource detector");
key = keyValue.getKey();
value = keyValue.getValue();
}

return context.loadComponent(Resource.class, key, value);
}
}
Loading
Loading