Skip to content
Open
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 @@ -80,6 +80,8 @@ final class Otel2PrometheusConverter {
private static final long NANOS_PER_MILLISECOND = TimeUnit.MILLISECONDS.toNanos(1);
static final int MAX_CACHE_SIZE = 10;

private final boolean otelScopeLabelsEnabled;
private final boolean otelTargetInfoMetricEnabled;
@Nullable private final Predicate<String> allowedResourceAttributesFilter;

/**
Expand All @@ -89,12 +91,20 @@ final class Otel2PrometheusConverter {
private final Map<Attributes, List<AttributeKey<?>>> resourceAttributesToAllowedKeysCache;

/**
* Constructor with feature flag parameter.
* Constructor with feature flag parameters.
*
* @param otelScopeLabelsEnabled whether to add OpenTelemetry scope labels to exported metrics
* @param otelTargetInfoMetricEnabled whether to export the target_info metric with resource
* attributes
* @param allowedResourceAttributesFilter if not {@code null}, resource attributes with keys
* matching this predicate will be added as labels on each exported metric
*/
Otel2PrometheusConverter(@Nullable Predicate<String> allowedResourceAttributesFilter) {
Otel2PrometheusConverter(
boolean otelScopeLabelsEnabled,
boolean otelTargetInfoMetricEnabled,
@Nullable Predicate<String> allowedResourceAttributesFilter) {
this.otelScopeLabelsEnabled = otelScopeLabelsEnabled;
this.otelTargetInfoMetricEnabled = otelTargetInfoMetricEnabled;
this.allowedResourceAttributesFilter = allowedResourceAttributesFilter;
this.resourceAttributesToAllowedKeysCache =
allowedResourceAttributesFilter != null
Expand All @@ -118,7 +128,7 @@ MetricSnapshots convert(@Nullable Collection<MetricData> metricDataCollection) {
resource = metricData.getResource();
}
}
if (resource != null) {
if (resource != null && otelTargetInfoMetricEnabled) {
putOrMerge(snapshotsByName, makeTargetInfo(resource));
}
return new MetricSnapshots(snapshotsByName.values());
Expand Down Expand Up @@ -457,7 +467,7 @@ private Labels convertAttributes(
requireNonNull(additionalAttributes[i]), additionalAttributes[i + 1]);
}

if (scope != null) {
if (scope != null && otelScopeLabelsEnabled) {
labelNameToValue.putIfAbsent(OTEL_SCOPE_NAME, scope.getName());
if (scope.getVersion() != null) {
labelNameToValue.putIfAbsent(OTEL_SCOPE_VERSION, scope.getVersion());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public final class PrometheusHttpServer implements MetricReader {

private final String host;
private final int port;
private final boolean otelScopeLabelsEnabled;
private final boolean otelTargetInfoMetricEnabled;
@Nullable private final Predicate<String> allowedResourceAttributesFilter;
private final MemoryMode memoryMode;
private final DefaultAggregationSelector defaultAggregationSelector;
Expand Down Expand Up @@ -71,18 +73,27 @@ public static PrometheusHttpServerBuilder builder() {
int port,
@Nullable ExecutorService executor,
PrometheusRegistry prometheusRegistry,
boolean otelScopeLabelsEnabled,
boolean otelTargetInfoMetricEnabled,
@Nullable Predicate<String> allowedResourceAttributesFilter,
MemoryMode memoryMode,
@Nullable HttpHandler defaultHandler,
DefaultAggregationSelector defaultAggregationSelector,
@Nullable Authenticator authenticator) {
this.host = host;
this.port = port;
this.otelScopeLabelsEnabled = otelScopeLabelsEnabled;
this.otelTargetInfoMetricEnabled = otelTargetInfoMetricEnabled;
this.allowedResourceAttributesFilter = allowedResourceAttributesFilter;
this.memoryMode = memoryMode;
this.defaultAggregationSelector = defaultAggregationSelector;
this.builder = builder;
this.prometheusMetricReader = new PrometheusMetricReader(allowedResourceAttributesFilter);
this.prometheusMetricReader =
PrometheusMetricReader.builder()
.setOtelScopeLabelsEnabled(otelScopeLabelsEnabled)
.setOtelTargetInfoMetricEnabled(otelTargetInfoMetricEnabled)
.setAllowedResourceAttributesFilter(allowedResourceAttributesFilter)
.build();
this.prometheusRegistry = prometheusRegistry;
prometheusRegistry.register(prometheusMetricReader);
// When memory mode is REUSABLE_DATA, concurrent reads lead to data corruption. To prevent this,
Expand Down Expand Up @@ -167,6 +178,8 @@ public String toString() {
StringJoiner joiner = new StringJoiner(",", "PrometheusHttpServer{", "}");
joiner.add("host=" + host);
joiner.add("port=" + port);
joiner.add("otelScopeLabelsEnabled=" + otelScopeLabelsEnabled);
joiner.add("otelTargetInfoMetricEnabled=" + otelTargetInfoMetricEnabled);
joiner.add("allowedResourceAttributesFilter=" + allowedResourceAttributesFilter);
joiner.add("memoryMode=" + memoryMode);
joiner.add(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public final class PrometheusHttpServerBuilder {
private String host = DEFAULT_HOST;
private int port = DEFAULT_PORT;
private PrometheusRegistry prometheusRegistry = new PrometheusRegistry();
private boolean otelScopeLabelsEnabled = true;
private boolean otelTargetInfoMetricEnabled = true;
@Nullable private Predicate<String> allowedResourceAttributesFilter;
@Nullable private ExecutorService executor;
private MemoryMode memoryMode = DEFAULT_MEMORY_MODE;
Expand All @@ -44,6 +46,8 @@ public final class PrometheusHttpServerBuilder {
this.host = builder.host;
this.port = builder.port;
this.prometheusRegistry = builder.prometheusRegistry;
this.otelScopeLabelsEnabled = builder.otelScopeLabelsEnabled;
this.otelTargetInfoMetricEnabled = builder.otelTargetInfoMetricEnabled;
this.allowedResourceAttributesFilter = builder.allowedResourceAttributesFilter;
this.executor = builder.executor;
this.memoryMode = builder.memoryMode;
Expand Down Expand Up @@ -81,14 +85,18 @@ public PrometheusHttpServerBuilder setPrometheusRegistry(PrometheusRegistry prom
return this;
}

/**
* Set if the {@code otel_scope_*} attributes are generated. Default is {@code true}.
*
* @deprecated {@code otel_scope_*} attributes are always generated.
*/
/** Set if the {@code otel_scope_*} attributes are generated. Default is {@code true}. */
@SuppressWarnings("UnusedReturnValue")
public PrometheusHttpServerBuilder setOtelScopeLabelsEnabled(boolean otelScopeLabelsEnabled) {
this.otelScopeLabelsEnabled = otelScopeLabelsEnabled;
return this;
}

/** Set if the {@code otel_target_info} metric is generated. Default is {@code true}. */
@SuppressWarnings("UnusedReturnValue")
@Deprecated
public PrometheusHttpServerBuilder setOtelScopeEnabled(boolean otelScopeEnabled) {
public PrometheusHttpServerBuilder setOtelTargetInfoMetricEnabled(
boolean otelTargetInfoMetricEnabled) {
this.otelTargetInfoMetricEnabled = otelTargetInfoMetricEnabled;
return this;
}

Expand Down Expand Up @@ -178,6 +186,8 @@ public PrometheusHttpServer build() {
port,
executor,
prometheusRegistry,
otelScopeLabelsEnabled,
otelTargetInfoMetricEnabled,
allowedResourceAttributesFilter,
memoryMode,
defaultHandler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,54 @@ public class PrometheusMetricReader implements MetricReader, MultiCollector {
private volatile CollectionRegistration collectionRegistration = CollectionRegistration.noop();
private final Otel2PrometheusConverter converter;

/** Returns a new {@link PrometheusMetricReader} with default configuration. */
public static PrometheusMetricReader create() {
return builder().build();
}

/** Returns a new {@link PrometheusMetricReaderBuilder}. */
public static PrometheusMetricReaderBuilder builder() {
return new PrometheusMetricReaderBuilder();
}

/**
* Deprecated. Use {@link #PrometheusMetricReader(Predicate)}.
* Deprecated. Use {@link #builder()}.
*
* @deprecated use {@link #PrometheusMetricReader(Predicate)}.
* @deprecated use {@link #builder()}.
*/
@Deprecated
@SuppressWarnings({"unused", "InconsistentOverloads"})
public PrometheusMetricReader(
boolean otelScopeEnabled, @Nullable Predicate<String> allowedResourceAttributesFilter) {
this.converter = new Otel2PrometheusConverter(allowedResourceAttributesFilter);
// otelScopeEnabled parameter was used to control the scope info metric, not scope labels.
this(
allowedResourceAttributesFilter,
/* otelScopeLabelsEnabled= */ true,
/* otelTargetInfoMetricEnabled= */ true);
}

// TODO: refactor to public static create or builder pattern to align with project style
/**
* Deprecated. Use {@link #builder()}.
*
* @deprecated use {@link #builder()}.
*/
@Deprecated
public PrometheusMetricReader(@Nullable Predicate<String> allowedResourceAttributesFilter) {
this.converter = new Otel2PrometheusConverter(allowedResourceAttributesFilter);
this(
allowedResourceAttributesFilter,
/* otelScopeLabelsEnabled= */ true,
/* otelTargetInfoMetricEnabled= */ true);
}

// Package-private constructor used by builder
@SuppressWarnings("InconsistentOverloads")
PrometheusMetricReader(
@Nullable Predicate<String> allowedResourceAttributesFilter,
boolean otelScopeLabelsEnabled,
boolean otelTargetInfoMetricEnabled) {
this.converter =
new Otel2PrometheusConverter(
otelScopeLabelsEnabled, otelTargetInfoMetricEnabled, allowedResourceAttributesFilter);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.exporter.prometheus;

import java.util.function.Predicate;
import javax.annotation.Nullable;

/** Builder for {@link PrometheusMetricReader}. */
public final class PrometheusMetricReaderBuilder {

private boolean otelScopeLabelsEnabled = true;
private boolean otelTargetInfoMetricEnabled = true;
@Nullable private Predicate<String> allowedResourceAttributesFilter;

PrometheusMetricReaderBuilder() {}

/**
* Sets whether to add OpenTelemetry scope labels (otel_scope_name, otel_scope_version, etc.) to
* exported metrics. Default is {@code true}.
*
* @param otelScopeLabelsEnabled whether to add scope labels
* @return this builder
*/
public PrometheusMetricReaderBuilder setOtelScopeLabelsEnabled(boolean otelScopeLabelsEnabled) {
this.otelScopeLabelsEnabled = otelScopeLabelsEnabled;
return this;
}

/**
* Sets whether to export the target_info metric with resource attributes. Default is {@code
* true}.
*
* @param otelTargetInfoMetricEnabled whether to export target_info metric
* @return this builder
*/
public PrometheusMetricReaderBuilder setOtelTargetInfoMetricEnabled(
boolean otelTargetInfoMetricEnabled) {
this.otelTargetInfoMetricEnabled = otelTargetInfoMetricEnabled;
return this;
}

/**
* Sets a filter to control which resource attributes are added as labels on each exported metric.
* If {@code null}, no resource attributes will be added as labels. Default is {@code null}.
*
* @param allowedResourceAttributesFilter predicate to filter resource attributes, or {@code null}
* @return this builder
*/
public PrometheusMetricReaderBuilder setAllowedResourceAttributesFilter(
@Nullable Predicate<String> allowedResourceAttributesFilter) {
this.allowedResourceAttributesFilter = allowedResourceAttributesFilter;
return this;
}

/** Builds a new {@link PrometheusMetricReader}. */
public PrometheusMetricReader build() {
return new PrometheusMetricReader(
allowedResourceAttributesFilter, otelScopeLabelsEnabled, otelTargetInfoMetricEnabled);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ public MetricReader create(DeclarativeConfigProperties config) {
prometheusBuilder.setHost(host);
}

Boolean withoutTargetInfo = config.getBoolean("without_target_info");
if (withoutTargetInfo != null) {
prometheusBuilder.setOtelTargetInfoMetricEnabled(!withoutTargetInfo);
}
Boolean withoutScopeInfo = config.getBoolean("without_scope_info");
if (withoutScopeInfo != null) {
prometheusBuilder.setOtelScopeLabelsEnabled(!withoutScopeInfo);
}

DeclarativeConfigProperties withResourceConstantLabels =
config.getStructured("with_resource_constant_labels");
if (withResourceConstantLabels != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ class Otel2PrometheusConverterTest {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

private final Otel2PrometheusConverter converter =
new Otel2PrometheusConverter(/* allowedResourceAttributesFilter= */ null);
new Otel2PrometheusConverter(
/* otelScopeLabelsEnabled= */ true,
/* otelTargetInfoMetricEnabled= */ true,
/* allowedResourceAttributesFilter= */ null);

@ParameterizedTest
@MethodSource("metricMetadataArgs")
Expand Down Expand Up @@ -201,7 +204,10 @@ void resourceAttributesAddition(
throws IOException {

Otel2PrometheusConverter converter =
new Otel2PrometheusConverter(allowedResourceAttributesFilter);
new Otel2PrometheusConverter(
/* otelScopeLabelsEnabled= */ true,
/* otelTargetInfoMetricEnabled= */ true,
allowedResourceAttributesFilter);

ByteArrayOutputStream out = new ByteArrayOutputStream();
MetricSnapshots snapshots = converter.convert(Collections.singletonList(metricData));
Expand Down Expand Up @@ -501,7 +507,10 @@ void validateCacheIsBounded() {
};

Otel2PrometheusConverter otel2PrometheusConverter =
new Otel2PrometheusConverter(/* allowedResourceAttributesFilter= */ countPredicate);
new Otel2PrometheusConverter(
/* otelScopeLabelsEnabled= */ true,
/* otelTargetInfoMetricEnabled= */ true,
/* allowedResourceAttributesFilter= */ countPredicate);

// Create 20 different metric data objects with 2 different resource attributes;
Resource resource1 = Resource.builder().put("cluster", "cluster1").build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ void stringRepresentation() {
"PrometheusHttpServer{"
+ "host=localhost,"
+ "port=0,"
+ "otelScopeLabelsEnabled=true,"
+ "otelTargetInfoMetricEnabled=true,"
+ "allowedResourceAttributesFilter=null,"
+ "memoryMode=REUSABLE_DATA,"
+ "defaultAggregationSelector=DefaultAggregationSelector{COUNTER=default, UP_DOWN_COUNTER=default, HISTOGRAM=default, OBSERVABLE_COUNTER=default, OBSERVABLE_UP_DOWN_COUNTER=default, OBSERVABLE_GAUGE=default, GAUGE=default}"
Expand Down
Loading
Loading