diff --git a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/registry/PrometheusRegistry.java b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/registry/PrometheusRegistry.java index a8ab5a762..8b059adb3 100644 --- a/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/registry/PrometheusRegistry.java +++ b/prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/registry/PrometheusRegistry.java @@ -94,6 +94,8 @@ public MetricSnapshots scrape(Predicate includedNames, PrometheusScrapeR MetricSnapshots.Builder result = MetricSnapshots.builder(); for (Collector collector : collectors) { String prometheusName = collector.getPrometheusName(); + // prometheusName == null means the name is unknown, and we have to scrape to learn the name. + // prometheusName != null means we can skip the scrape if the name is excluded. if (prometheusName == null || includedNames.test(prometheusName)) { MetricSnapshot snapshot = scrapeRequest == null ? collector.collect(includedNames) : collector.collect(includedNames, scrapeRequest); if (snapshot != null) { @@ -103,8 +105,9 @@ public MetricSnapshots scrape(Predicate includedNames, PrometheusScrapeR } for (MultiCollector collector : multiCollectors) { List prometheusNames = collector.getPrometheusNames(); - boolean excluded = true; // the multi-collector is excluded unless - // at least one name matches + // empty prometheusNames means the names are unknown, and we have to scrape to learn the names. + // non-empty prometheusNames means we can exclude the collector if all names are excluded by the filter. + boolean excluded = !prometheusNames.isEmpty(); for (String prometheusName : prometheusNames) { if (includedNames.test(prometheusName)) { excluded = false; @@ -112,8 +115,8 @@ public MetricSnapshots scrape(Predicate includedNames, PrometheusScrapeR } } if (!excluded) { - MetricSnapshots snaphots = scrapeRequest == null ? collector.collect(includedNames) : collector.collect(includedNames, scrapeRequest); - for (MetricSnapshot snapshot : snaphots) { + MetricSnapshots snapshots = scrapeRequest == null ? collector.collect(includedNames) : collector.collect(includedNames, scrapeRequest); + for (MetricSnapshot snapshot : snapshots) { if (snapshot != null) { result.metricSnapshot(snapshot); } diff --git a/prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/registry/MetricNameFilterTest.java b/prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/registry/MetricNameFilterTest.java index 3b74f9dee..91bcf74fc 100644 --- a/prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/registry/MetricNameFilterTest.java +++ b/prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/registry/MetricNameFilterTest.java @@ -1,12 +1,21 @@ package io.prometheus.metrics.model.registry; import io.prometheus.metrics.model.snapshots.CounterSnapshot; +import io.prometheus.metrics.model.snapshots.CounterSnapshot.CounterDataPointSnapshot; +import io.prometheus.metrics.model.snapshots.GaugeSnapshot; +import io.prometheus.metrics.model.snapshots.GaugeSnapshot.GaugeDataPointSnapshot; import io.prometheus.metrics.model.snapshots.Labels; import io.prometheus.metrics.model.snapshots.MetricSnapshots; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; + public class MetricNameFilterTest { private PrometheusRegistry registry; @@ -21,12 +30,12 @@ public void testCounter() { registry.register(() -> CounterSnapshot.builder() .name("counter1") .help("test counter 1") - .dataPoint(CounterSnapshot.CounterDataPointSnapshot.builder() + .dataPoint(CounterDataPointSnapshot.builder() .labels(Labels.of("path", "/hello")) .value(1.0) .build() ) - .dataPoint(CounterSnapshot.CounterDataPointSnapshot.builder() + .dataPoint(CounterDataPointSnapshot.builder() .labels(Labels.of("path", "/goodbye")) .value(2.0) .build() @@ -36,7 +45,7 @@ public void testCounter() { registry.register(() -> CounterSnapshot.builder() .name("counter2") .help("test counter 2") - .dataPoint(CounterSnapshot.CounterDataPointSnapshot.builder() + .dataPoint(CounterDataPointSnapshot.builder() .value(1.0) .build() ) diff --git a/prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/registry/MultiCollectorNameFilterTest.java b/prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/registry/MultiCollectorNameFilterTest.java new file mode 100644 index 000000000..b36d58aa6 --- /dev/null +++ b/prometheus-metrics-model/src/test/java/io/prometheus/metrics/model/registry/MultiCollectorNameFilterTest.java @@ -0,0 +1,100 @@ +package io.prometheus.metrics.model.registry; + +import io.prometheus.metrics.model.snapshots.CounterSnapshot; +import io.prometheus.metrics.model.snapshots.CounterSnapshot.CounterDataPointSnapshot; +import io.prometheus.metrics.model.snapshots.GaugeSnapshot; +import io.prometheus.metrics.model.snapshots.GaugeSnapshot.GaugeDataPointSnapshot; +import io.prometheus.metrics.model.snapshots.MetricSnapshots; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; + +public class MultiCollectorNameFilterTest { + + private PrometheusRegistry registry; + private boolean[] collectCalled = {false}; + private Predicate includedNames = null; + List prometheusNames = new ArrayList<>(); + + @Before + public void setUp() { + registry = new PrometheusRegistry(); + collectCalled[0] = false; + includedNames = null; + prometheusNames = Collections.emptyList(); + + registry.register(new MultiCollector() { + @Override + public MetricSnapshots collect() { + collectCalled[0] = true; + return MetricSnapshots.builder() + .metricSnapshot(CounterSnapshot.builder() + .name("counter_1") + .dataPoint(CounterDataPointSnapshot.builder().value(1.0).build()) + .build() + ) + .metricSnapshot(GaugeSnapshot.builder() + .name("gauge_2") + .dataPoint(GaugeDataPointSnapshot.builder().value(1.0).build()) + .build() + ) + .build(); + } + + @Override + public List getPrometheusNames() { + return prometheusNames; + } + }); + } + + @Test + public void testPartialFilter() { + + includedNames = name -> name.equals("counter_1"); + + MetricSnapshots snapshots = registry.scrape(includedNames); + Assert.assertTrue(collectCalled[0]); + Assert.assertEquals(1, snapshots.size()); + Assert.assertEquals("counter_1", snapshots.get(0).getMetadata().getName()); + } + + @Test + public void testPartialFilterWithPrometheusNames() { + + includedNames = name -> name.equals("counter_1"); + prometheusNames = Arrays.asList("counter_1", "gauge_2"); + + MetricSnapshots snapshots = registry.scrape(includedNames); + Assert.assertTrue(collectCalled[0]); + Assert.assertEquals(1, snapshots.size()); + Assert.assertEquals("counter_1", snapshots.get(0).getMetadata().getName()); + } + + @Test + public void testCompleteFilter_CollectCalled() { + + includedNames = name -> !name.equals("counter_1") && !name.equals("gauge_2"); + + MetricSnapshots snapshots = registry.scrape(includedNames); + Assert.assertTrue(collectCalled[0]); + Assert.assertEquals(0, snapshots.size()); + } + + @Test + public void testCompleteFilter_CollectNotCalled() { + + includedNames = name -> !name.equals("counter_1") && !name.equals("gauge_2"); + prometheusNames = Arrays.asList("counter_1", "gauge_2"); + + MetricSnapshots snapshots = registry.scrape(includedNames); + Assert.assertFalse(collectCalled[0]); + Assert.assertEquals(0, snapshots.size()); + } +}