Skip to content

Commit

Permalink
Added MetricReader customizer for AutoConfiguredOpenTelemetrySdkBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
asafm committed Feb 15, 2024
1 parent 48d41d3 commit d6f16f7
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
Comparing source compatibility of against
No changes.
*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer addMetricReaderCustomizer(java.util.function.BiFunction<? super io.opentelemetry.sdk.metrics.export.MetricReader,io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties,? extends io.opentelemetry.sdk.metrics.export.MetricReader>)
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer addMetricReaderCustomizer(java.util.function.BiFunction<? super io.opentelemetry.sdk.metrics.export.MetricReader,io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties,? extends io.opentelemetry.sdk.metrics.export.MetricReader>)
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.SpanProcessor;
Expand Down Expand Up @@ -150,12 +151,25 @@ default AutoConfigurationCustomizer addMeterProviderCustomizer(
*
* <p>Multiple calls will execute the customizers in order.
*/
@SuppressWarnings("UnusedReturnValue")
default AutoConfigurationCustomizer addMetricExporterCustomizer(
BiFunction<? super MetricExporter, ConfigProperties, ? extends MetricExporter>
exporterCustomizer) {
return this;
}

/**
* Adds a {@link BiFunction} to invoke with the autoconfigured {@link MetricReader} to allow
* customization. The return value of the {@link BiFunction} will replace the passed-in argument.
*
* <p>Multiple calls will execute the customizers in order.
*/
@SuppressWarnings("UnusedReturnValue")
default AutoConfigurationCustomizer addMetricReaderCustomizer(
BiFunction<? super MetricReader, ConfigProperties, ? extends MetricReader> readerCustomizer) {
return this;
}

/**
* Adds a {@link BiFunction} to invoke the with the {@link SdkLoggerProviderBuilder} to allow
* customization. The return value of the {@link BiFunction} will replace the passed-in argument.
Expand Down
2 changes: 2 additions & 0 deletions sdk-extensions/autoconfigure/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ dependencies {

testImplementation("com.google.guava:guava")
testImplementation("edu.berkeley.cs.jqf:jqf-fuzz")
testImplementation("com.linecorp.armeria:armeria")
}

testing {
Expand Down Expand Up @@ -53,6 +54,7 @@ testing {
implementation(project(":exporters:logging-otlp"))
implementation(project(":exporters:otlp:all"))
implementation(project(":exporters:prometheus"))
implementation("io.prometheus:prometheus-metrics-exporter-httpserver")
implementation(project(":exporters:zipkin"))
implementation(project(":sdk:testing"))
implementation(project(":sdk:trace-shaded-deps"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.SdkMeterProviderBuilder;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
Expand Down Expand Up @@ -83,6 +84,8 @@ public final class AutoConfiguredOpenTelemetrySdkBuilder implements AutoConfigur
meterProviderCustomizer = (a, unused) -> a;
private BiFunction<? super MetricExporter, ConfigProperties, ? extends MetricExporter>
metricExporterCustomizer = (a, unused) -> a;
private BiFunction<? super MetricReader, ConfigProperties, ? extends MetricReader>
metricReaderCustomizer = (a, unused) -> a;

private BiFunction<SdkLoggerProviderBuilder, ConfigProperties, SdkLoggerProviderBuilder>
loggerProviderCustomizer = (a, unused) -> a;
Expand Down Expand Up @@ -283,6 +286,20 @@ public AutoConfiguredOpenTelemetrySdkBuilder addMetricExporterCustomizer(
return this;
}

/**
* Adds a {@link BiFunction} to invoke with the autoconfigured {@link MetricReader} to allow
* customization. The return value of the {@link BiFunction} will replace the passed-in argument.
*
* <p>Multiple calls will execute the customizers in order.
*/
@Override
public AutoConfigurationCustomizer addMetricReaderCustomizer(
BiFunction<? super MetricReader, ConfigProperties, ? extends MetricReader> readerCustomizer) {
requireNonNull(readerCustomizer, "readerCustomizer");
this.metricReaderCustomizer = mergeCustomizer(this.metricReaderCustomizer, readerCustomizer);
return this;
}

/**
* Adds a {@link BiFunction} to invoke the with the {@link SdkLoggerProviderBuilder} to allow
* customization. The return value of the {@link BiFunction} will replace the passed-in argument.
Expand Down Expand Up @@ -406,7 +423,12 @@ public AutoConfiguredOpenTelemetrySdk build() {
SdkMeterProviderBuilder meterProviderBuilder = SdkMeterProvider.builder();
meterProviderBuilder.setResource(resource);
MeterProviderConfiguration.configureMeterProvider(
meterProviderBuilder, config, spiHelper, metricExporterCustomizer, closeables);
meterProviderBuilder,
config,
spiHelper,
metricReaderCustomizer,
metricExporterCustomizer,
closeables);
meterProviderBuilder = meterProviderCustomizer.apply(meterProviderBuilder, config);
SdkMeterProvider meterProvider = meterProviderBuilder.build();
closeables.add(meterProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ static void configureMeterProvider(
SdkMeterProviderBuilder meterProviderBuilder,
ConfigProperties config,
SpiHelper spiHelper,
BiFunction<? super MetricReader, ConfigProperties, ? extends MetricReader>
metricReaderCustomizer,
BiFunction<? super MetricExporter, ConfigProperties, ? extends MetricExporter>
metricExporterCustomizer,
List<Closeable> closeables) {
Expand Down Expand Up @@ -56,7 +58,8 @@ static void configureMeterProvider(
throw new ConfigurationException("otel.experimental.metrics.cardinality.limit must be >= 1");
}

configureMetricReaders(config, spiHelper, metricExporterCustomizer, closeables)
configureMetricReaders(
config, spiHelper, metricReaderCustomizer, metricExporterCustomizer, closeables)
.forEach(
reader ->
SdkMeterProviderUtil.registerMetricReaderWithCardinalitySelector(
Expand All @@ -66,6 +69,8 @@ static void configureMeterProvider(
static List<MetricReader> configureMetricReaders(
ConfigProperties config,
SpiHelper spiHelper,
BiFunction<? super MetricReader, ConfigProperties, ? extends MetricReader>
metricReaderCustomizer,
BiFunction<? super MetricExporter, ConfigProperties, ? extends MetricExporter>
metricExporterCustomizer,
List<Closeable> closeables) {
Expand All @@ -85,7 +90,12 @@ static List<MetricReader> configureMetricReaders(
.map(
exporterName ->
MetricExporterConfiguration.configureReader(
exporterName, config, spiHelper, metricExporterCustomizer, closeables))
exporterName,
config,
spiHelper,
metricReaderCustomizer,
metricExporterCustomizer,
closeables))
.collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ static MetricReader configureReader(
String name,
ConfigProperties config,
SpiHelper spiHelper,
BiFunction<? super MetricReader, ConfigProperties, ? extends MetricReader>
metricReaderCustomizer,
BiFunction<? super MetricExporter, ConfigProperties, ? extends MetricExporter>
metricExporterCustomizer,
List<Closeable> closeables) {
Expand All @@ -56,7 +58,14 @@ static MetricReader configureReader(
MetricReader metricReader = configureMetricReader(name, spiMetricReadersManager);
if (metricReader != null) {
closeables.add(metricReader);
return metricReader;

// Customize metric reader
MetricReader customizedMetricReader = metricReaderCustomizer.apply(metricReader, config);
if (customizedMetricReader != metricReader) {
closeables.add(customizedMetricReader);
}

return customizedMetricReader;
}
// No exporter or reader with the name
throw new ConfigurationException("Unrecognized value for otel.metrics.exporter: " + name);
Expand All @@ -74,7 +83,11 @@ static MetricReader configureReader(
.setInterval(config.getDuration("otel.metric.export.interval", DEFAULT_EXPORT_INTERVAL))
.build();
closeables.add(reader);
return reader;
MetricReader customizedMetricReader = metricReaderCustomizer.apply(reader, config);
if (customizedMetricReader != reader) {
closeables.add(customizedMetricReader);
}
return customizedMetricReader;
}

// Visible for testing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ private static ObjectAssert<ExemplarFilter> assertExemplarFilter(Map<String, Str
DefaultConfigProperties.createFromMap(configWithDefault),
SpiHelper.create(MeterProviderConfigurationTest.class.getClassLoader()),
(a, b) -> a,
(a, b) -> a,
new ArrayList<>());
return assertThat(builder)
.extracting("exemplarFilter", as(InstanceOfAssertFactories.type(ExemplarFilter.class)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@

package io.opentelemetry.sdk.autoconfigure;

import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;

import com.linecorp.armeria.client.WebClient;
import io.github.netmikey.logunit.api.LogCapturer;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.events.GlobalEventEmitterProvider;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import java.lang.reflect.Field;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -31,6 +35,23 @@ void setUp() {
GlobalEventEmitterProvider.resetForTest();
}

@SuppressWarnings("ResultOfMethodCallIgnored")
@Test
void build_addMetricReaderCustomizerPrometheus() {
AutoConfiguredOpenTelemetrySdkBuilder builder = AutoConfiguredOpenTelemetrySdk.builder();

builder.addPropertiesSupplier(() -> singletonMap("otel.metrics.exporter", "prometheus"));
builder.addMetricReaderCustomizer(
(reader, config) -> {
assertThat(reader).isInstanceOf(PrometheusHttpServer.class);
return PrometheusHttpServer.builder().setPort(1234).build();
});
builder.build();

WebClient client = WebClient.builder("http://localhost:1234").build();
assertThatCode(() -> client.get("/metrics")).doesNotThrowAnyException();
}

@Test
void initializeAndGet() {
try (OpenTelemetrySdk sdk = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ void configureMetricReaders_multipleWithNone() {
assertThatThrownBy(
() ->
MeterProviderConfiguration.configureMetricReaders(
config, spiHelper, (a, unused) -> a, closeables))
config, spiHelper, (a, unused) -> a, (a, unused) -> a, closeables))
.isInstanceOf(ConfigurationException.class)
.hasMessageContaining("otel.metrics.exporter contains none along with other exporters");
cleanup.addCloseables(closeables);
Expand All @@ -102,7 +102,11 @@ void configureMetricReaders_defaultExporter() {

List<MetricReader> metricReaders =
MeterProviderConfiguration.configureMetricReaders(
config, spiHelper, (metricExporter, unused) -> metricExporter, closeables);
config,
spiHelper,
(a, unused) -> a,
(metricExporter, unused) -> metricExporter,
closeables);
cleanup.addCloseables(closeables);

assertThat(metricReaders)
Expand All @@ -125,7 +129,11 @@ void configureMetricReaders_multipleExporters() {

List<MetricReader> metricReaders =
MeterProviderConfiguration.configureMetricReaders(
config, spiHelper, (metricExporter, unused) -> metricExporter, closeables);
config,
spiHelper,
(a, unused) -> a,
(metricExporter, unused) -> metricExporter,
closeables);
cleanup.addCloseables(closeables);

assertThat(metricReaders).hasSize(2).hasOnlyElementsOfType(PeriodicMetricReader.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ void configureMeterProvider_InvalidCardinalityLimit() {
"0")),
spiHelper,
(a, b) -> a,
(a, b) -> a,
closeables);
})
.isInstanceOf(ConfigurationException.class)
Expand All @@ -69,6 +70,7 @@ void configureMeterProvider_ConfiguresCardinalityLimit() {
Collections.singletonMap("otel.metrics.exporter", "logging")),
spiHelper,
(a, b) -> a,
(a, b) -> a,
closeables);
cleanup.addCloseables(closeables);
assertCardinalityLimit(builder, 2000);
Expand All @@ -85,6 +87,7 @@ void configureMeterProvider_ConfiguresCardinalityLimit() {
"100")),
spiHelper,
(a, b) -> a,
(a, b) -> a,
closeables);
cleanup.addCloseables(closeables);
assertCardinalityLimit(builder, 100);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package io.opentelemetry.sdk.autoconfigure;

import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

Expand All @@ -21,11 +22,16 @@
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
import java.io.Closeable;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.Stream;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
Expand All @@ -49,13 +55,52 @@ void configureReader_PrometheusOnClasspath() {

MetricReader reader =
MetricExporterConfiguration.configureReader(
"prometheus", CONFIG_PROPERTIES, spiHelper, (a, b) -> a, closeables);
"prometheus", CONFIG_PROPERTIES, spiHelper, (a, b) -> a, (a, b) -> a, closeables);
cleanup.addCloseables(closeables);

assertThat(reader).isInstanceOf(PrometheusHttpServer.class);
assertThat(closeables).hasSize(1);
}

@Test
void configureReader_customizeReader() {
List<Closeable> closeables = new ArrayList<>();

BiFunction<MetricReader, ConfigProperties, MetricReader> readerCustomizer =
(existingReader, config) -> PrometheusHttpServer.builder().setPort(7137).build();
MetricReader reader =
MetricExporterConfiguration.configureReader(
"prometheus", CONFIG_PROPERTIES, spiHelper, readerCustomizer, (a, b) -> a, closeables);
cleanup.addCloseables(closeables);

assertThat(reader).isInstanceOf(PrometheusHttpServer.class);
assertThat(closeables).hasSize(2);
PrometheusHttpServer prometheusHttpServer = (PrometheusHttpServer) reader;
assertThat(prometheusHttpServer)
.extracting("httpServer", as(InstanceOfAssertFactories.type(HTTPServer.class)))
.satisfies(httpServer -> assertThat(httpServer.getPort()).isEqualTo(7137));

List<Closeable> closeablesPart2 = new ArrayList<>();

readerCustomizer =
(existingReader, config) ->
PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder().build())
.setInterval(Duration.ofSeconds(123))
.build();

reader =
MetricExporterConfiguration.configureReader(
"otlp", CONFIG_PROPERTIES, spiHelper, readerCustomizer, (a, b) -> a, closeablesPart2);
cleanup.addCloseables(closeablesPart2);

assertThat(reader).isInstanceOf(PeriodicMetricReader.class);
assertThat(closeablesPart2).hasSize(3);
PeriodicMetricReader periodicMetricReader = (PeriodicMetricReader) reader;
assertThat(periodicMetricReader)
.extracting("intervalNanos")
.isEqualTo(Duration.ofSeconds(123).toNanos());
}

@ParameterizedTest
@MethodSource("knownExporters")
void configureExporter_KnownSpiExportersOnClasspath(
Expand Down

0 comments on commit d6f16f7

Please sign in to comment.