Skip to content

Commit

Permalink
Meter provider configuration factory (#5773)
Browse files Browse the repository at this point in the history
  • Loading branch information
jack-berg committed Aug 28, 2023
1 parent 7229c45 commit 01503ef
Show file tree
Hide file tree
Showing 26 changed files with 1,552 additions and 93 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.logging.LoggingMetricExporter (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) java.lang.String toString()
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.logging.LoggingSpanExporter (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) java.lang.String toString()
*** MODIFIED CLASS: PUBLIC io.opentelemetry.exporter.logging.SystemOutLogRecordExporter (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) java.lang.String toString()
Original file line number Diff line number Diff line change
Expand Up @@ -103,4 +103,9 @@ public CompletableResultCode shutdown() {
}
return flush();
}

@Override
public String toString() {
return "LoggingMetricExporter{}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,9 @@ public CompletableResultCode shutdown() {
}
return flush();
}

@Override
public String toString() {
return "LoggingSpanExporter{}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,9 @@ public CompletableResultCode shutdown() {
}
return CompletableResultCode.ofSuccess();
}

@Override
public String toString() {
return "SystemOutLogRecordExporter{}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,9 @@ void shutdown() {
assertThat(exporter.shutdown().isSuccess()).isTrue();
logs.assertContains("Calling shutdown() multiple times.");
}

@Test
void stringRepresentation() {
assertThat(LoggingMetricExporter.create().toString()).isEqualTo("LoggingMetricExporter{}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,9 @@ void shutdown() {
assertThat(exporter.shutdown().isSuccess()).isTrue();
logs.assertContains("Calling shutdown() multiple times.");
}

@Test
void stringRepresentation() {
assertThat(LoggingSpanExporter.create().toString()).isEqualTo("LoggingSpanExporter{}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ void shutdown() {
assertThat(exporter.shutdown().isSuccess()).isTrue();
}

@Test
void stringRepresentation() {
assertThat(SystemOutLogRecordExporter.create().toString())
.isEqualTo("SystemOutLogRecordExporter{}");
}

private static LogRecordData sampleLog(long timestamp) {
return TestLogRecordData.builder()
.setResource(Resource.empty())
Expand Down
2 changes: 2 additions & 0 deletions sdk-extensions/incubator/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ dependencies {
testImplementation(project(":sdk:testing"))
testImplementation(project(":sdk-extensions:autoconfigure"))
testImplementation(project(":exporters:otlp:all"))
testImplementation(project(":exporters:prometheus"))
testImplementation(project(":exporters:logging"))
testImplementation(project(":sdk-extensions:jaeger-remote-sampler"))
testImplementation(project(":extensions:trace-propagators"))
// As a part of the tests we check that we can parse examples without error. The https://github.com/open-telemetry/opentelemetry-configuration/blob/main/examples/kitchen-sink.yam contains a reference to the xray propagator
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Aggregation;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Base2ExponentialBucketHistogram;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExplicitBucketHistogram;
import java.io.Closeable;
import java.util.List;
import javax.annotation.Nullable;

final class AggregationFactory
implements Factory<Aggregation, io.opentelemetry.sdk.metrics.Aggregation> {

private static final AggregationFactory INSTANCE = new AggregationFactory();

private AggregationFactory() {}

static AggregationFactory getInstance() {
return INSTANCE;
}

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

if (model.getDrop() != null) {
return io.opentelemetry.sdk.metrics.Aggregation.drop();
}
if (model.getSum() != null) {
return io.opentelemetry.sdk.metrics.Aggregation.sum();
}
if (model.getLastValue() != null) {
return io.opentelemetry.sdk.metrics.Aggregation.lastValue();
}
Base2ExponentialBucketHistogram exponentialBucketHistogram =
model.getBase2ExponentialBucketHistogram();
if (exponentialBucketHistogram != null) {
Integer maxScale = exponentialBucketHistogram.getMaxScale();
if (maxScale == null) {
maxScale = 20;
}
Integer maxSize = exponentialBucketHistogram.getMaxSize();
if (maxSize == null) {
maxSize = 160;
}
try {
return io.opentelemetry.sdk.metrics.Aggregation.base2ExponentialBucketHistogram(
maxSize, maxScale);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Invalid exponential bucket histogram", e);
}
}
ExplicitBucketHistogram explicitBucketHistogram = model.getExplicitBucketHistogram();
if (explicitBucketHistogram != null) {
List<Double> boundaries = explicitBucketHistogram.getBoundaries();
if (boundaries == null) {
return io.opentelemetry.sdk.metrics.Aggregation.explicitBucketHistogram();
}
try {
return io.opentelemetry.sdk.metrics.Aggregation.explicitBucketHistogram(boundaries);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Invalid explicit bucket histogram", e);
}
}

return io.opentelemetry.sdk.metrics.Aggregation.defaultAggregation();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* 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.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.Selector;
import io.opentelemetry.sdk.metrics.InstrumentSelector;
import io.opentelemetry.sdk.metrics.InstrumentSelectorBuilder;
import io.opentelemetry.sdk.metrics.InstrumentType;
import java.io.Closeable;
import java.util.List;
import javax.annotation.Nullable;

final class InstrumentSelectorFactory implements Factory<Selector, InstrumentSelector> {

private static final InstrumentSelectorFactory INSTANCE = new InstrumentSelectorFactory();

private InstrumentSelectorFactory() {}

static InstrumentSelectorFactory getInstance() {
return INSTANCE;
}

@Override
public InstrumentSelector create(
@Nullable Selector model, SpiHelper spiHelper, List<Closeable> closeables) {
if (model == null) {
throw new ConfigurationException("selector must not be null");
}

InstrumentSelectorBuilder builder = InstrumentSelector.builder();
if (model.getInstrumentName() != null) {
builder.setName(model.getInstrumentName());
}
if (model.getInstrumentType() != null) {
InstrumentType instrumentType;
try {
instrumentType = InstrumentType.valueOf(model.getInstrumentType().name());
} catch (IllegalArgumentException e) {
throw new ConfigurationException(
"Unrecognized instrument type: " + model.getInstrumentType(), e);
}
builder.setType(instrumentType);
}
if (model.getMeterName() != null) {
builder.setMeterName(model.getMeterName());
}
if (model.getMeterSchemaUrl() != null) {
builder.setMeterSchemaUrl(model.getMeterSchemaUrl());
}
if (model.getMeterVersion() != null) {
builder.setMeterVersion(model.getMeterVersion());
}

try {
return builder.build();
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Invalid selector", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,53 +45,9 @@ public LogRecordExporter create(
return LogRecordExporter.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.logs.protocol", otlp.getProtocol());
}
if (otlp.getEndpoint() != null) {
// 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(
"otel.exporter.otlp.logs.headers",
otlp.getHeaders().getAdditionalProperties().entrySet().stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(joining(",")));
}
if (otlp.getCompression() != null) {
properties.put("otel.exporter.otlp.logs.compression", otlp.getCompression());
}
if (otlp.getTimeout() != null) {
properties.put("otel.exporter.otlp.logs.timeout", Integer.toString(otlp.getTimeout()));
}
if (otlp.getCertificate() != null) {
properties.put("otel.exporter.otlp.logs.certificate", otlp.getCertificate());
}
if (otlp.getClientKey() != null) {
properties.put("otel.exporter.otlp.logs.client.key", otlp.getClientKey());
}
if (otlp.getClientCertificate() != null) {
properties.put("otel.exporter.otlp.logs.client.certificate", otlp.getClientCertificate());
}

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

return FileConfigUtil.addAndReturn(
closeables,
FileConfigUtil.assertNotNull(
logRecordExporterSpiManager(configProperties, spiHelper).getByName("otlp"),
"otlp exporter"));
Otlp otlpModel = model.getOtlp();
if (otlpModel != null) {
return FileConfigUtil.addAndReturn(closeables, createOtlpExporter(otlpModel, spiHelper));
}

// TODO(jack-berg): add support for generic SPI exporters
Expand All @@ -104,6 +60,51 @@ public LogRecordExporter create(
return LogRecordExporter.composite();
}

private static LogRecordExporter createOtlpExporter(Otlp otlp, SpiHelper spiHelper) {
// 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.logs.protocol", otlp.getProtocol());
}
if (otlp.getEndpoint() != null) {
// 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(
"otel.exporter.otlp.logs.headers",
otlp.getHeaders().getAdditionalProperties().entrySet().stream()
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(joining(",")));
}
if (otlp.getCompression() != null) {
properties.put("otel.exporter.otlp.logs.compression", otlp.getCompression());
}
if (otlp.getTimeout() != null) {
properties.put("otel.exporter.otlp.logs.timeout", Integer.toString(otlp.getTimeout()));
}
if (otlp.getCertificate() != null) {
properties.put("otel.exporter.otlp.logs.certificate", otlp.getCertificate());
}
if (otlp.getClientKey() != null) {
properties.put("otel.exporter.otlp.logs.client.key", otlp.getClientKey());
}
if (otlp.getClientCertificate() != null) {
properties.put("otel.exporter.otlp.logs.client.certificate", otlp.getClientCertificate());
}

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

return FileConfigUtil.assertNotNull(
logRecordExporterSpiManager(configProperties, spiHelper).getByName("otlp"),
"otlp exporter");
}

private static NamedSpiManager<LogRecordExporter> logRecordExporterSpiManager(
ConfigProperties config, SpiHelper spiHelper) {
return spiHelper.loadConfigurable(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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.MeterProvider;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReader;
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.View;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import java.io.Closeable;
import java.util.List;
import javax.annotation.Nullable;

final class MeterProviderFactory implements Factory<MeterProvider, SdkMeterProviderBuilder> {

private static final MeterProviderFactory INSTANCE = new MeterProviderFactory();

private MeterProviderFactory() {}

static MeterProviderFactory getInstance() {
return INSTANCE;
}

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

SdkMeterProviderBuilder builder = SdkMeterProvider.builder();

List<MetricReader> readerModels = model.getReaders();
if (readerModels != null) {
readerModels.forEach(
readerModel -> {
io.opentelemetry.sdk.metrics.export.MetricReader metricReader =
MetricReaderFactory.getInstance().create(readerModel, spiHelper, closeables);
if (metricReader != null) {
builder.registerMetricReader(metricReader);
}
});
}

List<View> viewModels = model.getViews();
if (viewModels != null) {
viewModels.forEach(
viewModel ->
builder.registerView(
InstrumentSelectorFactory.getInstance()
.create(viewModel.getSelector(), spiHelper, closeables),
ViewFactory.getInstance().create(viewModel.getStream(), spiHelper, closeables)));
}

return builder;
}
}

0 comments on commit 01503ef

Please sign in to comment.