Metric exporter REUSABLE_DATA memory mode configuration options (#6304)

This commit is contained in:
jack-berg 2024-04-05 09:46:51 -05:00 committed by GitHub
parent ff0480c354
commit 4d8f4f3111
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 274 additions and 38 deletions

View File

@ -1,2 +1,7 @@
Comparing source compatibility of against
No changes.
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.export.MemoryMode getMemoryMode()
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter (not serializable)
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.export.MemoryMode getMemoryMode()

View File

@ -11,6 +11,7 @@ otelJava.moduleName.set("io.opentelemetry.exporter.internal")
val versions: Map<String, String> by project
dependencies {
api(project(":api:all"))
api(project(":sdk-extensions:autoconfigure-spi"))
compileOnly(project(":sdk:common"))

View File

@ -5,8 +5,13 @@
package io.opentelemetry.exporter.internal;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.common.export.MemoryMode;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;
import java.util.function.Consumer;
/**
* Utilities for exporter builders.
@ -33,5 +38,21 @@ public final class ExporterBuilderUtil {
return uri;
}
/** Invoke the {@code memoryModeConsumer} with the configured {@link MemoryMode}. */
public static void configureExporterMemoryMode(
ConfigProperties config, Consumer<MemoryMode> memoryModeConsumer) {
String memoryModeStr = config.getString("otel.java.experimental.exporter.memory_mode");
if (memoryModeStr == null) {
return;
}
MemoryMode memoryMode;
try {
memoryMode = MemoryMode.valueOf(memoryModeStr.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Unrecognized memory mode: " + memoryModeStr, e);
}
memoryModeConsumer.accept(memoryMode);
}
private ExporterBuilderUtil() {}
}

View File

@ -9,6 +9,7 @@ import io.opentelemetry.exporter.internal.http.HttpExporter;
import io.opentelemetry.exporter.internal.http.HttpExporterBuilder;
import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
@ -31,16 +32,19 @@ public final class OtlpHttpMetricExporter implements MetricExporter {
private final HttpExporter<MetricsRequestMarshaler> delegate;
private final AggregationTemporalitySelector aggregationTemporalitySelector;
private final DefaultAggregationSelector defaultAggregationSelector;
private final MemoryMode memoryMode;
OtlpHttpMetricExporter(
HttpExporterBuilder<MetricsRequestMarshaler> builder,
HttpExporter<MetricsRequestMarshaler> delegate,
AggregationTemporalitySelector aggregationTemporalitySelector,
DefaultAggregationSelector defaultAggregationSelector) {
DefaultAggregationSelector defaultAggregationSelector,
MemoryMode memoryMode) {
this.builder = builder;
this.delegate = delegate;
this.aggregationTemporalitySelector = aggregationTemporalitySelector;
this.defaultAggregationSelector = defaultAggregationSelector;
this.memoryMode = memoryMode;
}
/**
@ -72,7 +76,7 @@ public final class OtlpHttpMetricExporter implements MetricExporter {
* @since 1.29.0
*/
public OtlpHttpMetricExporterBuilder toBuilder() {
return new OtlpHttpMetricExporterBuilder(builder.copy());
return new OtlpHttpMetricExporterBuilder(builder.copy(), memoryMode);
}
@Override
@ -85,6 +89,11 @@ public final class OtlpHttpMetricExporter implements MetricExporter {
return defaultAggregationSelector.getDefaultAggregation(instrumentType);
}
@Override
public MemoryMode getMemoryMode() {
return memoryMode;
}
/**
* Submits all the given metrics in a single batch to the OpenTelemetry collector.
*

View File

@ -15,6 +15,7 @@ import io.opentelemetry.exporter.internal.compression.CompressorUtil;
import io.opentelemetry.exporter.internal.http.HttpExporterBuilder;
import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler;
import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.common.export.ProxyOptions;
import io.opentelemetry.sdk.common.export.RetryPolicy;
import io.opentelemetry.sdk.metrics.InstrumentType;
@ -39,6 +40,7 @@ public final class OtlpHttpMetricExporterBuilder {
private static final AggregationTemporalitySelector DEFAULT_AGGREGATION_TEMPORALITY_SELECTOR =
AggregationTemporalitySelector.alwaysCumulative();
private static final MemoryMode DEFAULT_MEMORY_MODE = MemoryMode.IMMUTABLE_DATA;
private final HttpExporterBuilder<MetricsRequestMarshaler> delegate;
private AggregationTemporalitySelector aggregationTemporalitySelector =
@ -46,15 +48,18 @@ public final class OtlpHttpMetricExporterBuilder {
private DefaultAggregationSelector defaultAggregationSelector =
DefaultAggregationSelector.getDefault();
private MemoryMode memoryMode;
OtlpHttpMetricExporterBuilder(HttpExporterBuilder<MetricsRequestMarshaler> delegate) {
OtlpHttpMetricExporterBuilder(
HttpExporterBuilder<MetricsRequestMarshaler> delegate, MemoryMode memoryMode) {
this.delegate = delegate;
this.memoryMode = memoryMode;
delegate.setMeterProvider(MeterProvider::noop);
OtlpUserAgent.addUserAgentHeader(delegate::addConstantHeaders);
}
OtlpHttpMetricExporterBuilder() {
this(new HttpExporterBuilder<>("otlp", "metric", DEFAULT_ENDPOINT));
this(new HttpExporterBuilder<>("otlp", "metric", DEFAULT_ENDPOINT), DEFAULT_MEMORY_MODE);
}
/**
@ -227,6 +232,13 @@ public final class OtlpHttpMetricExporterBuilder {
return this;
}
/** Set the {@link MemoryMode}. */
OtlpHttpMetricExporterBuilder setMemoryMode(MemoryMode memoryMode) {
requireNonNull(memoryMode, "memoryMode");
this.memoryMode = memoryMode;
return this;
}
OtlpHttpMetricExporterBuilder exportAsJson() {
delegate.exportAsJson();
return this;
@ -239,6 +251,10 @@ public final class OtlpHttpMetricExporterBuilder {
*/
public OtlpHttpMetricExporter build() {
return new OtlpHttpMetricExporter(
delegate, delegate.build(), aggregationTemporalitySelector, defaultAggregationSelector);
delegate,
delegate.build(),
aggregationTemporalitySelector,
defaultAggregationSelector,
memoryMode);
}
}

View File

@ -7,8 +7,11 @@ package io.opentelemetry.exporter.otlp.internal;
import static io.opentelemetry.sdk.metrics.Aggregation.explicitBucketHistogram;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.common.export.RetryPolicy;
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentType;
@ -19,6 +22,8 @@ import io.opentelemetry.sdk.metrics.internal.aggregator.AggregationUtil;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
@ -206,6 +211,44 @@ public final class OtlpConfigUtil {
}
}
/**
* Calls {@code #setMemoryMode} on the {@code Otlp{Protocol}MetricExporterBuilder} with the {@code
* memoryMode}.
*/
public static void setMemoryModeOnOtlpMetricExporterBuilder(
Object builder, MemoryMode memoryMode) {
try {
if (builder instanceof OtlpGrpcMetricExporterBuilder) {
// Calling getDeclaredMethod causes all private methods to be read, which causes a
// ClassNotFoundException when running with the OkHttHttpProvider as the private
// setManagedChanel(io.grpc.ManagedChannel) is reached and io.grpc.ManagedChannel is not on
// the classpath. io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricUtil provides a layer
// of indirection which avoids scanning the OtlpGrpcMetricExporterBuilder private methods.
Class<?> otlpGrpcMetricUtil =
Class.forName("io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricUtil");
Method method =
otlpGrpcMetricUtil.getDeclaredMethod(
"setMemoryMode", OtlpGrpcMetricExporterBuilder.class, MemoryMode.class);
method.setAccessible(true);
method.invoke(null, builder, memoryMode);
} else if (builder instanceof OtlpHttpMetricExporterBuilder) {
Method method =
OtlpHttpMetricExporterBuilder.class.getDeclaredMethod(
"setMemoryMode", MemoryMode.class);
method.setAccessible(true);
method.invoke(builder, memoryMode);
} else {
throw new IllegalArgumentException(
"Can only set memory mode on OtlpHttpMetricExporterBuilder and OtlpGrpcMetricExporterBuilder.");
}
} catch (NoSuchMethodException
| InvocationTargetException
| IllegalAccessException
| ClassNotFoundException e) {
throw new IllegalStateException("Error calling setMemoryMode.", e);
}
}
private static URL createUrl(URL context, String spec) {
try {
return new URL(context, spec);

View File

@ -9,6 +9,7 @@ import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.DATA_TYPE_M
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_GRPC;
import static io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
@ -48,6 +49,10 @@ public class OtlpMetricExporterProvider implements ConfigurableMetricExporterPro
config, builder::setAggregationTemporalitySelector);
OtlpConfigUtil.configureOtlpHistogramDefaultAggregation(
config, builder::setDefaultAggregationSelector);
ExporterBuilderUtil.configureExporterMemoryMode(
config,
memoryMode ->
OtlpConfigUtil.setMemoryModeOnOtlpMetricExporterBuilder(builder, memoryMode));
return builder.build();
} else if (protocol.equals(PROTOCOL_GRPC)) {
@ -67,6 +72,10 @@ public class OtlpMetricExporterProvider implements ConfigurableMetricExporterPro
config, builder::setAggregationTemporalitySelector);
OtlpConfigUtil.configureOtlpHistogramDefaultAggregation(
config, builder::setDefaultAggregationSelector);
ExporterBuilderUtil.configureExporterMemoryMode(
config,
memoryMode ->
OtlpConfigUtil.setMemoryModeOnOtlpMetricExporterBuilder(builder, memoryMode));
return builder.build();
}

View File

@ -9,6 +9,7 @@ import io.opentelemetry.exporter.internal.grpc.GrpcExporter;
import io.opentelemetry.exporter.internal.grpc.GrpcExporterBuilder;
import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.Aggregation;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
@ -31,6 +32,7 @@ public final class OtlpGrpcMetricExporter implements MetricExporter {
private final GrpcExporter<MetricsRequestMarshaler> delegate;
private final AggregationTemporalitySelector aggregationTemporalitySelector;
private final DefaultAggregationSelector defaultAggregationSelector;
private final MemoryMode memoryMode;
/**
* Returns a new {@link OtlpGrpcMetricExporter} using the default values.
@ -57,11 +59,13 @@ public final class OtlpGrpcMetricExporter implements MetricExporter {
GrpcExporterBuilder<MetricsRequestMarshaler> builder,
GrpcExporter<MetricsRequestMarshaler> delegate,
AggregationTemporalitySelector aggregationTemporalitySelector,
DefaultAggregationSelector defaultAggregationSelector) {
DefaultAggregationSelector defaultAggregationSelector,
MemoryMode memoryMode) {
this.builder = builder;
this.delegate = delegate;
this.aggregationTemporalitySelector = aggregationTemporalitySelector;
this.defaultAggregationSelector = defaultAggregationSelector;
this.memoryMode = memoryMode;
}
/**
@ -72,7 +76,7 @@ public final class OtlpGrpcMetricExporter implements MetricExporter {
* @since 1.29.0
*/
public OtlpGrpcMetricExporterBuilder toBuilder() {
return new OtlpGrpcMetricExporterBuilder(builder.copy());
return new OtlpGrpcMetricExporterBuilder(builder.copy(), memoryMode);
}
@Override
@ -85,6 +89,11 @@ public final class OtlpGrpcMetricExporter implements MetricExporter {
return defaultAggregationSelector.getDefaultAggregation(instrumentType);
}
@Override
public MemoryMode getMemoryMode() {
return memoryMode;
}
/**
* Submits all the given metrics in a single batch to the OpenTelemetry collector.
*

View File

@ -16,6 +16,7 @@ import io.opentelemetry.exporter.internal.compression.CompressorUtil;
import io.opentelemetry.exporter.internal.grpc.GrpcExporterBuilder;
import io.opentelemetry.exporter.internal.otlp.metrics.MetricsRequestMarshaler;
import io.opentelemetry.exporter.otlp.internal.OtlpUserAgent;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.common.export.RetryPolicy;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.export.AggregationTemporalitySelector;
@ -46,6 +47,7 @@ public final class OtlpGrpcMetricExporterBuilder {
private static final long DEFAULT_TIMEOUT_SECS = 10;
private static final AggregationTemporalitySelector DEFAULT_AGGREGATION_TEMPORALITY_SELECTOR =
AggregationTemporalitySelector.alwaysCumulative();
private static final MemoryMode DEFAULT_MEMORY_MODE = MemoryMode.IMMUTABLE_DATA;
// Visible for testing
final GrpcExporterBuilder<MetricsRequestMarshaler> delegate;
@ -55,9 +57,12 @@ public final class OtlpGrpcMetricExporterBuilder {
private DefaultAggregationSelector defaultAggregationSelector =
DefaultAggregationSelector.getDefault();
private MemoryMode memoryMode;
OtlpGrpcMetricExporterBuilder(GrpcExporterBuilder<MetricsRequestMarshaler> delegate) {
OtlpGrpcMetricExporterBuilder(
GrpcExporterBuilder<MetricsRequestMarshaler> delegate, MemoryMode memoryMode) {
this.delegate = delegate;
this.memoryMode = memoryMode;
delegate.setMeterProvider(MeterProvider::noop);
OtlpUserAgent.addUserAgentHeader(delegate::addConstantHeader);
}
@ -70,7 +75,8 @@ public final class OtlpGrpcMetricExporterBuilder {
DEFAULT_TIMEOUT_SECS,
DEFAULT_ENDPOINT,
() -> MarshalerMetricsServiceGrpc::newFutureStub,
GRPC_ENDPOINT_PATH));
GRPC_ENDPOINT_PATH),
DEFAULT_MEMORY_MODE);
}
/**
@ -259,6 +265,13 @@ public final class OtlpGrpcMetricExporterBuilder {
return this;
}
/** Set the {@link MemoryMode}. */
OtlpGrpcMetricExporterBuilder setMemoryMode(MemoryMode memoryMode) {
requireNonNull(memoryMode, "memoryMode");
this.memoryMode = memoryMode;
return this;
}
/**
* Constructs a new instance of the exporter based on the builder's values.
*
@ -266,6 +279,10 @@ public final class OtlpGrpcMetricExporterBuilder {
*/
public OtlpGrpcMetricExporter build() {
return new OtlpGrpcMetricExporter(
delegate, delegate.build(), aggregationTemporalitySelector, defaultAggregationSelector);
delegate,
delegate.build(),
aggregationTemporalitySelector,
defaultAggregationSelector,
memoryMode);
}
}

View File

@ -0,0 +1,19 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.exporter.otlp.metrics;
import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil;
import io.opentelemetry.sdk.common.export.MemoryMode;
final class OtlpGrpcMetricUtil {
private OtlpGrpcMetricUtil() {}
/** See {@link OtlpConfigUtil#setMemoryModeOnOtlpMetricExporterBuilder(Object, MemoryMode)}. */
static void setMemoryMode(OtlpGrpcMetricExporterBuilder builder, MemoryMode memoryMode) {
builder.setMemoryMode(memoryMode);
}
}

View File

@ -20,6 +20,7 @@ import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigurationException;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.export.MetricExporter;
import java.io.IOException;
import java.nio.file.Files;
@ -127,6 +128,7 @@ class OtlpMetricExporterProviderTest {
verify(grpcBuilder, never()).setTrustedCertificates(any());
verify(grpcBuilder, never()).setClientTls(any(), any());
assertThat(grpcBuilder).extracting("delegate").extracting("retryPolicy").isNull();
assertThat(exporter.getMemoryMode()).isEqualTo(MemoryMode.IMMUTABLE_DATA);
}
Mockito.verifyNoInteractions(httpBuilder);
}
@ -176,6 +178,7 @@ class OtlpMetricExporterProviderTest {
config.put("otel.exporter.otlp.metrics.compression", "gzip");
config.put("otel.exporter.otlp.timeout", "1s");
config.put("otel.exporter.otlp.metrics.timeout", "15s");
config.put("otel.java.experimental.exporter.memory_mode", "reusable_data");
try (MetricExporter exporter =
provider.createExporter(DefaultConfigProperties.createFromMap(config))) {
@ -188,6 +191,7 @@ class OtlpMetricExporterProviderTest {
verify(grpcBuilder).setTrustedCertificates(serverTls.certificate().getEncoded());
verify(grpcBuilder)
.setClientTls(clientTls.privateKey().getEncoded(), clientTls.certificate().getEncoded());
assertThat(exporter.getMemoryMode()).isEqualTo(MemoryMode.REUSABLE_DATA);
}
Mockito.verifyNoInteractions(httpBuilder);
}
@ -208,6 +212,7 @@ class OtlpMetricExporterProviderTest {
verify(httpBuilder, never()).setTrustedCertificates(any());
verify(httpBuilder, never()).setClientTls(any(), any());
assertThat(httpBuilder).extracting("delegate").extracting("retryPolicy").isNull();
assertThat(exporter.getMemoryMode()).isEqualTo(MemoryMode.IMMUTABLE_DATA);
}
Mockito.verifyNoInteractions(grpcBuilder);
}
@ -260,6 +265,7 @@ class OtlpMetricExporterProviderTest {
config.put("otel.exporter.otlp.metrics.compression", "gzip");
config.put("otel.exporter.otlp.timeout", "1s");
config.put("otel.exporter.otlp.metrics.timeout", "15s");
config.put("otel.java.experimental.exporter.memory_mode", "reusable_data");
try (MetricExporter exporter =
provider.createExporter(DefaultConfigProperties.createFromMap(config))) {
@ -272,6 +278,7 @@ class OtlpMetricExporterProviderTest {
verify(httpBuilder).setTrustedCertificates(serverTls.certificate().getEncoded());
verify(httpBuilder)
.setClientTls(clientTls.privateKey().getEncoded(), clientTls.certificate().getEncoded());
assertThat(exporter.getMemoryMode()).isEqualTo(MemoryMode.REUSABLE_DATA);
}
Mockito.verifyNoInteractions(grpcBuilder);
}

View File

@ -11,6 +11,7 @@ otelJava.moduleName.set("io.opentelemetry.exporter.prometheus")
dependencies {
api(project(":sdk:metrics"))
implementation(project(":exporters:common"))
implementation(project(":sdk-extensions:autoconfigure-spi"))
implementation("io.prometheus:prometheus-metrics-exporter-httpserver")

View File

@ -11,6 +11,7 @@
package io.opentelemetry.exporter.prometheus;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.InstrumentType;
import io.opentelemetry.sdk.metrics.data.AggregationTemporality;
import io.opentelemetry.sdk.metrics.export.CollectionRegistration;
@ -32,11 +33,12 @@ import javax.annotation.Nullable;
*/
public final class PrometheusHttpServer implements MetricReader {
private final PrometheusHttpServerBuilder builder;
private final HTTPServer httpServer;
private final PrometheusMetricReader prometheusMetricReader;
private final PrometheusRegistry prometheusRegistry;
private final String host;
private final PrometheusHttpServerBuilder builder;
private final MemoryMode memoryMode;
/**
* Returns a new {@link PrometheusHttpServer} which can be registered to an {@link
@ -59,11 +61,13 @@ public final class PrometheusHttpServer implements MetricReader {
@Nullable ExecutorService executor,
PrometheusRegistry prometheusRegistry,
boolean otelScopeEnabled,
@Nullable Predicate<String> allowedResourceAttributesFilter) {
@Nullable Predicate<String> allowedResourceAttributesFilter,
MemoryMode memoryMode) {
this.builder = builder;
this.prometheusMetricReader =
new PrometheusMetricReader(otelScopeEnabled, allowedResourceAttributesFilter);
this.host = host;
this.memoryMode = memoryMode;
this.prometheusRegistry = prometheusRegistry;
prometheusRegistry.register(prometheusMetricReader);
try {
@ -85,6 +89,11 @@ public final class PrometheusHttpServer implements MetricReader {
return prometheusMetricReader.getAggregationTemporality(instrumentType);
}
@Override
public MemoryMode getMemoryMode() {
return memoryMode;
}
@Override
public void register(CollectionRegistration registration) {
prometheusMetricReader.register(registration);

View File

@ -8,6 +8,7 @@ package io.opentelemetry.exporter.prometheus;
import static io.opentelemetry.api.internal.Utils.checkArgument;
import static java.util.Objects.requireNonNull;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.prometheus.metrics.model.registry.PrometheusRegistry;
import java.util.concurrent.ExecutorService;
import java.util.function.Predicate;
@ -18,6 +19,7 @@ public final class PrometheusHttpServerBuilder {
static final int DEFAULT_PORT = 9464;
private static final String DEFAULT_HOST = "0.0.0.0";
private static final MemoryMode DEFAULT_MEMORY_MODE = MemoryMode.IMMUTABLE_DATA;
private String host = DEFAULT_HOST;
private int port = DEFAULT_PORT;
@ -25,6 +27,18 @@ public final class PrometheusHttpServerBuilder {
private boolean otelScopeEnabled = true;
@Nullable private Predicate<String> allowedResourceAttributesFilter;
@Nullable private ExecutorService executor;
private MemoryMode memoryMode = DEFAULT_MEMORY_MODE;
PrometheusHttpServerBuilder() {}
PrometheusHttpServerBuilder(PrometheusHttpServerBuilder builder) {
this.host = builder.host;
this.port = builder.port;
this.prometheusRegistry = builder.prometheusRegistry;
this.otelScopeEnabled = builder.otelScopeEnabled;
this.allowedResourceAttributesFilter = builder.allowedResourceAttributesFilter;
this.executor = builder.executor;
}
/** Sets the host to bind to. If unset, defaults to {@value #DEFAULT_HOST}. */
public PrometheusHttpServerBuilder setHost(String host) {
@ -79,6 +93,13 @@ public final class PrometheusHttpServerBuilder {
return this;
}
/** Set the {@link MemoryMode}. */
public PrometheusHttpServerBuilder setMemoryMode(MemoryMode memoryMode) {
requireNonNull(memoryMode, "memoryMode");
this.memoryMode = memoryMode;
return this;
}
/**
* Returns a new {@link PrometheusHttpServer} with the configuration of this builder which can be
* registered with a {@link io.opentelemetry.sdk.metrics.SdkMeterProvider}.
@ -91,17 +112,7 @@ public final class PrometheusHttpServerBuilder {
executor,
prometheusRegistry,
otelScopeEnabled,
allowedResourceAttributesFilter);
}
PrometheusHttpServerBuilder() {}
PrometheusHttpServerBuilder(PrometheusHttpServerBuilder builder) {
this.host = builder.host;
this.port = builder.port;
this.prometheusRegistry = builder.prometheusRegistry;
this.otelScopeEnabled = builder.otelScopeEnabled;
this.allowedResourceAttributesFilter = builder.allowedResourceAttributesFilter;
this.executor = builder.executor;
allowedResourceAttributesFilter,
memoryMode);
}
}

View File

@ -5,6 +5,7 @@
package io.opentelemetry.exporter.prometheus.internal;
import io.opentelemetry.exporter.internal.ExporterBuilderUtil;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServerBuilder;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
@ -32,6 +33,8 @@ public class PrometheusMetricReaderProvider implements ConfigurableMetricReaderP
prometheusBuilder.setHost(host);
}
ExporterBuilderUtil.configureExporterMemoryMode(config, prometheusBuilder::setMemoryMode);
return prometheusBuilder.build();
}

View File

@ -14,6 +14,7 @@ import com.sun.net.httpserver.HttpServer;
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.metrics.export.MetricReader;
import io.prometheus.metrics.exporter.httpserver.HTTPServer;
import java.io.IOException;
@ -57,6 +58,7 @@ class PrometheusMetricReaderProviderTest {
assertThat(server.getAddress().getHostName()).isEqualTo("0:0:0:0:0:0:0:0");
assertThat(server.getAddress().getPort()).isEqualTo(9464);
});
assertThat(metricReader.getMemoryMode()).isEqualTo(MemoryMode.IMMUTABLE_DATA);
}
}
@ -73,6 +75,7 @@ class PrometheusMetricReaderProviderTest {
Map<String, String> config = new HashMap<>();
config.put("otel.exporter.prometheus.host", "localhost");
config.put("otel.exporter.prometheus.port", String.valueOf(port));
config.put("otel.java.experimental.exporter.memory_mode", "reusable_data");
when(configProperties.getInt(any())).thenReturn(null);
when(configProperties.getString(any())).thenReturn(null);
@ -87,6 +90,7 @@ class PrometheusMetricReaderProviderTest {
assertThat(server.getAddress().getHostName()).isEqualTo("localhost");
assertThat(server.getAddress().getPort()).isEqualTo(port);
});
assertThat(metricReader.getMemoryMode()).isEqualTo(MemoryMode.REUSABLE_DATA);
}
}
}

View File

@ -38,9 +38,12 @@ import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.exporter.otlp.http.logs.OtlpHttpLogRecordExporter;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporterBuilder;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporterBuilder;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest;
import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceResponse;
@ -63,6 +66,7 @@ import io.opentelemetry.proto.metrics.v1.Sum;
import io.opentelemetry.proto.trace.v1.ResourceSpans;
import io.opentelemetry.proto.trace.v1.ScopeSpans;
import io.opentelemetry.proto.trace.v1.Span.Link;
import io.opentelemetry.sdk.common.export.MemoryMode;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
@ -93,6 +97,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.BindMode;
@ -195,7 +200,7 @@ abstract class OtlpExporterIntegrationTest {
@ParameterizedTest
@ValueSource(strings = {"gzip", "none"})
void testOtlpGrpcTraceExport(String compression) {
SpanExporter otlpGrpcTraceExporter =
SpanExporter exporter =
OtlpGrpcSpanExporter.builder()
.setEndpoint(
"http://"
@ -205,7 +210,7 @@ abstract class OtlpExporterIntegrationTest {
.setCompression(compression)
.build();
testTraceExport(otlpGrpcTraceExporter);
testTraceExport(exporter);
}
@Test
@ -227,7 +232,7 @@ abstract class OtlpExporterIntegrationTest {
@ParameterizedTest
@ValueSource(strings = {"gzip", "none"})
void testOtlpHttpTraceExport(String compression) {
SpanExporter otlpGrpcTraceExporter =
SpanExporter exporter =
OtlpHttpSpanExporter.builder()
.setEndpoint(
"http://"
@ -238,7 +243,7 @@ abstract class OtlpExporterIntegrationTest {
.setCompression(compression)
.build();
testTraceExport(otlpGrpcTraceExporter);
testTraceExport(exporter);
}
@Test
@ -328,7 +333,7 @@ abstract class OtlpExporterIntegrationTest {
@ParameterizedTest
@ValueSource(strings = {"gzip", "none"})
void testOtlpGrpcMetricExport(String compression) {
MetricExporter otlpGrpcMetricExporter =
MetricExporter exporter =
OtlpGrpcMetricExporter.builder()
.setEndpoint(
"http://"
@ -338,7 +343,26 @@ abstract class OtlpExporterIntegrationTest {
.setCompression(compression)
.build();
testMetricExport(otlpGrpcMetricExporter);
testMetricExport(exporter);
}
@ParameterizedTest
@EnumSource(MemoryMode.class)
void testOtlpGrpcMetricExport_memoryMode(MemoryMode memoryMode) {
OtlpGrpcMetricExporterBuilder builder = OtlpGrpcMetricExporter.builder();
OtlpConfigUtil.setMemoryModeOnOtlpMetricExporterBuilder(builder, memoryMode);
MetricExporter exporter =
builder
.setEndpoint(
"http://"
+ collector.getHost()
+ ":"
+ collector.getMappedPort(COLLECTOR_OTLP_GRPC_PORT))
.build();
assertThat(exporter.getMemoryMode()).isEqualTo(memoryMode);
testMetricExport(exporter);
}
@Test
@ -360,7 +384,8 @@ abstract class OtlpExporterIntegrationTest {
@ParameterizedTest
@ValueSource(strings = {"gzip", "none"})
void testOtlpHttpMetricExport(String compression) {
MetricExporter otlpGrpcMetricExporter =
MetricExporter exporter =
OtlpHttpMetricExporter.builder()
.setEndpoint(
"http://"
@ -371,7 +396,27 @@ abstract class OtlpExporterIntegrationTest {
.setCompression(compression)
.build();
testMetricExport(otlpGrpcMetricExporter);
testMetricExport(exporter);
}
@ParameterizedTest
@EnumSource(MemoryMode.class)
void testOtlpHttpMetricExport_memoryMode(MemoryMode memoryMode) {
OtlpHttpMetricExporterBuilder builder = OtlpHttpMetricExporter.builder();
OtlpConfigUtil.setMemoryModeOnOtlpMetricExporterBuilder(builder, memoryMode);
MetricExporter exporter =
builder
.setEndpoint(
"http://"
+ collector.getHost()
+ ":"
+ collector.getMappedPort(COLLECTOR_OTLP_HTTP_PORT)
+ "/v1/metrics")
.build();
assertThat(exporter.getMemoryMode()).isEqualTo(memoryMode);
testMetricExport(exporter);
}
@Test

View File

@ -72,11 +72,18 @@ The OpenTelemetry SDK can be disabled entirely. If disabled, `AutoConfiguredOpen
The following configuration properties are common to all exporters:
| System property | Environment variable | Purpose |
|-----------------------|-----------------------|----------------------------------------------------------------------------------------------------------------------------|
| otel.traces.exporter | OTEL_TRACES_EXPORTER | List of exporters to be used for tracing, separated by commas. Default is `otlp`. `none` means no autoconfigured exporter. |
| otel.metrics.exporter | OTEL_METRICS_EXPORTER | List of exporters to be used for metrics, separated by commas. Default is `otlp`. `none` means no autoconfigured exporter. |
| otel.logs.exporter | OTEL_LOGS_EXPORTER | List of exporters to be used for logging, separated by commas. Default is `otlp`. `none` means no autoconfigured exporter. |
| System property | Environment variable | Purpose |
|---------------------------------------------|---------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| otel.traces.exporter | OTEL_TRACES_EXPORTER | List of exporters to be used for tracing, separated by commas. Default is `otlp`. `none` means no autoconfigured exporter. |
| otel.metrics.exporter | OTEL_METRICS_EXPORTER | List of exporters to be used for metrics, separated by commas. Default is `otlp`. `none` means no autoconfigured exporter. |
| otel.logs.exporter | OTEL_LOGS_EXPORTER | List of exporters to be used for logging, separated by commas. Default is `otlp`. `none` means no autoconfigured exporter. |
| otel.java.experimental.exporter.memory_mode | OTEL_JAVA_EXPERIMENTAL_EXPORTER_MEMORY_MODE | If `reusable_data`, enable reusable memory mode (on exporters which support it) to reduce allocations. Default is `immutable_data`. This option is experimental and subject to change or removal.**[1]** |
**[1]**: NOTE: The exporters which adhere
to `otel.java.experimental.exporter.memory_mode=reusable_data`
are `OtlpGrpcMetricExporter`, `OtlpHttpMetricExporter`, and `PrometheusHttpServer`. Support for
additional exporters may be added in the future.
#### OTLP exporter (span, metric, and log exporters)