Skip to content

Commit cecfb83

Browse files
authored
Extend prometheus declarative config support to include without_scope_info, with_resource_constant_labels (#6840)
1 parent 915c64a commit cecfb83

File tree

13 files changed

+343
-126
lines changed

13 files changed

+343
-126
lines changed

exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServer.java

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.io.IOException;
2727
import java.io.UncheckedIOException;
2828
import java.net.InetSocketAddress;
29+
import java.util.StringJoiner;
2930
import java.util.concurrent.ExecutorService;
3031
import java.util.concurrent.LinkedBlockingQueue;
3132
import java.util.concurrent.ThreadPoolExecutor;
@@ -39,13 +40,17 @@
3940
*/
4041
public final class PrometheusHttpServer implements MetricReader {
4142

43+
private final String host;
44+
private final int port;
45+
private final boolean otelScopeEnabled;
46+
@Nullable private final Predicate<String> allowedResourceAttributesFilter;
47+
private final MemoryMode memoryMode;
48+
private final DefaultAggregationSelector defaultAggregationSelector;
49+
4250
private final PrometheusHttpServerBuilder builder;
4351
private final HTTPServer httpServer;
4452
private final PrometheusMetricReader prometheusMetricReader;
4553
private final PrometheusRegistry prometheusRegistry;
46-
private final String host;
47-
private final MemoryMode memoryMode;
48-
private final DefaultAggregationSelector defaultAggregationSelector;
4954

5055
/**
5156
* Returns a new {@link PrometheusHttpServer} which can be registered to an {@link
@@ -73,11 +78,15 @@ public static PrometheusHttpServerBuilder builder() {
7378
@Nullable HttpHandler defaultHandler,
7479
DefaultAggregationSelector defaultAggregationSelector,
7580
@Nullable Authenticator authenticator) {
81+
this.host = host;
82+
this.port = port;
83+
this.otelScopeEnabled = otelScopeEnabled;
84+
this.allowedResourceAttributesFilter = allowedResourceAttributesFilter;
85+
this.memoryMode = memoryMode;
86+
this.defaultAggregationSelector = defaultAggregationSelector;
7687
this.builder = builder;
7788
this.prometheusMetricReader =
7889
new PrometheusMetricReader(otelScopeEnabled, allowedResourceAttributesFilter);
79-
this.host = host;
80-
this.memoryMode = memoryMode;
8190
this.prometheusRegistry = prometheusRegistry;
8291
prometheusRegistry.register(prometheusMetricReader);
8392
// When memory mode is REUSABLE_DATA, concurrent reads lead to data corruption. To prevent this,
@@ -106,7 +115,6 @@ public static PrometheusHttpServerBuilder builder() {
106115
} catch (IOException e) {
107116
throw new UncheckedIOException("Could not create Prometheus HTTP server", e);
108117
}
109-
this.defaultAggregationSelector = defaultAggregationSelector;
110118
}
111119

112120
@Override
@@ -160,7 +168,16 @@ public void close() {
160168

161169
@Override
162170
public String toString() {
163-
return "PrometheusHttpServer{address=" + getAddress() + "}";
171+
StringJoiner joiner = new StringJoiner(",", "PrometheusHttpServer{", "}");
172+
joiner.add("host=" + host);
173+
joiner.add("port=" + port);
174+
joiner.add("otelScopeEnabled=" + otelScopeEnabled);
175+
joiner.add("allowedResourceAttributesFilter=" + allowedResourceAttributesFilter);
176+
joiner.add("memoryMode=" + memoryMode);
177+
joiner.add(
178+
"defaultAggregationSelector="
179+
+ DefaultAggregationSelector.asString(defaultAggregationSelector));
180+
return joiner.toString();
164181
}
165182

166183
/**

exporters/prometheus/src/main/java/io/opentelemetry/exporter/prometheus/internal/PrometheusComponentProvider.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import io.opentelemetry.exporter.prometheus.PrometheusHttpServer;
1010
import io.opentelemetry.exporter.prometheus.PrometheusHttpServerBuilder;
1111
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
12+
import io.opentelemetry.sdk.internal.IncludeExcludePredicate;
1213
import io.opentelemetry.sdk.metrics.export.MetricReader;
14+
import java.util.List;
1315

1416
/**
1517
* Declarative configuration SPI implementation for {@link PrometheusHttpServer}.
@@ -37,11 +39,28 @@ public MetricReader create(DeclarativeConfigProperties config) {
3739
if (port != null) {
3840
prometheusBuilder.setPort(port);
3941
}
42+
4043
String host = config.getString("host");
4144
if (host != null) {
4245
prometheusBuilder.setHost(host);
4346
}
4447

48+
Boolean withoutScopeInfo = config.getBoolean("without_scope_info");
49+
if (withoutScopeInfo != null) {
50+
prometheusBuilder.setOtelScopeEnabled(!withoutScopeInfo);
51+
}
52+
53+
DeclarativeConfigProperties withResourceConstantLabels =
54+
config.getStructured("with_resource_constant_labels");
55+
if (withResourceConstantLabels != null) {
56+
List<String> included = withResourceConstantLabels.getScalarList("included", String.class);
57+
List<String> excluded = withResourceConstantLabels.getScalarList("excluded", String.class);
58+
if (included != null || excluded != null) {
59+
prometheusBuilder.setAllowedResourceAttributesFilter(
60+
IncludeExcludePredicate.createPatternMatching(included, excluded));
61+
}
62+
}
63+
4564
return prometheusBuilder.build();
4665
}
4766
}

exporters/prometheus/src/test/java/io/opentelemetry/exporter/prometheus/PrometheusHttpServerTest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,15 @@ void fetch_DuplicateMetrics() {
409409
@Test
410410
void stringRepresentation() {
411411
assertThat(prometheusServer.toString())
412-
.isEqualTo("PrometheusHttpServer{address=" + prometheusServer.getAddress() + "}");
412+
.isEqualTo(
413+
"PrometheusHttpServer{"
414+
+ "host=localhost,"
415+
+ "port=0,"
416+
+ "otelScopeEnabled=true,"
417+
+ "allowedResourceAttributesFilter=null,"
418+
+ "memoryMode=REUSABLE_DATA,"
419+
+ "defaultAggregationSelector=DefaultAggregationSelector{COUNTER=default, UP_DOWN_COUNTER=default, HISTOGRAM=default, OBSERVABLE_COUNTER=default, OBSERVABLE_UP_DOWN_COUNTER=default, OBSERVABLE_GAUGE=default, GAUGE=default}"
420+
+ "}");
413421
}
414422

415423
@Test

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ResourceFactory.java

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

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

8-
import static io.opentelemetry.sdk.internal.GlobUtil.createGlobPatternPredicate;
9-
108
import io.opentelemetry.api.common.Attributes;
119
import io.opentelemetry.sdk.autoconfigure.ResourceConfiguration;
1210
import io.opentelemetry.sdk.autoconfigure.spi.internal.DefaultConfigProperties;
@@ -15,6 +13,7 @@
1513
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalResourceDetectorModel;
1614
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel;
1715
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ResourceModel;
16+
import io.opentelemetry.sdk.internal.IncludeExcludePredicate;
1817
import io.opentelemetry.sdk.resources.Resource;
1918
import io.opentelemetry.sdk.resources.ResourceBuilder;
2019
import java.util.Collections;
@@ -90,35 +89,6 @@ private static Predicate<String> detectorAttributeFilter(
9089
if (included == null && excluded == null) {
9190
return ResourceFactory::matchAll;
9291
}
93-
if (included == null) {
94-
return excludedPredicate(excluded);
95-
}
96-
if (excluded == null) {
97-
return includedPredicate(included);
98-
}
99-
return includedPredicate(included).and(excludedPredicate(excluded));
100-
}
101-
102-
/**
103-
* Returns a predicate which matches strings matching any of the {@code included} glob patterns.
104-
*/
105-
private static Predicate<String> includedPredicate(List<String> included) {
106-
Predicate<String> result = attributeKey -> false;
107-
for (String include : included) {
108-
result = result.or(createGlobPatternPredicate(include));
109-
}
110-
return result;
111-
}
112-
113-
/**
114-
* Returns a predicate which matches strings NOT matching any of the {@code excluded} glob
115-
* patterns.
116-
*/
117-
private static Predicate<String> excludedPredicate(List<String> excluded) {
118-
Predicate<String> result = attributeKey -> true;
119-
for (String exclude : excluded) {
120-
result = result.and(createGlobPatternPredicate(exclude).negate());
121-
}
122-
return result;
92+
return IncludeExcludePredicate.createPatternMatching(included, excluded);
12393
}
12494
}

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactory.java

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@
77

88
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel;
99
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewStreamModel;
10+
import io.opentelemetry.sdk.internal.IncludeExcludePredicate;
1011
import io.opentelemetry.sdk.metrics.View;
1112
import io.opentelemetry.sdk.metrics.ViewBuilder;
12-
import java.util.HashSet;
1313
import java.util.List;
14-
import java.util.Set;
15-
import javax.annotation.Nullable;
1614

1715
final class ViewFactory implements Factory<ViewStreamModel, View> {
1816

@@ -35,7 +33,11 @@ public View create(ViewStreamModel model, DeclarativeConfigContext context) {
3533
}
3634
IncludeExcludeModel attributeKeys = model.getAttributeKeys();
3735
if (attributeKeys != null) {
38-
addAttributeKeyFilter(builder, attributeKeys.getIncluded(), attributeKeys.getExcluded());
36+
List<String> included = attributeKeys.getIncluded();
37+
List<String> excluded = attributeKeys.getExcluded();
38+
if (included != null || excluded != null) {
39+
builder.setAttributeFilter(IncludeExcludePredicate.createExactMatching(included, excluded));
40+
}
3941
}
4042
if (model.getAggregation() != null) {
4143
builder.setAggregation(
@@ -46,25 +48,4 @@ public View create(ViewStreamModel model, DeclarativeConfigContext context) {
4648
}
4749
return builder.build();
4850
}
49-
50-
private static void addAttributeKeyFilter(
51-
ViewBuilder builder, @Nullable List<String> included, @Nullable List<String> excluded) {
52-
if (included == null && excluded == null) {
53-
return;
54-
}
55-
if (included == null) {
56-
Set<String> excludedKeys = new HashSet<>(excluded);
57-
// TODO: set predicate with useful toString implementation
58-
builder.setAttributeFilter(attributeKey -> !excludedKeys.contains(attributeKey));
59-
return;
60-
}
61-
if (excluded == null) {
62-
Set<String> includedKeys = new HashSet<>(included);
63-
builder.setAttributeFilter(includedKeys);
64-
return;
65-
}
66-
Set<String> includedKeys = new HashSet<>(included);
67-
excluded.forEach(includedKeys::remove);
68-
builder.setAttributeFilter(includedKeys);
69-
}
7051
}

sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/MetricReaderFactoryTest.java

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.opentelemetry.sdk.extension.incubator.fileconfig;
77

88
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
9+
import static java.util.Collections.singletonList;
910
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1011
import static org.mockito.ArgumentMatchers.any;
1112
import static org.mockito.ArgumentMatchers.eq;
@@ -20,12 +21,14 @@
2021
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
2122
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.CardinalityLimitsModel;
2223
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExperimentalPrometheusMetricExporterModel;
24+
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel;
2325
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.MetricReaderModel;
2426
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OtlpHttpMetricExporterModel;
2527
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PeriodicMetricReaderModel;
2628
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricExporterModel;
2729
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PullMetricReaderModel;
2830
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.PushMetricExporterModel;
31+
import io.opentelemetry.sdk.internal.IncludeExcludePredicate;
2932
import io.opentelemetry.sdk.metrics.InstrumentType;
3033
import io.opentelemetry.sdk.metrics.export.MetricReader;
3134
import java.io.Closeable;
@@ -92,7 +95,7 @@ void create_PeriodicDefaults() {
9295
@Test
9396
void create_PeriodicConfigured() {
9497
List<Closeable> closeables = new ArrayList<>();
95-
io.opentelemetry.sdk.metrics.export.MetricReader expectedReader =
98+
MetricReader expectedReader =
9699
io.opentelemetry.sdk.metrics.export.PeriodicMetricReader.builder(
97100
OtlpHttpMetricExporter.getDefault())
98101
.setInterval(Duration.ofMillis(1))
@@ -143,8 +146,7 @@ void create_PullPrometheusDefault() throws IOException {
143146
new ExperimentalPrometheusMetricExporterModel()
144147
.withPort(port)))),
145148
context);
146-
io.opentelemetry.sdk.metrics.export.MetricReader reader =
147-
readerAndCardinalityLimits.getMetricReader();
149+
MetricReader reader = readerAndCardinalityLimits.getMetricReader();
148150
cleanup.addCloseable(reader);
149151
cleanup.addCloseables(closeables);
150152

@@ -160,7 +162,14 @@ void create_PullPrometheusConfigured() throws IOException {
160162

161163
List<Closeable> closeables = new ArrayList<>();
162164
PrometheusHttpServer expectedReader =
163-
PrometheusHttpServer.builder().setHost("localhost").setPort(port).build();
165+
PrometheusHttpServer.builder()
166+
.setHost("localhost")
167+
.setPort(port)
168+
.setOtelScopeEnabled(false)
169+
.setAllowedResourceAttributesFilter(
170+
IncludeExcludePredicate.createPatternMatching(
171+
singletonList("foo"), singletonList("bar")))
172+
.build();
164173
// Close the reader to avoid port conflict with the new instance created by MetricReaderFactory
165174
expectedReader.close();
166175

@@ -170,16 +179,22 @@ void create_PullPrometheusConfigured() throws IOException {
170179
new MetricReaderModel()
171180
.withPull(
172181
new PullMetricReaderModel()
182+
.withCardinalityLimits(new CardinalityLimitsModel().withDefault(100))
173183
.withExporter(
174184
new PullMetricExporterModel()
175185
.withPrometheusDevelopment(
176186
new ExperimentalPrometheusMetricExporterModel()
177187
.withHost("localhost")
178-
.withPort(port)))
179-
.withCardinalityLimits(new CardinalityLimitsModel().withDefault(100))),
188+
.withPort(port)
189+
.withWithResourceConstantLabels(
190+
new IncludeExcludeModel()
191+
.withIncluded(singletonList("foo"))
192+
.withExcluded(singletonList("bar")))
193+
.withWithoutScopeInfo(true)
194+
.withWithoutTypeSuffix(true)
195+
.withWithoutUnits(true)))),
180196
context);
181-
io.opentelemetry.sdk.metrics.export.MetricReader reader =
182-
readerAndCardinalityLimits.getMetricReader();
197+
MetricReader reader = readerAndCardinalityLimits.getMetricReader();
183198
cleanup.addCloseable(reader);
184199
cleanup.addCloseables(closeables);
185200

sdk-extensions/incubator/src/test/java/io/opentelemetry/sdk/extension/incubator/fileconfig/ViewFactoryTest.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ExplicitBucketHistogramAggregationModel;
1313
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.IncludeExcludeModel;
1414
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.ViewStreamModel;
15+
import io.opentelemetry.sdk.internal.IncludeExcludePredicate;
1516
import io.opentelemetry.sdk.metrics.View;
1617
import java.util.Arrays;
17-
import java.util.HashSet;
18+
import java.util.Collections;
1819
import org.junit.jupiter.api.Test;
1920

2021
class ViewFactoryTest {
@@ -38,7 +39,9 @@ void create() {
3839
View.builder()
3940
.setName("name")
4041
.setDescription("description")
41-
.setAttributeFilter(new HashSet<>(Arrays.asList("foo", "bar")))
42+
.setAttributeFilter(
43+
IncludeExcludePredicate.createExactMatching(
44+
Arrays.asList("foo", "bar"), Collections.singletonList("baz")))
4245
.setAggregation(
4346
io.opentelemetry.sdk.metrics.Aggregation.explicitBucketHistogram(
4447
Arrays.asList(1.0, 2.0)))
@@ -51,7 +54,9 @@ void create() {
5154
.withName("name")
5255
.withDescription("description")
5356
.withAttributeKeys(
54-
new IncludeExcludeModel().withIncluded(Arrays.asList("foo", "bar")))
57+
new IncludeExcludeModel()
58+
.withIncluded(Arrays.asList("foo", "bar"))
59+
.withExcluded(Collections.singletonList("baz")))
5560
.withAggregation(
5661
new AggregationModel()
5762
.withExplicitBucketHistogram(

0 commit comments

Comments
 (0)