Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SdkTracerProvider configuration factory #5751

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ public LogRecordExporter create(
properties.put("otel.exporter.otlp.logs.protocol", otlp.getProtocol());
}
if (otlp.getEndpoint() != null) {
properties.put("otel.exporter.otlp.logs.endpoint", otlp.getEndpoint());
// NOTE: Set general otel.exporter.otlp.endpoint instead of signal specific
// otel.exporter.otlp.logs.endpoint to allow signal path (i.e. /v1/logs) to be added if not
// present
properties.put("otel.exporter.otlp.endpoint", otlp.getEndpoint());
}
if (otlp.getHeaders() != null) {
properties.put(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,15 @@ public OpenTelemetrySdk create(
.build()));
}

// TODO(jack-berg): add support for tracer provider
if (model.getTracerProvider() != null) {
builder.setTracerProvider(
FileConfigUtil.addAndReturn(
closeables,
TracerProviderFactory.getInstance()
.create(model.getTracerProvider(), spiHelper, closeables)
.build()));
}

// TODO(jack-berg): add support for meter provider
// TODO(jack-berg): add support for propagators
// TODO(jack-berg): add support for resource
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.extension.incubator.fileconfig;

import static java.util.stream.Collectors.joining;

import io.opentelemetry.sdk.autoconfigure.internal.NamedSpiManager;
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Otlp;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import java.io.Closeable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;

final class SpanExporterFactory
implements Factory<
io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporter,
SpanExporter> {

private static final SpanExporterFactory INSTANCE = new SpanExporterFactory();

private SpanExporterFactory() {}

static SpanExporterFactory getInstance() {
return INSTANCE;
}

@Override
public SpanExporter create(
@Nullable
io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporter model,
SpiHelper spiHelper,
List<Closeable> closeables) {
if (model == null) {
return SpanExporter.composite();
}

if (model.getOtlp() != null) {
Otlp otlp = model.getOtlp();

// Translate from file configuration scheme to environment variable scheme. This is ultimately
// interpreted by Otlp*ExporterProviders, but we want to avoid the dependency on
// opentelemetry-exporter-otlp
Map<String, String> properties = new HashMap<>();
if (otlp.getProtocol() != null) {
properties.put("otel.exporter.otlp.traces.protocol", otlp.getProtocol());
}
if (otlp.getEndpoint() != null) {
// NOTE: Set general otel.exporter.otlp.endpoint instead of signal specific
// otel.exporter.otlp.traces.endpoint to allow signal path (i.e. /v1/traces) to be added if
// not present
properties.put("otel.exporter.otlp.endpoint", otlp.getEndpoint());
}
if (otlp.getHeaders() != null) {
properties.put(
"otel.exporter.otlp.traces.headers",
otlp.getHeaders().getAdditionalProperties().entrySet().stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(joining(",")));
}
if (otlp.getCompression() != null) {
properties.put("otel.exporter.otlp.traces.compression", otlp.getCompression());
}
if (otlp.getTimeout() != null) {
properties.put("otel.exporter.otlp.traces.timeout", Integer.toString(otlp.getTimeout()));
}
if (otlp.getCertificate() != null) {
properties.put("otel.exporter.otlp.traces.certificate", otlp.getCertificate());
}
if (otlp.getClientKey() != null) {
properties.put("otel.exporter.otlp.traces.client.key", otlp.getClientKey());
}
if (otlp.getClientCertificate() != null) {
properties.put("otel.exporter.otlp.traces.client.certificate", otlp.getClientCertificate());
}

// TODO(jack-berg): add method for creating from map
ConfigProperties configProperties = DefaultConfigProperties.createForTest(properties);

return FileConfigUtil.addAndReturn(
closeables,
FileConfigUtil.assertNotNull(
spanExporterSpiManager(configProperties, spiHelper).getByName("otlp"),
"otlp exporter"));
}

// TODO(jack-berg): add support for generic SPI exporters
if (!model.getAdditionalProperties().isEmpty()) {
throw new ConfigurationException(
"Unrecognized span exporter(s): "
+ model.getAdditionalProperties().keySet().stream().collect(joining(",", "[", "]")));
}

return SpanExporter.composite();
}

private static NamedSpiManager<SpanExporter> spanExporterSpiManager(
ConfigProperties config, SpiHelper spiHelper) {
return spiHelper.loadConfigurable(
ConfigurableSpanExporterProvider.class,
ConfigurableSpanExporterProvider::getName,
ConfigurableSpanExporterProvider::createExporter,
config);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.extension.incubator.fileconfig;

import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanLimits;
import io.opentelemetry.sdk.trace.SpanLimitsBuilder;
import java.io.Closeable;
import java.util.List;
import javax.annotation.Nullable;

final class SpanLimitsFactory
implements Factory<SpanLimits, io.opentelemetry.sdk.trace.SpanLimits> {

private static final SpanLimitsFactory INSTANCE = new SpanLimitsFactory();

private SpanLimitsFactory() {}

static SpanLimitsFactory getInstance() {
return INSTANCE;
}

@Override
public io.opentelemetry.sdk.trace.SpanLimits create(
@Nullable SpanLimits model, SpiHelper spiHelper, List<Closeable> closeables) {
if (model == null) {
return io.opentelemetry.sdk.trace.SpanLimits.getDefault();
}

SpanLimitsBuilder builder = io.opentelemetry.sdk.trace.SpanLimits.builder();
if (model.getAttributeCountLimit() != null) {
builder.setMaxNumberOfAttributes(model.getAttributeCountLimit());
}
if (model.getAttributeValueLengthLimit() != null) {
builder.setMaxAttributeValueLength(model.getAttributeValueLengthLimit());
}
if (model.getEventCountLimit() != null) {
builder.setMaxNumberOfEvents(model.getEventCountLimit());
}
if (model.getLinkCountLimit() != null) {
builder.setMaxNumberOfLinks(model.getLinkCountLimit());
}
if (model.getEventAttributeCountLimit() != null) {
builder.setMaxNumberOfAttributesPerEvent(model.getEventAttributeCountLimit());
}
if (model.getLinkAttributeCountLimit() != null) {
builder.setMaxNumberOfAttributesPerLink(model.getLinkAttributeCountLimit());
}

return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.extension.incubator.fileconfig;

import static java.util.stream.Collectors.joining;

import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanExporter;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import java.io.Closeable;
import java.time.Duration;
import java.util.List;
import javax.annotation.Nullable;

final class SpanProcessorFactory
implements Factory<
io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessor,
SpanProcessor> {

private static final SpanProcessorFactory INSTANCE = new SpanProcessorFactory();

private SpanProcessorFactory() {}

static SpanProcessorFactory getInstance() {
return INSTANCE;
}

@Override
public SpanProcessor create(
@Nullable
io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessor model,
SpiHelper spiHelper,
List<Closeable> closeables) {
if (model == null) {
return SpanProcessor.composite();
}

io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.BatchSpanProcessor
batchModel = model.getBatch();
if (batchModel != null) {
SpanExporter exporterModel = batchModel.getExporter();
if (exporterModel == null) {
return SpanProcessor.composite();
}

BatchSpanProcessorBuilder builder =
BatchSpanProcessor.builder(
SpanExporterFactory.getInstance().create(exporterModel, spiHelper, closeables));
if (batchModel.getExportTimeout() != null) {
builder.setExporterTimeout(Duration.ofMillis(batchModel.getExportTimeout()));
}
if (batchModel.getMaxExportBatchSize() != null) {
builder.setMaxExportBatchSize(batchModel.getMaxExportBatchSize());
}
if (batchModel.getMaxQueueSize() != null) {
builder.setMaxQueueSize(batchModel.getMaxQueueSize());
}
if (batchModel.getScheduleDelay() != null) {
builder.setScheduleDelay(Duration.ofMillis(batchModel.getScheduleDelay()));
}
return FileConfigUtil.addAndReturn(closeables, builder.build());
}

io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SimpleSpanProcessor
simpleModel = model.getSimple();
if (simpleModel != null) {
SpanExporter exporterModel = simpleModel.getExporter();
if (exporterModel == null) {
return SpanProcessor.composite();
}

return FileConfigUtil.addAndReturn(
closeables,
SimpleSpanProcessor.create(
SpanExporterFactory.getInstance().create(exporterModel, spiHelper, closeables)));
}

// TODO: add support for generic span processors
if (!model.getAdditionalProperties().isEmpty()) {
throw new ConfigurationException(
"Unrecognized span processor(s): "
+ model.getAdditionalProperties().keySet().stream().collect(joining(",", "[", "]")));
}

return SpanProcessor.composite();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.extension.incubator.fileconfig;

import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SpanProcessor;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.TracerProvider;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.SpanLimits;
import java.io.Closeable;
import java.util.List;
import javax.annotation.Nullable;

final class TracerProviderFactory implements Factory<TracerProvider, SdkTracerProviderBuilder> {

private static final TracerProviderFactory INSTANCE = new TracerProviderFactory();

private TracerProviderFactory() {}

static TracerProviderFactory getInstance() {
return INSTANCE;
}

@Override
public SdkTracerProviderBuilder create(
@Nullable TracerProvider model, SpiHelper spiHelper, List<Closeable> closeables) {
if (model == null) {
return SdkTracerProvider.builder();
}

SdkTracerProviderBuilder builder = SdkTracerProvider.builder();

SpanLimits spanLimits =
SpanLimitsFactory.getInstance().create(model.getLimits(), spiHelper, closeables);
builder.setSpanLimits(spanLimits);

List<SpanProcessor> processors = model.getProcessors();
if (processors != null) {
processors.forEach(
processor ->
builder.addSpanProcessor(
SpanProcessorFactory.getInstance().create(processor, spiHelper, closeables)));
}

return builder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void create_OtlpDefaults() {
eq(ConfigurableLogRecordExporterProvider.class), any(), any(), configCaptor.capture());
ConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("otel.exporter.otlp.logs.protocol")).isNull();
assertThat(configProperties.getString("otel.exporter.otlp.logs.endpoint")).isNull();
assertThat(configProperties.getString("otel.exporter.otlp.endpoint")).isNull();
assertThat(configProperties.getMap("otel.exporter.otlp.logs.headers")).isEmpty();
assertThat(configProperties.getString("otel.exporter.otlp.logs.compression")).isNull();
assertThat(configProperties.getDuration("otel.exporter.otlp.logs.timeout")).isNull();
Expand Down Expand Up @@ -124,7 +124,7 @@ void create_OtlpConfigured(@TempDir Path tempDir)
.withOtlp(
new Otlp()
.withProtocol("http/protobuf")
.withEndpoint("http://example:4318/v1/logs")
.withEndpoint("http://example:4318")
.withHeaders(
new Headers()
.withAdditionalProperty("key1", "value1")
Expand All @@ -148,8 +148,8 @@ void create_OtlpConfigured(@TempDir Path tempDir)
ConfigProperties configProperties = configCaptor.getValue();
assertThat(configProperties.getString("otel.exporter.otlp.logs.protocol"))
.isEqualTo("http/protobuf");
assertThat(configProperties.getString("otel.exporter.otlp.logs.endpoint"))
.isEqualTo("http://example:4318/v1/logs");
assertThat(configProperties.getString("otel.exporter.otlp.endpoint"))
.isEqualTo("http://example:4318");
assertThat(configProperties.getMap("otel.exporter.otlp.logs.headers"))
.isEqualTo(ImmutableMap.of("key1", "value1", "key2", "value2"));
assertThat(configProperties.getString("otel.exporter.otlp.logs.compression")).isEqualTo("gzip");
Expand Down
Loading