From 36f6e10aab95cf65fe01c90bb88bcbfa9f7dff21 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 4 May 2026 11:41:06 +0000 Subject: [PATCH 01/11] WIP expose collector metadata for prom-client-java compatibility Signed-off-by: Gregor Zeitlinger --- .../MicrometerCollector.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java index 0a04cc9468..c6266da490 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java @@ -17,10 +17,12 @@ import io.micrometer.core.instrument.Meter; import io.prometheus.metrics.model.registry.MultiCollector; +import io.prometheus.metrics.model.registry.MetricType; import io.prometheus.metrics.model.snapshots.DataPointSnapshot; import io.prometheus.metrics.model.snapshots.MetricMetadata; import io.prometheus.metrics.model.snapshots.MetricSnapshot; import io.prometheus.metrics.model.snapshots.MetricSnapshots; +import org.jspecify.annotations.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -72,6 +74,50 @@ Meter.Id getOriginalId() { return originalMeterId; } + @Override + public List getPrometheusNames() { + return Collections.singletonList(conventionName); + } + + @Override + public @Nullable MetricType getMetricType(String prometheusName) { + if (!conventionName.equals(prometheusName)) { + return null; + } + switch (originalMeterId.getType()) { + case COUNTER: + return MetricType.COUNTER; + case TIMER: + case LONG_TASK_TIMER: + case DISTRIBUTION_SUMMARY: + return MetricType.SUMMARY; + case GAUGE: + case OTHER: + default: + return MetricType.GAUGE; + } + } + + @Override + public @Nullable Set getLabelNames(String prometheusName) { + if (!conventionName.equals(prometheusName)) { + return null; + } + Set names = new HashSet<>(); + for (io.micrometer.core.instrument.Tag tag : originalMeterId.getConventionTags(new PrometheusNamingConvention())) { + names.add(tag.getKey()); + } + return names; + } + + @Override + public @Nullable MetricMetadata getMetadata(String prometheusName) { + if (!conventionName.equals(prometheusName)) { + return null; + } + return new MetricMetadata(conventionName, " ", null); + } + @Override public MetricSnapshots collect() { Map families = new HashMap<>(); From 5abca1b3f92aef90b0cad6e5de94b8dd28180f5c Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 4 May 2026 12:07:32 +0000 Subject: [PATCH 02/11] fix: align prometheus registration metadata Signed-off-by: Gregor Zeitlinger --- .../MicrometerCollector.java | 68 ++++++++++++------- .../PrometheusMeterRegistry.java | 40 ++++++++--- 2 files changed, 76 insertions(+), 32 deletions(-) diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java index c6266da490..568b9c8ea2 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java @@ -16,6 +16,10 @@ package io.micrometer.prometheusmetrics; import io.micrometer.core.instrument.Meter; +import io.prometheus.metrics.model.snapshots.CounterSnapshot; +import io.prometheus.metrics.model.snapshots.GaugeSnapshot; +import io.prometheus.metrics.model.snapshots.HistogramSnapshot; +import io.prometheus.metrics.model.snapshots.InfoSnapshot; import io.prometheus.metrics.model.registry.MultiCollector; import io.prometheus.metrics.model.registry.MetricType; import io.prometheus.metrics.model.snapshots.DataPointSnapshot; @@ -76,46 +80,58 @@ Meter.Id getOriginalId() { @Override public List getPrometheusNames() { - return Collections.singletonList(conventionName); + return metricSnapshots().stream() + .map(snapshot -> snapshot.getMetadata().getPrometheusName()) + .distinct() + .collect(toList()); } @Override public @Nullable MetricType getMetricType(String prometheusName) { - if (!conventionName.equals(prometheusName)) { - return null; - } - switch (originalMeterId.getType()) { - case COUNTER: - return MetricType.COUNTER; - case TIMER: - case LONG_TASK_TIMER: - case DISTRIBUTION_SUMMARY: - return MetricType.SUMMARY; - case GAUGE: - case OTHER: - default: - return MetricType.GAUGE; + for (MetricSnapshot snapshot : metricSnapshots()) { + if (snapshot.getMetadata().getPrometheusName().equals(prometheusName)) { + if (snapshot instanceof CounterSnapshot) { + return MetricType.COUNTER; + } + if (snapshot instanceof InfoSnapshot) { + return MetricType.INFO; + } + if (snapshot instanceof HistogramSnapshot) { + return MetricType.HISTOGRAM; + } + if (snapshot instanceof io.prometheus.metrics.model.snapshots.SummarySnapshot) { + return MetricType.SUMMARY; + } + if (snapshot instanceof GaugeSnapshot) { + return MetricType.GAUGE; + } + return MetricType.UNKNOWN; + } } + return null; } @Override public @Nullable Set getLabelNames(String prometheusName) { - if (!conventionName.equals(prometheusName)) { - return null; - } Set names = new HashSet<>(); - for (io.micrometer.core.instrument.Tag tag : originalMeterId.getConventionTags(new PrometheusNamingConvention())) { - names.add(tag.getKey()); + for (MetricSnapshot snapshot : metricSnapshots()) { + if (snapshot.getMetadata().getPrometheusName().equals(prometheusName)) { + for (DataPointSnapshot dataPoint : snapshot.getDataPoints()) { + dataPoint.getLabels().forEach(label -> names.add(label.getName())); + } + } } - return names; + return names.isEmpty() ? null : names; } @Override public @Nullable MetricMetadata getMetadata(String prometheusName) { - if (!conventionName.equals(prometheusName)) { - return null; + for (MetricSnapshot snapshot : metricSnapshots()) { + if (snapshot.getMetadata().getPrometheusName().equals(prometheusName)) { + return snapshot.getMetadata(); + } } - return new MetricMetadata(conventionName, " ", null); + return null; } @Override @@ -137,6 +153,10 @@ public MetricSnapshots collect() { return new MetricSnapshots(metricSnapshots); } + private List metricSnapshots() { + return collect().stream().collect(toList()); + } + interface Child { Stream> samples(String conventionName); diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java index c2f103baea..9639b9d4c5 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java @@ -219,8 +219,9 @@ public Counter newCounter(Meter.Id id) { List tagKeys = tagKeys(id); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName, id.getDescription()), new CounterDataPointSnapshot(counter.count(), - Labels.of(tagKeys, tagValues), counter.exemplar(), createdTimestampMillis)))); + getCounterMetadata(conventionName, id.getDescription()), + new CounterDataPointSnapshot(counter.count(), Labels.of(tagKeys, tagValues), + counter.exemplar(), createdTimestampMillis)))); }); return counter; } @@ -332,7 +333,7 @@ protected io.micrometer.core.instrument.Gauge newGauge(Meter.Id id, @Nullabl collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> new InfoSnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName, id.getDescription()), + getInfoMetadata(conventionName, id.getDescription()), new InfoDataPointSnapshot(Labels.of(tagKeys, tagValues))))); } else { @@ -383,8 +384,9 @@ protected FunctionCounter newFunctionCounter(Meter.Id id, T obj, ToDoubleFun collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName, id.getDescription()), new CounterDataPointSnapshot(fc.count(), - Labels.of(tagKeys, tagValues), null, createdTimestampMillis)))); + getCounterMetadata(conventionName, id.getDescription()), + new CounterDataPointSnapshot(fc.count(), Labels.of(tagKeys, tagValues), null, + createdTimestampMillis)))); }); return fc; } @@ -442,7 +444,7 @@ private MicrometerCollector.Family customCounterFamily long createdTimestampMillis = clock.wallTime(); return new MicrometerCollector.Family<>(conventionName + suffix, family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName + suffix, id.getDescription()), + getCounterMetadata(conventionName + suffix, id.getDescription()), new CounterDataPointSnapshot(value, labels, null, createdTimestampMillis)); } @@ -579,13 +581,35 @@ private MetricMetadata getMetadata(String name, @Nullable String description) { return new MetricMetadata(name, help, null); } + private MetricMetadata getCounterMetadata(String name, @Nullable String description) { + String help = prometheusConfig.descriptions() && description != null ? description : " "; + if (name.endsWith("_total")) { + return new MetricMetadata(name.substring(0, name.length() - "_total".length()), name, name, help, null); + } + return new MetricMetadata(name, help, null); + } + + private MetricMetadata getInfoMetadata(String name, @Nullable String description) { + String help = prometheusConfig.descriptions() && description != null ? description : " "; + if (name.endsWith("_info")) { + return new MetricMetadata(name.substring(0, name.length() - "_info".length()), name, name, help, null); + } + return new MetricMetadata(name, help, null); + } + private void applyToCollector(Meter.Id id, Consumer consumer) { collectorMap.compute(getConventionName(id), (name, existingCollector) -> { if (existingCollector == null) { MicrometerCollector micrometerCollector = new MicrometerCollector(name, id); consumer.accept(micrometerCollector); - registry.register(micrometerCollector); - return micrometerCollector; + try { + registry.register(micrometerCollector); + return micrometerCollector; + } + catch (IllegalArgumentException e) { + meterRegistrationFailed(id, e.getMessage()); + return null; + } } if (!existingCollector.getOriginalId().getName().equals(id.getName())) { From bea3c3badfaa12f302a5dbbe4ad68cd60ec9d419 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 4 May 2026 17:44:45 +0000 Subject: [PATCH 03/11] fix: validate prom-client-java family collisions Signed-off-by: Gregor Zeitlinger --- .../MicrometerCollector.java | 86 ++++++----- .../PrometheusMeterRegistry.java | 138 ++++++++++++++---- 2 files changed, 163 insertions(+), 61 deletions(-) diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java index 568b9c8ea2..14778a1d91 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java @@ -16,10 +16,6 @@ package io.micrometer.prometheusmetrics; import io.micrometer.core.instrument.Meter; -import io.prometheus.metrics.model.snapshots.CounterSnapshot; -import io.prometheus.metrics.model.snapshots.GaugeSnapshot; -import io.prometheus.metrics.model.snapshots.HistogramSnapshot; -import io.prometheus.metrics.model.snapshots.InfoSnapshot; import io.prometheus.metrics.model.registry.MultiCollector; import io.prometheus.metrics.model.registry.MetricType; import io.prometheus.metrics.model.snapshots.DataPointSnapshot; @@ -45,6 +41,7 @@ class MicrometerCollector implements MultiCollector { private final Map children = new ConcurrentHashMap<>(); + private final Map> descriptors = new ConcurrentHashMap<>(); private final String conventionName; @@ -58,12 +55,14 @@ class MicrometerCollector implements MultiCollector { this.originalMeterId = id; } - public void add(Meter.Id id, Child child) { + public void add(Meter.Id id, Child child, Descriptor... descriptors) { children.put(id, child); + this.descriptors.put(id, Arrays.asList(descriptors)); } public void remove(Meter.Id id) { children.remove(id); + descriptors.remove(id); } public boolean isEmpty() { @@ -80,32 +79,17 @@ Meter.Id getOriginalId() { @Override public List getPrometheusNames() { - return metricSnapshots().stream() - .map(snapshot -> snapshot.getMetadata().getPrometheusName()) + return registrationDescriptors().stream() + .map(Descriptor::getPrometheusName) .distinct() .collect(toList()); } @Override public @Nullable MetricType getMetricType(String prometheusName) { - for (MetricSnapshot snapshot : metricSnapshots()) { - if (snapshot.getMetadata().getPrometheusName().equals(prometheusName)) { - if (snapshot instanceof CounterSnapshot) { - return MetricType.COUNTER; - } - if (snapshot instanceof InfoSnapshot) { - return MetricType.INFO; - } - if (snapshot instanceof HistogramSnapshot) { - return MetricType.HISTOGRAM; - } - if (snapshot instanceof io.prometheus.metrics.model.snapshots.SummarySnapshot) { - return MetricType.SUMMARY; - } - if (snapshot instanceof GaugeSnapshot) { - return MetricType.GAUGE; - } - return MetricType.UNKNOWN; + for (Descriptor descriptor : registrationDescriptors()) { + if (descriptor.getPrometheusName().equals(prometheusName)) { + return descriptor.getMetricType(); } } return null; @@ -114,11 +98,9 @@ public List getPrometheusNames() { @Override public @Nullable Set getLabelNames(String prometheusName) { Set names = new HashSet<>(); - for (MetricSnapshot snapshot : metricSnapshots()) { - if (snapshot.getMetadata().getPrometheusName().equals(prometheusName)) { - for (DataPointSnapshot dataPoint : snapshot.getDataPoints()) { - dataPoint.getLabels().forEach(label -> names.add(label.getName())); - } + for (Descriptor descriptor : registrationDescriptors()) { + if (descriptor.getPrometheusName().equals(prometheusName)) { + names.addAll(descriptor.getLabelNames()); } } return names.isEmpty() ? null : names; @@ -126,9 +108,9 @@ public List getPrometheusNames() { @Override public @Nullable MetricMetadata getMetadata(String prometheusName) { - for (MetricSnapshot snapshot : metricSnapshots()) { - if (snapshot.getMetadata().getPrometheusName().equals(prometheusName)) { - return snapshot.getMetadata(); + for (Descriptor descriptor : registrationDescriptors()) { + if (descriptor.getPrometheusName().equals(prometheusName)) { + return descriptor.getMetadata(); } } return null; @@ -153,8 +135,8 @@ public MetricSnapshots collect() { return new MetricSnapshots(metricSnapshots); } - private List metricSnapshots() { - return collect().stream().collect(toList()); + private List registrationDescriptors() { + return descriptors.values().stream().flatMap(Collection::stream).collect(toList()); } interface Child { @@ -163,6 +145,40 @@ interface Child { } + static class Descriptor { + + private final String prometheusName; + + private final MetricType metricType; + + private final MetricMetadata metadata; + + private final Set labelNames; + + Descriptor(MetricType metricType, MetricMetadata metadata, Collection labelNames) { + this.prometheusName = metadata.getPrometheusName(); + this.metricType = metricType; + this.metadata = metadata; + this.labelNames = new LinkedHashSet<>(labelNames); + } + + String getPrometheusName() { + return prometheusName; + } + + MetricType getMetricType() { + return metricType; + } + + MetricMetadata getMetadata() { + return metadata; + } + + Set getLabelNames() { + return labelNames; + } + } + static class Family { final String conventionName; diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java index 9639b9d4c5..a739981b37 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java @@ -29,6 +29,7 @@ import io.prometheus.metrics.config.PrometheusProperties; import io.prometheus.metrics.config.PrometheusPropertiesLoader; import io.prometheus.metrics.expositionformats.ExpositionFormats; +import io.prometheus.metrics.model.registry.MetricType; import io.prometheus.metrics.model.registry.PrometheusRegistry; import io.prometheus.metrics.model.snapshots.*; import io.prometheus.metrics.model.snapshots.CounterSnapshot.CounterDataPointSnapshot; @@ -44,6 +45,7 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -217,11 +219,14 @@ public Counter newCounter(Meter.Id id) { applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); + MetricMetadata metadata = + getCounterMetadata(conventionName(id), id.getName(), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - getCounterMetadata(conventionName, id.getDescription()), + metadata, new CounterDataPointSnapshot(counter.count(), Labels.of(tagKeys, tagValues), - counter.exemplar(), createdTimestampMillis)))); + counter.exemplar(), createdTimestampMillis))), + descriptor(MetricType.COUNTER, metadata, tagKeys)); }); return counter; } @@ -235,6 +240,9 @@ public DistributionSummary newDistributionSummary(Meter.Id id, applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); + MetricMetadata summaryMetadata = getMetadata(conventionName(id), id.getDescription()); + MetricMetadata maxMetadata = getMetadata(conventionName(id) + "_max", id.getDescription()); + MetricType primaryType = summary.histogramCounts().length == 0 ? MetricType.SUMMARY : MetricType.HISTOGRAM; collector.add(id, (conventionName) -> { Stream.Builder> families = Stream.builder(); @@ -256,7 +264,7 @@ public DistributionSummary newDistributionSummary(Meter.Id id, Exemplars exemplars = summary.exemplars(); families.add(new MicrometerCollector.Family<>(conventionName, family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName, id.getDescription()), new SummaryDataPointSnapshot(count, sum, + summaryMetadata, new SummaryDataPointSnapshot(count, sum, quantiles, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); } else { @@ -286,7 +294,7 @@ public DistributionSummary newDistributionSummary(Meter.Id id, families.add(new MicrometerCollector.Family<>(conventionName, family -> new io.prometheus.metrics.model.snapshots.HistogramSnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName, id.getDescription()), + summaryMetadata, new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), sum, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); @@ -302,11 +310,13 @@ public DistributionSummary newDistributionSummary(Meter.Id id, families.add(new MicrometerCollector.Family<>(conventionName + "_max", family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName + "_max", id.getDescription()), + maxMetadata, new GaugeDataPointSnapshot(summary.max(), Labels.of(tagKeys, tagValues), null))); return families.build(); - }); + }, + descriptor(primaryType, summaryMetadata, tagKeys), + descriptor(MetricType.GAUGE, maxMetadata, tagKeys)); }); return summary; @@ -330,18 +340,22 @@ protected io.micrometer.core.instrument.Gauge newGauge(Meter.Id id, @Nullabl List tagValues = tagValues(id); List tagKeys = tagKeys(id); if (id.getName().endsWith(".info")) { + MetricMetadata infoMetadata = getInfoMetadata(conventionName(id), id.getName(), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> new InfoSnapshot(family.metadata, family.dataPointSnapshots), - getInfoMetadata(conventionName, id.getDescription()), - new InfoDataPointSnapshot(Labels.of(tagKeys, tagValues))))); + infoMetadata, + new InfoDataPointSnapshot(Labels.of(tagKeys, tagValues)))), + descriptor(MetricType.INFO, infoMetadata, tagKeys)); } else { + MetricMetadata metadata = getMetadata(conventionName(id), id.getName(), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName, id.getDescription()), - new GaugeDataPointSnapshot(gauge.value(), Labels.of(tagKeys, tagValues), null)))); + metadata, + new GaugeDataPointSnapshot(gauge.value(), Labels.of(tagKeys, tagValues), null))), + descriptor(MetricType.GAUGE, metadata, tagKeys)); } }); return gauge; @@ -381,12 +395,15 @@ protected FunctionCounter newFunctionCounter(Meter.Id id, T obj, ToDoubleFun applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); + MetricMetadata metadata = + getCounterMetadata(conventionName(id), id.getName(), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - getCounterMetadata(conventionName, id.getDescription()), + metadata, new CounterDataPointSnapshot(fc.count(), Labels.of(tagKeys, tagValues), null, - createdTimestampMillis)))); + createdTimestampMillis))), + descriptor(MetricType.COUNTER, metadata, tagKeys)); }); return fc; } @@ -396,10 +413,42 @@ protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable mea applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); + List statKeys = new ArrayList<>(tagKeys); + statKeys.add("statistic"); + List registrationDescriptors = new ArrayList<>(); + String name = conventionName(id); + for (Measurement measurement : measurements) { + switch (measurement.getStatistic()) { + case TOTAL: + case TOTAL_TIME: + registrationDescriptors.add(descriptor(MetricType.COUNTER, + getCounterMetadata(name + "_sum", id.getDescription()), statKeys)); + break; + case COUNT: + registrationDescriptors.add(descriptor(MetricType.COUNTER, + getCounterMetadata(name, id.getDescription()), statKeys)); + break; + case MAX: + registrationDescriptors.add(descriptor(MetricType.GAUGE, + getMetadata(name + "_max", id.getDescription()), statKeys)); + break; + case VALUE: + case UNKNOWN: + registrationDescriptors.add(descriptor(MetricType.GAUGE, + getMetadata(name + "_value", id.getDescription()), statKeys)); + break; + case ACTIVE_TASKS: + registrationDescriptors.add(descriptor(MetricType.GAUGE, + getMetadata(name + "_active_count", id.getDescription()), statKeys)); + break; + case DURATION: + registrationDescriptors.add(descriptor(MetricType.GAUGE, + getMetadata(name + "_duration_sum", id.getDescription()), statKeys)); + break; + } + } collector.add(id, (conventionName) -> { Stream.Builder> families = Stream.builder(); - List statKeys = new ArrayList<>(tagKeys); - statKeys.add("statistic"); for (Measurement measurement : measurements) { List statValues = new ArrayList<>(tagValues); statValues.add(measurement.getStatistic().toString()); @@ -433,7 +482,7 @@ protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable mea } } return families.build(); - }); + }, registrationDescriptors.toArray(new MicrometerCollector.Descriptor[0])); }); return new DefaultMeter(id, type, measurements); @@ -473,6 +522,10 @@ private void addDistributionStatisticSamples(Meter.Id id, MicrometerCollector co boolean forLongTaskTimer) { long createdTimestampMillis = clock.wallTime(); List tagKeys = tagKeys(id); + MetricMetadata primaryMetadata = getMetadata(conventionName(id), id.getDescription()); + MetricMetadata maxMetadata = getMetadata(conventionName(id) + "_max", id.getDescription()); + MetricType primaryType = histogramSupport.takeSnapshot().histogramCounts().length == 0 + ? MetricType.SUMMARY : MetricType.HISTOGRAM; collector.add(id, (conventionName) -> { Stream.Builder> families = Stream.builder(); @@ -495,7 +548,7 @@ private void addDistributionStatisticSamples(Meter.Id id, MicrometerCollector co Exemplars exemplars = createExemplarsWithScaledValues(exemplarsSupplier.get()); families.add(new MicrometerCollector.Family<>(conventionName, family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName, id.getDescription()), new SummaryDataPointSnapshot(count, sum, + primaryMetadata, new SummaryDataPointSnapshot(count, sum, quantiles, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); } else { @@ -525,7 +578,7 @@ private void addDistributionStatisticSamples(Meter.Id id, MicrometerCollector co families.add(new MicrometerCollector.Family<>(conventionName, family -> new io.prometheus.metrics.model.snapshots.HistogramSnapshot(forLongTaskTimer, family.metadata, family.dataPointSnapshots), - getMetadata(conventionName, id.getDescription()), + primaryMetadata, new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), sum, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); @@ -541,11 +594,22 @@ private void addDistributionStatisticSamples(Meter.Id id, MicrometerCollector co families.add(new MicrometerCollector.Family<>(conventionName + "_max", family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName + "_max", id.getDescription()), new GaugeDataPointSnapshot( + maxMetadata, new GaugeDataPointSnapshot( histogramSnapshot.max(getBaseTimeUnit()), Labels.of(tagKeys, tagValues), null))); return families.build(); - }); + }, + descriptor(primaryType, primaryMetadata, tagKeys), + descriptor(MetricType.GAUGE, maxMetadata, tagKeys)); + } + + private String conventionName(Meter.Id id) { + return getConventionName(id); + } + + private MicrometerCollector.Descriptor descriptor( + MetricType metricType, MetricMetadata metadata, Collection labelNames) { + return new MicrometerCollector.Descriptor(metricType, metadata, labelNames); } private Exemplars createExemplarsWithScaledValues(Exemplars exemplars) { @@ -575,26 +639,48 @@ private void onMeterRemoved(Meter meter) { } private MetricMetadata getMetadata(String name, @Nullable String description) { + return getMetadata(name, name, description); + } + + private MetricMetadata getMetadata(String name, String originalName, @Nullable String description) { String help = prometheusConfig.descriptions() && description != null ? description : " "; // Unit is intentionally not set, see: // https://github.com/OpenObservability/OpenMetrics/blob/1386544931307dff279688f332890c31b6c5de36/specification/OpenMetrics.md#unit - return new MetricMetadata(name, help, null); + return new MetricMetadata(name, name, originalName, help, null); } private MetricMetadata getCounterMetadata(String name, @Nullable String description) { + return getCounterMetadata(name, name, description); + } + + private MetricMetadata getCounterMetadata(String name, String originalName, @Nullable String description) { String help = prometheusConfig.descriptions() && description != null ? description : " "; - if (name.endsWith("_total")) { - return new MetricMetadata(name.substring(0, name.length() - "_total".length()), name, name, help, null); + String baseName = name; + if (originalName.endsWith(".bucket")) { + baseName = stripSuffix(name, "_bucket"); + } + else if (originalName.endsWith(".created")) { + baseName = stripSuffix(name, "_created"); } - return new MetricMetadata(name, help, null); + else if (originalName.endsWith(".info")) { + baseName = stripSuffix(name, "_info"); + } + else if (name.endsWith("_total")) { + baseName = stripSuffix(name, "_total"); + } + return new MetricMetadata(baseName, name, originalName, help, null); } - private MetricMetadata getInfoMetadata(String name, @Nullable String description) { + private MetricMetadata getInfoMetadata(String name, String originalName, @Nullable String description) { String help = prometheusConfig.descriptions() && description != null ? description : " "; if (name.endsWith("_info")) { - return new MetricMetadata(name.substring(0, name.length() - "_info".length()), name, name, help, null); + return new MetricMetadata(stripSuffix(name, "_info"), name, originalName, help, null); } - return new MetricMetadata(name, help, null); + return new MetricMetadata(name, name, originalName, help, null); + } + + private static String stripSuffix(String name, String suffix) { + return name.endsWith(suffix) ? name.substring(0, name.length() - suffix.length()) : name; } private void applyToCollector(Meter.Id id, Consumer consumer) { From d2d2f03c75702742666c51304280a49083d98372 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 5 May 2026 16:39:43 +0000 Subject: [PATCH 04/11] refactor: share custom meter metadata mapping Signed-off-by: Gregor Zeitlinger --- .../PrometheusMeterRegistry.java | 132 +++++++++--------- 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java index a739981b37..a8d2a3ec25 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java @@ -418,68 +418,15 @@ protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable mea List registrationDescriptors = new ArrayList<>(); String name = conventionName(id); for (Measurement measurement : measurements) { - switch (measurement.getStatistic()) { - case TOTAL: - case TOTAL_TIME: - registrationDescriptors.add(descriptor(MetricType.COUNTER, - getCounterMetadata(name + "_sum", id.getDescription()), statKeys)); - break; - case COUNT: - registrationDescriptors.add(descriptor(MetricType.COUNTER, - getCounterMetadata(name, id.getDescription()), statKeys)); - break; - case MAX: - registrationDescriptors.add(descriptor(MetricType.GAUGE, - getMetadata(name + "_max", id.getDescription()), statKeys)); - break; - case VALUE: - case UNKNOWN: - registrationDescriptors.add(descriptor(MetricType.GAUGE, - getMetadata(name + "_value", id.getDescription()), statKeys)); - break; - case ACTIVE_TASKS: - registrationDescriptors.add(descriptor(MetricType.GAUGE, - getMetadata(name + "_active_count", id.getDescription()), statKeys)); - break; - case DURATION: - registrationDescriptors.add(descriptor(MetricType.GAUGE, - getMetadata(name + "_duration_sum", id.getDescription()), statKeys)); - break; - } + registrationDescriptors.add(customMeterDescriptor(id, name, measurement.getStatistic(), statKeys)); } collector.add(id, (conventionName) -> { Stream.Builder> families = Stream.builder(); for (Measurement measurement : measurements) { List statValues = new ArrayList<>(tagValues); statValues.add(measurement.getStatistic().toString()); - switch (measurement.getStatistic()) { - case TOTAL: - case TOTAL_TIME: - families.add(customCounterFamily(id, conventionName, "_sum", - Labels.of(statKeys, statValues), measurement.getValue())); - break; - case COUNT: - families.add(customCounterFamily(id, conventionName, "", Labels.of(statKeys, statValues), - measurement.getValue())); - break; - case MAX: - families.add(customGaugeFamily(id, conventionName, "_max", Labels.of(statKeys, statValues), - measurement.getValue())); - break; - case VALUE: - case UNKNOWN: - families.add(customGaugeFamily(id, conventionName, "_value", - Labels.of(statKeys, statValues), measurement.getValue())); - break; - case ACTIVE_TASKS: - families.add(customGaugeFamily(id, conventionName, "_active_count", - Labels.of(statKeys, statValues), measurement.getValue())); - break; - case DURATION: - families.add(customGaugeFamily(id, conventionName, "_duration_sum", - Labels.of(statKeys, statValues), measurement.getValue())); - break; - } + families.add(customMeterFamily(id, conventionName, measurement.getStatistic(), + Labels.of(statKeys, statValues), measurement.getValue())); } return families.build(); }, registrationDescriptors.toArray(new MicrometerCollector.Descriptor[0])); @@ -488,23 +435,80 @@ protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable mea return new DefaultMeter(id, type, measurements); } - private MicrometerCollector.Family customCounterFamily(Meter.Id id, String conventionName, - String suffix, Labels labels, double value) { + private MicrometerCollector.Descriptor customMeterDescriptor( + Meter.Id id, String conventionName, Statistic statistic, Collection labelNames) { + CustomMeterMetric metric = customMeterMetric(id, conventionName, statistic); + return descriptor(metric.metricType, metric.metadata, labelNames); + } + + private MicrometerCollector.Family customMeterFamily( + Meter.Id id, String conventionName, Statistic statistic, Labels labels, double value) { + CustomMeterMetric metric = customMeterMetric(id, conventionName, statistic); + if (metric.metricType == MetricType.COUNTER) { + return customCounterFamily(metric, labels, value); + } + return customGaugeFamily(metric, labels, value); + } + + private CustomMeterMetric customMeterMetric(Meter.Id id, String conventionName, Statistic statistic) { + switch (statistic) { + case TOTAL: + case TOTAL_TIME: + return new CustomMeterMetric(conventionName + "_sum", MetricType.COUNTER, + getCounterMetadata(conventionName + "_sum", id.getDescription())); + case COUNT: + return new CustomMeterMetric(conventionName, MetricType.COUNTER, + getCounterMetadata(conventionName, id.getDescription())); + case MAX: + return new CustomMeterMetric(conventionName + "_max", MetricType.GAUGE, + getMetadata(conventionName + "_max", id.getDescription())); + case VALUE: + case UNKNOWN: + return new CustomMeterMetric(conventionName + "_value", MetricType.GAUGE, + getMetadata(conventionName + "_value", id.getDescription())); + case ACTIVE_TASKS: + return new CustomMeterMetric(conventionName + "_active_count", MetricType.GAUGE, + getMetadata(conventionName + "_active_count", id.getDescription())); + case DURATION: + return new CustomMeterMetric(conventionName + "_duration_sum", MetricType.GAUGE, + getMetadata(conventionName + "_duration_sum", id.getDescription())); + default: + throw new IllegalArgumentException("Unsupported meter statistic: " + statistic); + } + } + + private MicrometerCollector.Family customCounterFamily( + CustomMeterMetric metric, Labels labels, double value) { long createdTimestampMillis = clock.wallTime(); - return new MicrometerCollector.Family<>(conventionName + suffix, + return new MicrometerCollector.Family<>(metric.name, family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - getCounterMetadata(conventionName + suffix, id.getDescription()), + metric.metadata, new CounterDataPointSnapshot(value, labels, null, createdTimestampMillis)); } - private MicrometerCollector.Family customGaugeFamily(Meter.Id id, String conventionName, - String suffix, Labels labels, double value) { - return new MicrometerCollector.Family<>(conventionName + suffix, + private MicrometerCollector.Family customGaugeFamily( + CustomMeterMetric metric, Labels labels, double value) { + return new MicrometerCollector.Family<>(metric.name, family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName + suffix, id.getDescription()), + metric.metadata, new GaugeDataPointSnapshot(value, labels, null)); } + private static class CustomMeterMetric { + + private final String name; + + private final MetricType metricType; + + private final MetricMetadata metadata; + + private CustomMeterMetric(String name, MetricType metricType, MetricMetadata metadata) { + this.name = name; + this.metricType = metricType; + this.metadata = metadata; + } + } + @Override protected TimeUnit getBaseTimeUnit() { return SECONDS; From 72851a5924941adc414c13b05848d3e4567c6722 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 5 May 2026 16:45:38 +0000 Subject: [PATCH 05/11] refactor: centralize suffix base-name normalization Signed-off-by: Gregor Zeitlinger --- .../PrometheusMeterRegistry.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java index a8d2a3ec25..232c802f34 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java @@ -659,17 +659,9 @@ private MetricMetadata getCounterMetadata(String name, @Nullable String descript private MetricMetadata getCounterMetadata(String name, String originalName, @Nullable String description) { String help = prometheusConfig.descriptions() && description != null ? description : " "; - String baseName = name; - if (originalName.endsWith(".bucket")) { - baseName = stripSuffix(name, "_bucket"); - } - else if (originalName.endsWith(".created")) { - baseName = stripSuffix(name, "_created"); - } - else if (originalName.endsWith(".info")) { - baseName = stripSuffix(name, "_info"); - } - else if (name.endsWith("_total")) { + String baseName = normalizeBaseName(name, originalName, ".bucket", "_bucket", ".created", "_created", + ".info", "_info"); + if (baseName.equals(name)) { baseName = stripSuffix(name, "_total"); } return new MetricMetadata(baseName, name, originalName, help, null); @@ -677,10 +669,17 @@ else if (name.endsWith("_total")) { private MetricMetadata getInfoMetadata(String name, String originalName, @Nullable String description) { String help = prometheusConfig.descriptions() && description != null ? description : " "; - if (name.endsWith("_info")) { - return new MetricMetadata(stripSuffix(name, "_info"), name, originalName, help, null); + return new MetricMetadata(normalizeBaseName(name, originalName, ".info", "_info"), name, originalName, help, + null); + } + + private static String normalizeBaseName(String name, String originalName, String... suffixMappings) { + for (int i = 0; i < suffixMappings.length; i += 2) { + if (originalName.endsWith(suffixMappings[i])) { + return stripSuffix(name, suffixMappings[i + 1]); + } } - return new MetricMetadata(name, name, originalName, help, null); + return name; } private static String stripSuffix(String name, String suffix) { From fdd1075eadcf7b9b06171abae1c44cf249361343 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 6 May 2026 08:09:06 +0000 Subject: [PATCH 06/11] fix: restore prometheus metadata compatibility Signed-off-by: Gregor Zeitlinger --- .../MicrometerCollector.java | 4 +- .../PrometheusMeterRegistry.java | 41 +++++++++---------- .../MicrometerCollectorTest.java | 22 ++++++++++ 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java index 14778a1d91..87a43ef677 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java @@ -155,8 +155,8 @@ static class Descriptor { private final Set labelNames; - Descriptor(MetricType metricType, MetricMetadata metadata, Collection labelNames) { - this.prometheusName = metadata.getPrometheusName(); + Descriptor(String prometheusName, MetricType metricType, MetricMetadata metadata, Collection labelNames) { + this.prometheusName = prometheusName; this.metricType = metricType; this.metadata = metadata; this.labelNames = new LinkedHashSet<>(labelNames); diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java index 232c802f34..5de92e9b48 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java @@ -226,7 +226,7 @@ public Counter newCounter(Meter.Id id) { metadata, new CounterDataPointSnapshot(counter.count(), Labels.of(tagKeys, tagValues), counter.exemplar(), createdTimestampMillis))), - descriptor(MetricType.COUNTER, metadata, tagKeys)); + descriptor(conventionName(id), MetricType.COUNTER, metadata, tagKeys)); }); return counter; } @@ -315,8 +315,8 @@ summaryMetadata, new SummaryDataPointSnapshot(count, sum, return families.build(); }, - descriptor(primaryType, summaryMetadata, tagKeys), - descriptor(MetricType.GAUGE, maxMetadata, tagKeys)); + descriptor(conventionName(id), primaryType, summaryMetadata, tagKeys), + descriptor(conventionName(id) + "_max", MetricType.GAUGE, maxMetadata, tagKeys)); }); return summary; @@ -346,16 +346,16 @@ protected io.micrometer.core.instrument.Gauge newGauge(Meter.Id id, @Nullabl family -> new InfoSnapshot(family.metadata, family.dataPointSnapshots), infoMetadata, new InfoDataPointSnapshot(Labels.of(tagKeys, tagValues)))), - descriptor(MetricType.INFO, infoMetadata, tagKeys)); + descriptor(conventionName(id), MetricType.INFO, infoMetadata, tagKeys)); } else { - MetricMetadata metadata = getMetadata(conventionName(id), id.getName(), id.getDescription()); + MetricMetadata metadata = getMetadata(conventionName(id), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), metadata, new GaugeDataPointSnapshot(gauge.value(), Labels.of(tagKeys, tagValues), null))), - descriptor(MetricType.GAUGE, metadata, tagKeys)); + descriptor(conventionName(id), MetricType.GAUGE, metadata, tagKeys)); } }); return gauge; @@ -378,12 +378,14 @@ protected FunctionTimer newFunctionTimer(Meter.Id id, T obj, ToLongFunction< applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); + MetricMetadata metadata = getMetadata(conventionName(id), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), - getMetadata(conventionName, id.getDescription()), + metadata, new SummaryDataPointSnapshot((long) ft.count(), ft.totalTime(getBaseTimeUnit()), - Quantiles.EMPTY, Labels.of(tagKeys, tagValues), null, createdTimestampMillis)))); + Quantiles.EMPTY, Labels.of(tagKeys, tagValues), null, createdTimestampMillis))), + descriptor(conventionName(id), MetricType.SUMMARY, metadata, tagKeys)); }); return ft; } @@ -403,7 +405,7 @@ protected FunctionCounter newFunctionCounter(Meter.Id id, T obj, ToDoubleFun metadata, new CounterDataPointSnapshot(fc.count(), Labels.of(tagKeys, tagValues), null, createdTimestampMillis))), - descriptor(MetricType.COUNTER, metadata, tagKeys)); + descriptor(conventionName(id), MetricType.COUNTER, metadata, tagKeys)); }); return fc; } @@ -438,7 +440,7 @@ protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable mea private MicrometerCollector.Descriptor customMeterDescriptor( Meter.Id id, String conventionName, Statistic statistic, Collection labelNames) { CustomMeterMetric metric = customMeterMetric(id, conventionName, statistic); - return descriptor(metric.metricType, metric.metadata, labelNames); + return descriptor(metric.name, metric.metricType, metric.metadata, labelNames); } private MicrometerCollector.Family customMeterFamily( @@ -603,8 +605,8 @@ maxMetadata, new GaugeDataPointSnapshot( return families.build(); }, - descriptor(primaryType, primaryMetadata, tagKeys), - descriptor(MetricType.GAUGE, maxMetadata, tagKeys)); + descriptor(conventionName(id), primaryType, primaryMetadata, tagKeys), + descriptor(conventionName(id) + "_max", MetricType.GAUGE, maxMetadata, tagKeys)); } private String conventionName(Meter.Id id) { @@ -612,8 +614,8 @@ private String conventionName(Meter.Id id) { } private MicrometerCollector.Descriptor descriptor( - MetricType metricType, MetricMetadata metadata, Collection labelNames) { - return new MicrometerCollector.Descriptor(metricType, metadata, labelNames); + String prometheusName, MetricType metricType, MetricMetadata metadata, Collection labelNames) { + return new MicrometerCollector.Descriptor(prometheusName, metricType, metadata, labelNames); } private Exemplars createExemplarsWithScaledValues(Exemplars exemplars) { @@ -643,14 +645,10 @@ private void onMeterRemoved(Meter meter) { } private MetricMetadata getMetadata(String name, @Nullable String description) { - return getMetadata(name, name, description); - } - - private MetricMetadata getMetadata(String name, String originalName, @Nullable String description) { String help = prometheusConfig.descriptions() && description != null ? description : " "; // Unit is intentionally not set, see: // https://github.com/OpenObservability/OpenMetrics/blob/1386544931307dff279688f332890c31b6c5de36/specification/OpenMetrics.md#unit - return new MetricMetadata(name, name, originalName, help, null); + return new MetricMetadata(name, help, null); } private MetricMetadata getCounterMetadata(String name, @Nullable String description) { @@ -664,13 +662,12 @@ private MetricMetadata getCounterMetadata(String name, String originalName, @Nul if (baseName.equals(name)) { baseName = stripSuffix(name, "_total"); } - return new MetricMetadata(baseName, name, originalName, help, null); + return new MetricMetadata(baseName, help, null); } private MetricMetadata getInfoMetadata(String name, String originalName, @Nullable String description) { String help = prometheusConfig.descriptions() && description != null ? description : " "; - return new MetricMetadata(normalizeBaseName(name, originalName, ".info", "_info"), name, originalName, help, - null); + return new MetricMetadata(normalizeBaseName(name, originalName, ".info", "_info"), help, null); } private static String normalizeBaseName(String name, String originalName, String... suffixMappings) { diff --git a/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java b/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java index e8fa44ffc0..84b51ddd88 100644 --- a/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java +++ b/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java @@ -21,11 +21,13 @@ import io.micrometer.core.instrument.Tag; import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.config.NamingConvention; +import io.prometheus.metrics.model.registry.MetricType; import io.prometheus.metrics.model.snapshots.CounterSnapshot; import io.prometheus.metrics.model.snapshots.Labels; import io.prometheus.metrics.model.snapshots.MetricMetadata; import org.junit.jupiter.api.Test; +import java.util.Objects; import java.util.stream.Stream; import static java.util.Arrays.asList; @@ -152,4 +154,24 @@ void sameMetricNameWithNoTagsAndAListOfTags() { assertThat(collector.collect().get(0).getDataPoints()).hasSize(2); } + @Test + void registrationDescriptorUsesPrometheusFamilyName() { + Meter.Id id = Metrics.counter("my.counter").getId(); + MicrometerCollector collector = new MicrometerCollector(id.getConventionName(convention), id); + + CounterSnapshot.CounterDataPointSnapshot sample = new CounterSnapshot.CounterDataPointSnapshot(1.0, + Labels.of("k", "v"), null, 0); + MetricMetadata metadata = new MetricMetadata("my_counter", "help"); + + collector.add(id, + (conventionName) -> Stream.of(new MicrometerCollector.Family<>("my_counter_total", + family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), metadata, sample)), + new MicrometerCollector.Descriptor("my_counter_total", MetricType.COUNTER, metadata, asList("k"))); + + assertThat(collector.getPrometheusNames()).containsExactly("my_counter_total"); + assertThat(collector.getMetricType("my_counter_total")).isEqualTo(MetricType.COUNTER); + assertThat(collector.getLabelNames("my_counter_total")).containsExactly("k"); + assertThat(Objects.requireNonNull(collector.getMetadata("my_counter_total")).getName()).isEqualTo("my_counter"); + } + } From b277d5f5f28e3a29cd08791040a9226241409323 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 6 May 2026 09:13:30 +0000 Subject: [PATCH 07/11] style: format prometheus metadata changes Signed-off-by: Gregor Zeitlinger --- .../MicrometerCollector.java | 10 +- .../PrometheusMeterRegistry.java | 100 ++++++++---------- 2 files changed, 49 insertions(+), 61 deletions(-) diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java index 87a43ef677..cf59b73ca9 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java @@ -41,6 +41,7 @@ class MicrometerCollector implements MultiCollector { private final Map children = new ConcurrentHashMap<>(); + private final Map> descriptors = new ConcurrentHashMap<>(); private final String conventionName; @@ -79,10 +80,7 @@ Meter.Id getOriginalId() { @Override public List getPrometheusNames() { - return registrationDescriptors().stream() - .map(Descriptor::getPrometheusName) - .distinct() - .collect(toList()); + return registrationDescriptors().stream().map(Descriptor::getPrometheusName).distinct().collect(toList()); } @Override @@ -155,7 +153,8 @@ static class Descriptor { private final Set labelNames; - Descriptor(String prometheusName, MetricType metricType, MetricMetadata metadata, Collection labelNames) { + Descriptor(String prometheusName, MetricType metricType, MetricMetadata metadata, + Collection labelNames) { this.prometheusName = prometheusName; this.metricType = metricType; this.metadata = metadata; @@ -177,6 +176,7 @@ MetricMetadata getMetadata() { Set getLabelNames() { return labelNames; } + } static class Family { diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java index 5de92e9b48..d24e9e15c0 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java @@ -219,13 +219,12 @@ public Counter newCounter(Meter.Id id) { applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); - MetricMetadata metadata = - getCounterMetadata(conventionName(id), id.getName(), id.getDescription()); - collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - metadata, - new CounterDataPointSnapshot(counter.count(), Labels.of(tagKeys, tagValues), - counter.exemplar(), createdTimestampMillis))), + MetricMetadata metadata = getCounterMetadata(conventionName(id), id.getName(), id.getDescription()); + collector.add(id, + (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, + family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), metadata, + new CounterDataPointSnapshot(counter.count(), Labels.of(tagKeys, tagValues), + counter.exemplar(), createdTimestampMillis))), descriptor(conventionName(id), MetricType.COUNTER, metadata, tagKeys)); }); return counter; @@ -263,9 +262,9 @@ public DistributionSummary newDistributionSummary(Meter.Id id, Exemplars exemplars = summary.exemplars(); families.add(new MicrometerCollector.Family<>(conventionName, - family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), - summaryMetadata, new SummaryDataPointSnapshot(count, sum, - quantiles, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); + family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), summaryMetadata, + new SummaryDataPointSnapshot(count, sum, quantiles, Labels.of(tagKeys, tagValues), + exemplars, createdTimestampMillis))); } else { List buckets = new ArrayList<>(); @@ -294,9 +293,8 @@ summaryMetadata, new SummaryDataPointSnapshot(count, sum, families.add(new MicrometerCollector.Family<>(conventionName, family -> new io.prometheus.metrics.model.snapshots.HistogramSnapshot(family.metadata, family.dataPointSnapshots), - summaryMetadata, - new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), sum, - Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); + summaryMetadata, new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), + sum, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); // TODO: Add support back for VictoriaMetrics // Previously we had low-level control so a histogram was just @@ -309,13 +307,11 @@ summaryMetadata, new SummaryDataPointSnapshot(count, sum, } families.add(new MicrometerCollector.Family<>(conventionName + "_max", - family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), - maxMetadata, + family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), maxMetadata, new GaugeDataPointSnapshot(summary.max(), Labels.of(tagKeys, tagValues), null))); return families.build(); - }, - descriptor(conventionName(id), primaryType, summaryMetadata, tagKeys), + }, descriptor(conventionName(id), primaryType, summaryMetadata, tagKeys), descriptor(conventionName(id) + "_max", MetricType.GAUGE, maxMetadata, tagKeys)); }); @@ -343,8 +339,7 @@ protected io.micrometer.core.instrument.Gauge newGauge(Meter.Id id, @Nullabl MetricMetadata infoMetadata = getInfoMetadata(conventionName(id), id.getName(), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new InfoSnapshot(family.metadata, family.dataPointSnapshots), - infoMetadata, + family -> new InfoSnapshot(family.metadata, family.dataPointSnapshots), infoMetadata, new InfoDataPointSnapshot(Labels.of(tagKeys, tagValues)))), descriptor(conventionName(id), MetricType.INFO, infoMetadata, tagKeys)); } @@ -352,8 +347,7 @@ protected io.micrometer.core.instrument.Gauge newGauge(Meter.Id id, @Nullabl MetricMetadata metadata = getMetadata(conventionName(id), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), - metadata, + family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), metadata, new GaugeDataPointSnapshot(gauge.value(), Labels.of(tagKeys, tagValues), null))), descriptor(conventionName(id), MetricType.GAUGE, metadata, tagKeys)); } @@ -381,8 +375,7 @@ protected FunctionTimer newFunctionTimer(Meter.Id id, T obj, ToLongFunction< MetricMetadata metadata = getMetadata(conventionName(id), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), - metadata, + family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), metadata, new SummaryDataPointSnapshot((long) ft.count(), ft.totalTime(getBaseTimeUnit()), Quantiles.EMPTY, Labels.of(tagKeys, tagValues), null, createdTimestampMillis))), descriptor(conventionName(id), MetricType.SUMMARY, metadata, tagKeys)); @@ -397,12 +390,10 @@ protected FunctionCounter newFunctionCounter(Meter.Id id, T obj, ToDoubleFun applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); - MetricMetadata metadata = - getCounterMetadata(conventionName(id), id.getName(), id.getDescription()); + MetricMetadata metadata = getCounterMetadata(conventionName(id), id.getName(), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - metadata, + family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), metadata, new CounterDataPointSnapshot(fc.count(), Labels.of(tagKeys, tagValues), null, createdTimestampMillis))), descriptor(conventionName(id), MetricType.COUNTER, metadata, tagKeys)); @@ -437,14 +428,14 @@ protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable mea return new DefaultMeter(id, type, measurements); } - private MicrometerCollector.Descriptor customMeterDescriptor( - Meter.Id id, String conventionName, Statistic statistic, Collection labelNames) { + private MicrometerCollector.Descriptor customMeterDescriptor(Meter.Id id, String conventionName, + Statistic statistic, Collection labelNames) { CustomMeterMetric metric = customMeterMetric(id, conventionName, statistic); return descriptor(metric.name, metric.metricType, metric.metadata, labelNames); } - private MicrometerCollector.Family customMeterFamily( - Meter.Id id, String conventionName, Statistic statistic, Labels labels, double value) { + private MicrometerCollector.Family customMeterFamily(Meter.Id id, String conventionName, Statistic statistic, + Labels labels, double value) { CustomMeterMetric metric = customMeterMetric(id, conventionName, statistic); if (metric.metricType == MetricType.COUNTER) { return customCounterFamily(metric, labels, value); @@ -479,20 +470,18 @@ private CustomMeterMetric customMeterMetric(Meter.Id id, String conventionName, } } - private MicrometerCollector.Family customCounterFamily( - CustomMeterMetric metric, Labels labels, double value) { + private MicrometerCollector.Family customCounterFamily(CustomMeterMetric metric, + Labels labels, double value) { long createdTimestampMillis = clock.wallTime(); return new MicrometerCollector.Family<>(metric.name, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - metric.metadata, + family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), metric.metadata, new CounterDataPointSnapshot(value, labels, null, createdTimestampMillis)); } - private MicrometerCollector.Family customGaugeFamily( - CustomMeterMetric metric, Labels labels, double value) { + private MicrometerCollector.Family customGaugeFamily(CustomMeterMetric metric, + Labels labels, double value) { return new MicrometerCollector.Family<>(metric.name, - family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), - metric.metadata, + family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), metric.metadata, new GaugeDataPointSnapshot(value, labels, null)); } @@ -509,6 +498,7 @@ private CustomMeterMetric(String name, MetricType metricType, MetricMetadata met this.metricType = metricType; this.metadata = metadata; } + } @Override @@ -530,8 +520,8 @@ private void addDistributionStatisticSamples(Meter.Id id, MicrometerCollector co List tagKeys = tagKeys(id); MetricMetadata primaryMetadata = getMetadata(conventionName(id), id.getDescription()); MetricMetadata maxMetadata = getMetadata(conventionName(id) + "_max", id.getDescription()); - MetricType primaryType = histogramSupport.takeSnapshot().histogramCounts().length == 0 - ? MetricType.SUMMARY : MetricType.HISTOGRAM; + MetricType primaryType = histogramSupport.takeSnapshot().histogramCounts().length == 0 ? MetricType.SUMMARY + : MetricType.HISTOGRAM; collector.add(id, (conventionName) -> { Stream.Builder> families = Stream.builder(); @@ -553,9 +543,9 @@ private void addDistributionStatisticSamples(Meter.Id id, MicrometerCollector co Exemplars exemplars = createExemplarsWithScaledValues(exemplarsSupplier.get()); families.add(new MicrometerCollector.Family<>(conventionName, - family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), - primaryMetadata, new SummaryDataPointSnapshot(count, sum, - quantiles, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); + family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), primaryMetadata, + new SummaryDataPointSnapshot(count, sum, quantiles, Labels.of(tagKeys, tagValues), exemplars, + createdTimestampMillis))); } else { List buckets = new ArrayList<>(); @@ -584,9 +574,8 @@ primaryMetadata, new SummaryDataPointSnapshot(count, sum, families.add(new MicrometerCollector.Family<>(conventionName, family -> new io.prometheus.metrics.model.snapshots.HistogramSnapshot(forLongTaskTimer, family.metadata, family.dataPointSnapshots), - primaryMetadata, - new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), sum, - Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); + primaryMetadata, new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), + sum, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); // TODO: Add support back for VictoriaMetrics // Previously we had low-level control so a histogram was just @@ -599,13 +588,12 @@ primaryMetadata, new SummaryDataPointSnapshot(count, sum, } families.add(new MicrometerCollector.Family<>(conventionName + "_max", - family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), - maxMetadata, new GaugeDataPointSnapshot( - histogramSnapshot.max(getBaseTimeUnit()), Labels.of(tagKeys, tagValues), null))); + family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), maxMetadata, + new GaugeDataPointSnapshot(histogramSnapshot.max(getBaseTimeUnit()), Labels.of(tagKeys, tagValues), + null))); return families.build(); - }, - descriptor(conventionName(id), primaryType, primaryMetadata, tagKeys), + }, descriptor(conventionName(id), primaryType, primaryMetadata, tagKeys), descriptor(conventionName(id) + "_max", MetricType.GAUGE, maxMetadata, tagKeys)); } @@ -613,8 +601,8 @@ private String conventionName(Meter.Id id) { return getConventionName(id); } - private MicrometerCollector.Descriptor descriptor( - String prometheusName, MetricType metricType, MetricMetadata metadata, Collection labelNames) { + private MicrometerCollector.Descriptor descriptor(String prometheusName, MetricType metricType, + MetricMetadata metadata, Collection labelNames) { return new MicrometerCollector.Descriptor(prometheusName, metricType, metadata, labelNames); } @@ -657,8 +645,8 @@ private MetricMetadata getCounterMetadata(String name, @Nullable String descript private MetricMetadata getCounterMetadata(String name, String originalName, @Nullable String description) { String help = prometheusConfig.descriptions() && description != null ? description : " "; - String baseName = normalizeBaseName(name, originalName, ".bucket", "_bucket", ".created", "_created", - ".info", "_info"); + String baseName = normalizeBaseName(name, originalName, ".bucket", "_bucket", ".created", "_created", ".info", + "_info"); if (baseName.equals(name)) { baseName = stripSuffix(name, "_total"); } From bda9034fc8dada0a789c4dbf9d11cf3eb94c673d Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 6 May 2026 09:28:10 +0000 Subject: [PATCH 08/11] test: cover function timer registration collisions Signed-off-by: Gregor Zeitlinger --- .../PrometheusMeterRegistryTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistryTest.java b/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistryTest.java index 9148961be5..e2d18d523a 100644 --- a/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistryTest.java +++ b/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistryTest.java @@ -90,6 +90,19 @@ void differentMicrometerNameSamePrometheusNameFailsToRegister() { assertThat(failed.get()).isTrue(); } + @Test + void functionTimerCollisionUsesPrometheusRegistrationMetadata() { + registry.throwExceptionOnRegistrationFailure(); + + registry.more().timer("test", Tags.empty(), this, o -> 1, o -> 2, TimeUnit.SECONDS); + + assertThatThrownBy( + () -> Gauge.builder("test.seconds", new AtomicInteger(42), AtomicInteger::get).register(registry)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("same Prometheus name (test_seconds)") + .hasMessageContaining("would fail with an exception on scrape"); + } + @Test @Disabled("We don't detect this situation yet; scrape will fail") void differentTypesThatProduceSamePrometheusMetricFamilyFailsToRegister() { From 99cb4d24baef174097702268961b75adc3856331 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Wed, 13 May 2026 12:22:21 +0000 Subject: [PATCH 09/11] feat: use typed metric family descriptors for prometheus registration Signed-off-by: Gregor Zeitlinger --- .../MicrometerCollector.java | 85 ++++---- .../PrometheusMeterRegistry.java | 203 ++++++++++-------- .../MicrometerCollectorTest.java | 90 +++++--- 3 files changed, 213 insertions(+), 165 deletions(-) diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java index cf59b73ca9..7657bcad9c 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java @@ -16,15 +16,24 @@ package io.micrometer.prometheusmetrics; import io.micrometer.core.instrument.Meter; -import io.prometheus.metrics.model.registry.MultiCollector; import io.prometheus.metrics.model.registry.MetricType; +import io.prometheus.metrics.model.registry.MultiCollector; import io.prometheus.metrics.model.snapshots.DataPointSnapshot; +import io.prometheus.metrics.model.snapshots.MetricFamilyDescriptor; import io.prometheus.metrics.model.snapshots.MetricMetadata; import io.prometheus.metrics.model.snapshots.MetricSnapshot; import io.prometheus.metrics.model.snapshots.MetricSnapshots; import org.jspecify.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.stream.Stream; @@ -42,7 +51,7 @@ class MicrometerCollector implements MultiCollector { private final Map children = new ConcurrentHashMap<>(); - private final Map> descriptors = new ConcurrentHashMap<>(); + private final Map> registeredFamilies = new ConcurrentHashMap<>(); private final String conventionName; @@ -56,14 +65,14 @@ class MicrometerCollector implements MultiCollector { this.originalMeterId = id; } - public void add(Meter.Id id, Child child, Descriptor... descriptors) { + public void add(Meter.Id id, Child child, RegisteredFamily... registeredFamilies) { children.put(id, child); - this.descriptors.put(id, Arrays.asList(descriptors)); + this.registeredFamilies.put(id, Arrays.asList(registeredFamilies)); } public void remove(Meter.Id id) { children.remove(id); - descriptors.remove(id); + registeredFamilies.remove(id); } public boolean isEmpty() { @@ -80,14 +89,17 @@ Meter.Id getOriginalId() { @Override public List getPrometheusNames() { - return registrationDescriptors().stream().map(Descriptor::getPrometheusName).distinct().collect(toList()); + return registrationFamilies().stream() + .map(RegisteredFamily::getPrometheusName) + .distinct() + .collect(toList()); } @Override public @Nullable MetricType getMetricType(String prometheusName) { - for (Descriptor descriptor : registrationDescriptors()) { - if (descriptor.getPrometheusName().equals(prometheusName)) { - return descriptor.getMetricType(); + for (RegisteredFamily family : registrationFamilies()) { + if (family.getPrometheusName().equals(prometheusName)) { + return family.getMetricType(); } } return null; @@ -96,9 +108,9 @@ public List getPrometheusNames() { @Override public @Nullable Set getLabelNames(String prometheusName) { Set names = new HashSet<>(); - for (Descriptor descriptor : registrationDescriptors()) { - if (descriptor.getPrometheusName().equals(prometheusName)) { - names.addAll(descriptor.getLabelNames()); + for (RegisteredFamily family : registrationFamilies()) { + if (family.getPrometheusName().equals(prometheusName)) { + names.addAll(family.getLabelNames()); } } return names.isEmpty() ? null : names; @@ -106,9 +118,9 @@ public List getPrometheusNames() { @Override public @Nullable MetricMetadata getMetadata(String prometheusName) { - for (Descriptor descriptor : registrationDescriptors()) { - if (descriptor.getPrometheusName().equals(prometheusName)) { - return descriptor.getMetadata(); + for (RegisteredFamily family : registrationFamilies()) { + if (family.getPrometheusName().equals(prometheusName)) { + return family.getMetadata(); } } return null; @@ -133,8 +145,8 @@ public MetricSnapshots collect() { return new MetricSnapshots(metricSnapshots); } - private List registrationDescriptors() { - return descriptors.values().stream().flatMap(Collection::stream).collect(toList()); + private List registrationFamilies() { + return registeredFamilies.values().stream().flatMap(Collection::stream).collect(toList()); } interface Child { @@ -143,57 +155,42 @@ interface Child { } - static class Descriptor { - - private final String prometheusName; - - private final MetricType metricType; - - private final MetricMetadata metadata; + static final class RegisteredFamily { - private final Set labelNames; + private final MetricFamilyDescriptor descriptor; - Descriptor(String prometheusName, MetricType metricType, MetricMetadata metadata, - Collection labelNames) { - this.prometheusName = prometheusName; - this.metricType = metricType; - this.metadata = metadata; - this.labelNames = new LinkedHashSet<>(labelNames); + RegisteredFamily(MetricFamilyDescriptor descriptor) { + this.descriptor = descriptor; } String getPrometheusName() { - return prometheusName; + return descriptor.getPrometheusName(); } MetricType getMetricType() { - return metricType; - } - - MetricMetadata getMetadata() { - return metadata; + return descriptor.getType(); } Set getLabelNames() { - return labelNames; + return descriptor.getLabelNames(); } + MetricMetadata getMetadata() { + return descriptor.getMetadata(); + } } static class Family { final String conventionName; - final MetricMetadata metadata; - final List dataPointSnapshots = new ArrayList<>(); final Function, MetricSnapshot> metricSnapshotFactory; - Family(String conventionName, Function, MetricSnapshot> metricSnapshotFactory, - MetricMetadata metadata, T... dataPointSnapshots) { + Family(String conventionName, Function, MetricSnapshot> metricSnapshotFactory, T... dataPointSnapshots) { this.conventionName = conventionName; this.metricSnapshotFactory = metricSnapshotFactory; - this.metadata = metadata; Collections.addAll(this.dataPointSnapshots, dataPointSnapshots); } diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java index d24e9e15c0..5dc1d10ec9 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java @@ -219,13 +219,13 @@ public Counter newCounter(Meter.Id id) { applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); - MetricMetadata metadata = getCounterMetadata(conventionName(id), id.getName(), id.getDescription()); + String familyName = counterMetricName(conventionName(id), id.getName()); collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), metadata, + (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, + family -> counterSnapshot(family, family.getConventionName(), helpText(id.getDescription())), new CounterDataPointSnapshot(counter.count(), Labels.of(tagKeys, tagValues), counter.exemplar(), createdTimestampMillis))), - descriptor(conventionName(id), MetricType.COUNTER, metadata, tagKeys)); + registeredFamily(MetricType.COUNTER, familyName, tagKeys, id.getDescription())); }); return counter; } @@ -239,8 +239,6 @@ public DistributionSummary newDistributionSummary(Meter.Id id, applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); - MetricMetadata summaryMetadata = getMetadata(conventionName(id), id.getDescription()); - MetricMetadata maxMetadata = getMetadata(conventionName(id) + "_max", id.getDescription()); MetricType primaryType = summary.histogramCounts().length == 0 ? MetricType.SUMMARY : MetricType.HISTOGRAM; collector.add(id, (conventionName) -> { Stream.Builder> families = Stream.builder(); @@ -262,7 +260,7 @@ public DistributionSummary newDistributionSummary(Meter.Id id, Exemplars exemplars = summary.exemplars(); families.add(new MicrometerCollector.Family<>(conventionName, - family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), summaryMetadata, + family -> summarySnapshot(family, family.getConventionName(), helpText(id.getDescription())), new SummaryDataPointSnapshot(count, sum, quantiles, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); } @@ -291,10 +289,10 @@ public DistributionSummary newDistributionSummary(Meter.Id id, Exemplars exemplars = summary.exemplars(); families.add(new MicrometerCollector.Family<>(conventionName, - family -> new io.prometheus.metrics.model.snapshots.HistogramSnapshot(family.metadata, - family.dataPointSnapshots), - summaryMetadata, new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), - sum, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); + family -> histogramSnapshot(family, family.getConventionName(), helpText(id.getDescription()), + false), + new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), sum, + Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); // TODO: Add support back for VictoriaMetrics // Previously we had low-level control so a histogram was just @@ -307,12 +305,12 @@ summaryMetadata, new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(bucke } families.add(new MicrometerCollector.Family<>(conventionName + "_max", - family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), maxMetadata, + family -> gaugeSnapshot(family, family.getConventionName(), helpText(id.getDescription())), new GaugeDataPointSnapshot(summary.max(), Labels.of(tagKeys, tagValues), null))); return families.build(); - }, descriptor(conventionName(id), primaryType, summaryMetadata, tagKeys), - descriptor(conventionName(id) + "_max", MetricType.GAUGE, maxMetadata, tagKeys)); + }, registeredFamily(primaryType, conventionName(id), tagKeys, id.getDescription()), + registeredFamily(MetricType.GAUGE, conventionName(id) + "_max", tagKeys, id.getDescription())); }); return summary; @@ -336,20 +334,20 @@ protected io.micrometer.core.instrument.Gauge newGauge(Meter.Id id, @Nullabl List tagValues = tagValues(id); List tagKeys = tagKeys(id); if (id.getName().endsWith(".info")) { - MetricMetadata infoMetadata = getInfoMetadata(conventionName(id), id.getName(), id.getDescription()); + String familyName = infoMetricName(conventionName(id), id.getName()); collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new InfoSnapshot(family.metadata, family.dataPointSnapshots), infoMetadata, + (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, + family -> infoSnapshot(family, family.getConventionName(), helpText(id.getDescription())), new InfoDataPointSnapshot(Labels.of(tagKeys, tagValues)))), - descriptor(conventionName(id), MetricType.INFO, infoMetadata, tagKeys)); + registeredFamily(MetricType.INFO, familyName, tagKeys, id.getDescription())); } else { - MetricMetadata metadata = getMetadata(conventionName(id), id.getDescription()); + String familyName = gaugeMetricName(conventionName(id), id.getName()); collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), metadata, + (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, + family -> gaugeSnapshot(family, family.getConventionName(), helpText(id.getDescription())), new GaugeDataPointSnapshot(gauge.value(), Labels.of(tagKeys, tagValues), null))), - descriptor(conventionName(id), MetricType.GAUGE, metadata, tagKeys)); + registeredFamily(MetricType.GAUGE, familyName, tagKeys, id.getDescription())); } }); return gauge; @@ -372,13 +370,12 @@ protected FunctionTimer newFunctionTimer(Meter.Id id, T obj, ToLongFunction< applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); - MetricMetadata metadata = getMetadata(conventionName(id), id.getDescription()); collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), metadata, + family -> summarySnapshot(family, family.getConventionName(), helpText(id.getDescription())), new SummaryDataPointSnapshot((long) ft.count(), ft.totalTime(getBaseTimeUnit()), Quantiles.EMPTY, Labels.of(tagKeys, tagValues), null, createdTimestampMillis))), - descriptor(conventionName(id), MetricType.SUMMARY, metadata, tagKeys)); + registeredFamily(MetricType.SUMMARY, conventionName(id), tagKeys, id.getDescription())); }); return ft; } @@ -390,13 +387,13 @@ protected FunctionCounter newFunctionCounter(Meter.Id id, T obj, ToDoubleFun applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); - MetricMetadata metadata = getCounterMetadata(conventionName(id), id.getName(), id.getDescription()); + String familyName = counterMetricName(conventionName(id), id.getName()); collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), metadata, + (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, + family -> counterSnapshot(family, family.getConventionName(), helpText(id.getDescription())), new CounterDataPointSnapshot(fc.count(), Labels.of(tagKeys, tagValues), null, createdTimestampMillis))), - descriptor(conventionName(id), MetricType.COUNTER, metadata, tagKeys)); + registeredFamily(MetricType.COUNTER, familyName, tagKeys, id.getDescription())); }); return fc; } @@ -408,7 +405,7 @@ protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable mea List tagKeys = tagKeys(id); List statKeys = new ArrayList<>(tagKeys); statKeys.add("statistic"); - List registrationDescriptors = new ArrayList<>(); + List registrationDescriptors = new ArrayList<>(); String name = conventionName(id); for (Measurement measurement : measurements) { registrationDescriptors.add(customMeterDescriptor(id, name, measurement.getStatistic(), statKeys)); @@ -422,66 +419,60 @@ protected Meter newMeter(Meter.Id id, Meter.Type type, Iterable mea Labels.of(statKeys, statValues), measurement.getValue())); } return families.build(); - }, registrationDescriptors.toArray(new MicrometerCollector.Descriptor[0])); + }, registrationDescriptors.toArray(new MicrometerCollector.RegisteredFamily[0])); }); return new DefaultMeter(id, type, measurements); } - private MicrometerCollector.Descriptor customMeterDescriptor(Meter.Id id, String conventionName, + private MicrometerCollector.RegisteredFamily customMeterDescriptor(Meter.Id id, String conventionName, Statistic statistic, Collection labelNames) { - CustomMeterMetric metric = customMeterMetric(id, conventionName, statistic); - return descriptor(metric.name, metric.metricType, metric.metadata, labelNames); + CustomMeterMetric metric = customMeterMetric(conventionName, statistic); + return registeredFamily(metric.metricType, metric.name, labelNames, id.getDescription()); } private MicrometerCollector.Family customMeterFamily(Meter.Id id, String conventionName, Statistic statistic, Labels labels, double value) { - CustomMeterMetric metric = customMeterMetric(id, conventionName, statistic); + CustomMeterMetric metric = customMeterMetric(conventionName, statistic); if (metric.metricType == MetricType.COUNTER) { - return customCounterFamily(metric, labels, value); + return customCounterFamily(id, metric, labels, value); } - return customGaugeFamily(metric, labels, value); + return customGaugeFamily(id, metric, labels, value); } - private CustomMeterMetric customMeterMetric(Meter.Id id, String conventionName, Statistic statistic) { + private CustomMeterMetric customMeterMetric(String conventionName, Statistic statistic) { switch (statistic) { case TOTAL: case TOTAL_TIME: - return new CustomMeterMetric(conventionName + "_sum", MetricType.COUNTER, - getCounterMetadata(conventionName + "_sum", id.getDescription())); + return new CustomMeterMetric(conventionName + "_sum", MetricType.COUNTER); case COUNT: - return new CustomMeterMetric(conventionName, MetricType.COUNTER, - getCounterMetadata(conventionName, id.getDescription())); + return new CustomMeterMetric(conventionName, MetricType.COUNTER); case MAX: - return new CustomMeterMetric(conventionName + "_max", MetricType.GAUGE, - getMetadata(conventionName + "_max", id.getDescription())); + return new CustomMeterMetric(conventionName + "_max", MetricType.GAUGE); case VALUE: case UNKNOWN: - return new CustomMeterMetric(conventionName + "_value", MetricType.GAUGE, - getMetadata(conventionName + "_value", id.getDescription())); + return new CustomMeterMetric(conventionName + "_value", MetricType.GAUGE); case ACTIVE_TASKS: - return new CustomMeterMetric(conventionName + "_active_count", MetricType.GAUGE, - getMetadata(conventionName + "_active_count", id.getDescription())); + return new CustomMeterMetric(conventionName + "_active_count", MetricType.GAUGE); case DURATION: - return new CustomMeterMetric(conventionName + "_duration_sum", MetricType.GAUGE, - getMetadata(conventionName + "_duration_sum", id.getDescription())); + return new CustomMeterMetric(conventionName + "_duration_sum", MetricType.GAUGE); default: throw new IllegalArgumentException("Unsupported meter statistic: " + statistic); } } - private MicrometerCollector.Family customCounterFamily(CustomMeterMetric metric, - Labels labels, double value) { + private MicrometerCollector.Family customCounterFamily(Meter.Id id, + CustomMeterMetric metric, Labels labels, double value) { long createdTimestampMillis = clock.wallTime(); return new MicrometerCollector.Family<>(metric.name, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), metric.metadata, + family -> counterSnapshot(family, metric.name, helpText(id.getDescription())), new CounterDataPointSnapshot(value, labels, null, createdTimestampMillis)); } - private MicrometerCollector.Family customGaugeFamily(CustomMeterMetric metric, - Labels labels, double value) { + private MicrometerCollector.Family customGaugeFamily(Meter.Id id, + CustomMeterMetric metric, Labels labels, double value) { return new MicrometerCollector.Family<>(metric.name, - family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), metric.metadata, + family -> gaugeSnapshot(family, metric.name, helpText(id.getDescription())), new GaugeDataPointSnapshot(value, labels, null)); } @@ -491,12 +482,9 @@ private static class CustomMeterMetric { private final MetricType metricType; - private final MetricMetadata metadata; - - private CustomMeterMetric(String name, MetricType metricType, MetricMetadata metadata) { + private CustomMeterMetric(String name, MetricType metricType) { this.name = name; this.metricType = metricType; - this.metadata = metadata; } } @@ -518,8 +506,6 @@ private void addDistributionStatisticSamples(Meter.Id id, MicrometerCollector co boolean forLongTaskTimer) { long createdTimestampMillis = clock.wallTime(); List tagKeys = tagKeys(id); - MetricMetadata primaryMetadata = getMetadata(conventionName(id), id.getDescription()); - MetricMetadata maxMetadata = getMetadata(conventionName(id) + "_max", id.getDescription()); MetricType primaryType = histogramSupport.takeSnapshot().histogramCounts().length == 0 ? MetricType.SUMMARY : MetricType.HISTOGRAM; collector.add(id, (conventionName) -> { @@ -543,7 +529,7 @@ private void addDistributionStatisticSamples(Meter.Id id, MicrometerCollector co Exemplars exemplars = createExemplarsWithScaledValues(exemplarsSupplier.get()); families.add(new MicrometerCollector.Family<>(conventionName, - family -> new SummarySnapshot(family.metadata, family.dataPointSnapshots), primaryMetadata, + family -> summarySnapshot(family, family.getConventionName(), helpText(id.getDescription())), new SummaryDataPointSnapshot(count, sum, quantiles, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); } @@ -572,10 +558,10 @@ private void addDistributionStatisticSamples(Meter.Id id, MicrometerCollector co Exemplars exemplars = createExemplarsWithScaledValues(exemplarsSupplier.get()); families.add(new MicrometerCollector.Family<>(conventionName, - family -> new io.prometheus.metrics.model.snapshots.HistogramSnapshot(forLongTaskTimer, - family.metadata, family.dataPointSnapshots), - primaryMetadata, new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), - sum, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); + family -> histogramSnapshot(family, family.getConventionName(), helpText(id.getDescription()), + forLongTaskTimer), + new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), sum, + Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); // TODO: Add support back for VictoriaMetrics // Previously we had low-level control so a histogram was just @@ -588,22 +574,29 @@ primaryMetadata, new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(bucke } families.add(new MicrometerCollector.Family<>(conventionName + "_max", - family -> new GaugeSnapshot(family.metadata, family.dataPointSnapshots), maxMetadata, + family -> gaugeSnapshot(family, family.getConventionName(), helpText(id.getDescription())), new GaugeDataPointSnapshot(histogramSnapshot.max(getBaseTimeUnit()), Labels.of(tagKeys, tagValues), null))); return families.build(); - }, descriptor(conventionName(id), primaryType, primaryMetadata, tagKeys), - descriptor(conventionName(id) + "_max", MetricType.GAUGE, maxMetadata, tagKeys)); + }, registeredFamily(primaryType, conventionName(id), tagKeys, id.getDescription()), + registeredFamily(MetricType.GAUGE, conventionName(id) + "_max", tagKeys, id.getDescription())); } private String conventionName(Meter.Id id) { return getConventionName(id); } - private MicrometerCollector.Descriptor descriptor(String prometheusName, MetricType metricType, - MetricMetadata metadata, Collection labelNames) { - return new MicrometerCollector.Descriptor(prometheusName, metricType, metadata, labelNames); + private MicrometerCollector.RegisteredFamily registeredFamily(MetricType metricType, String name, + Collection labelNames, @Nullable String description) { + MetricFamilyDescriptor.Builder builder = MetricFamilyDescriptor.of(metricType, name) + .help(helpText(description)) + .labelNames(labelNames); + return new MicrometerCollector.RegisteredFamily(builder.build()); + } + + private String helpText(@Nullable String description) { + return prometheusConfig.descriptions() && description != null ? description : " "; } private Exemplars createExemplarsWithScaledValues(Exemplars exemplars) { @@ -632,30 +625,58 @@ private void onMeterRemoved(Meter meter) { } } - private MetricMetadata getMetadata(String name, @Nullable String description) { - String help = prometheusConfig.descriptions() && description != null ? description : " "; - // Unit is intentionally not set, see: - // https://github.com/OpenObservability/OpenMetrics/blob/1386544931307dff279688f332890c31b6c5de36/specification/OpenMetrics.md#unit - return new MetricMetadata(name, help, null); + private CounterSnapshot counterSnapshot(MicrometerCollector.Family family, + String name, String help) { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(name).help(help); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); } - private MetricMetadata getCounterMetadata(String name, @Nullable String description) { - return getCounterMetadata(name, name, description); + private GaugeSnapshot gaugeSnapshot(MicrometerCollector.Family family, String name, + String help) { + GaugeSnapshot.Builder builder = GaugeSnapshot.builder().name(name).help(help); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); } - private MetricMetadata getCounterMetadata(String name, String originalName, @Nullable String description) { - String help = prometheusConfig.descriptions() && description != null ? description : " "; - String baseName = normalizeBaseName(name, originalName, ".bucket", "_bucket", ".created", "_created", ".info", - "_info"); - if (baseName.equals(name)) { - baseName = stripSuffix(name, "_total"); - } - return new MetricMetadata(baseName, help, null); + private InfoSnapshot infoSnapshot(MicrometerCollector.Family family, String name, + String help) { + InfoSnapshot.Builder builder = InfoSnapshot.builder().name(name).help(help); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + } + + private SummarySnapshot summarySnapshot(MicrometerCollector.Family family, String name, + String help) { + SummarySnapshot.Builder builder = SummarySnapshot.builder().name(name).help(help); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + } + + private io.prometheus.metrics.model.snapshots.HistogramSnapshot histogramSnapshot( + MicrometerCollector.Family family, String name, String help, + boolean gaugeHistogram) { + io.prometheus.metrics.model.snapshots.HistogramSnapshot.Builder builder = io.prometheus.metrics.model.snapshots.HistogramSnapshot + .builder() + .name(name) + .help(help) + .gaugeHistogram(gaugeHistogram); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + } + + private String counterMetricName(String prometheusName, String originalName) { + return normalizeBaseName(prometheusName, originalName, ".bucket", "_bucket", ".created", "_created", + ".info", "_info", ".total", "_total"); + } + + private String infoMetricName(String prometheusName, String originalName) { + return normalizeBaseName(prometheusName, originalName, ".info", "_info"); } - private MetricMetadata getInfoMetadata(String name, String originalName, @Nullable String description) { - String help = prometheusConfig.descriptions() && description != null ? description : " "; - return new MetricMetadata(normalizeBaseName(name, originalName, ".info", "_info"), help, null); + private String gaugeMetricName(String prometheusName, String originalName) { + return normalizeBaseName(prometheusName, originalName, ".bucket", "_bucket", ".created", "_created", + ".total", "_total"); } private static String normalizeBaseName(String name, String originalName, String... suffixMappings) { diff --git a/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java b/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java index 84b51ddd88..ca279d0d42 100644 --- a/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java +++ b/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java @@ -24,10 +24,9 @@ import io.prometheus.metrics.model.registry.MetricType; import io.prometheus.metrics.model.snapshots.CounterSnapshot; import io.prometheus.metrics.model.snapshots.Labels; -import io.prometheus.metrics.model.snapshots.MetricMetadata; +import io.prometheus.metrics.model.snapshots.MetricFamilyDescriptor; import org.junit.jupiter.api.Test; -import java.util.Objects; import java.util.stream.Stream; import static java.util.Arrays.asList; @@ -50,8 +49,11 @@ void manyTags() { collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - new MetricMetadata(conventionName), sample))); + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); } // Threw StackOverflowException because of too many nested streams originally @@ -72,12 +74,18 @@ void sameValuesDifferentOrder() { collector.add(sampleId, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - new MetricMetadata(conventionName), sample))); + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); collector.add(sample2Id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - new MetricMetadata(conventionName), sample2))); + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample2))); assertThat(collector.collect().get(0).getDataPoints()).hasSize(2); } @@ -96,12 +104,18 @@ void sameMetricDifferentTagKeysCounter() { collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - new MetricMetadata(conventionName), sample))); + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); collector.add(id2, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - new MetricMetadata(conventionName), sample2))); + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample2))); assertThat(collector.collect().get(0).getDataPoints()).hasSize(2); } @@ -120,12 +134,18 @@ void oneSampleHasSubsetOfTagKeysOfAnotherSample() { collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - new MetricMetadata(conventionName), sample))); + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); collector.add(id2, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - new MetricMetadata(conventionName), sample2))); + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample2))); assertThat(collector.collect().get(0).getDataPoints()).hasSize(2); } @@ -144,12 +164,18 @@ void sameMetricNameWithNoTagsAndAListOfTags() { collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - new MetricMetadata(conventionName), sample))); + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); collector.add(id2, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), - new MetricMetadata(conventionName), sample2))); + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample2))); assertThat(collector.collect().get(0).getDataPoints()).hasSize(2); } @@ -161,17 +187,21 @@ void registrationDescriptorUsesPrometheusFamilyName() { CounterSnapshot.CounterDataPointSnapshot sample = new CounterSnapshot.CounterDataPointSnapshot(1.0, Labels.of("k", "v"), null, 0); - MetricMetadata metadata = new MetricMetadata("my_counter", "help"); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>("my_counter_total", - family -> new CounterSnapshot(family.metadata, family.dataPointSnapshots), metadata, sample)), - new MicrometerCollector.Descriptor("my_counter_total", MetricType.COUNTER, metadata, asList("k"))); - - assertThat(collector.getPrometheusNames()).containsExactly("my_counter_total"); - assertThat(collector.getMetricType("my_counter_total")).isEqualTo(MetricType.COUNTER); - assertThat(collector.getLabelNames("my_counter_total")).containsExactly("k"); - assertThat(Objects.requireNonNull(collector.getMetadata("my_counter_total")).getName()).isEqualTo("my_counter"); + (conventionName) -> Stream.of(new MicrometerCollector.Family<>("my_counter", + family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name("my_counter"); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample)), + new MicrometerCollector.RegisteredFamily( + MetricFamilyDescriptor.counter("my_counter").help("help").labelNames(asList("k")).build())); + + assertThat(collector.getPrometheusNames()).containsExactly("my_counter"); + assertThat(collector.getMetricType("my_counter")).isEqualTo(MetricType.COUNTER); + assertThat(collector.getLabelNames("my_counter")).containsExactly("k"); + assertThat(collector.getMetadata("my_counter")).isNotNull(); + assertThat(collector.getMetadata("my_counter").getName()).isEqualTo("my_counter"); } } From 84092837e94d16de4d3bf95a4644498ce2ef49fd Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 4 Jun 2026 14:26:45 +0000 Subject: [PATCH 10/11] build: bump prometheus client_java to 1.7.0 Signed-off-by: Gregor Zeitlinger --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f384954afe..a87be7796d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -61,7 +61,7 @@ newrelic-api = "5.14.0" # Kotlin 1.7 sample will fail from OkHttp 4.12.0 due to okio dependency being a Kotlin 1.9 module okhttp = "4.12.0" postgre = "42.7.11" -prometheus = "1.5.1" +prometheus = "1.7.0" prometheusSimpleClient = "0.16.0" reactor = "2022.0.22" rest-assured = "5.5.7" From 09f32142f06b11a88afe41eab50daaf6c8d08efb Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 4 Jun 2026 14:34:52 +0000 Subject: [PATCH 11/11] style: apply formatter to prometheus registry Signed-off-by: Gregor Zeitlinger --- .../MicrometerCollector.java | 9 +- .../PrometheusMeterRegistry.java | 64 +++++---- .../MicrometerCollectorTest.java | 121 ++++++++---------- 3 files changed, 85 insertions(+), 109 deletions(-) diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java index 7657bcad9c..dc3762defd 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/MicrometerCollector.java @@ -89,10 +89,7 @@ Meter.Id getOriginalId() { @Override public List getPrometheusNames() { - return registrationFamilies().stream() - .map(RegisteredFamily::getPrometheusName) - .distinct() - .collect(toList()); + return registrationFamilies().stream().map(RegisteredFamily::getPrometheusName).distinct().collect(toList()); } @Override @@ -178,6 +175,7 @@ Set getLabelNames() { MetricMetadata getMetadata() { return descriptor.getMetadata(); } + } static class Family { @@ -188,7 +186,8 @@ static class Family { final Function, MetricSnapshot> metricSnapshotFactory; - Family(String conventionName, Function, MetricSnapshot> metricSnapshotFactory, T... dataPointSnapshots) { + Family(String conventionName, Function, MetricSnapshot> metricSnapshotFactory, + T... dataPointSnapshots) { this.conventionName = conventionName; this.metricSnapshotFactory = metricSnapshotFactory; Collections.addAll(this.dataPointSnapshots, dataPointSnapshots); diff --git a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java index 5dc1d10ec9..8799ce4a6d 100644 --- a/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java +++ b/implementations/micrometer-registry-prometheus/src/main/java/io/micrometer/prometheusmetrics/PrometheusMeterRegistry.java @@ -220,11 +220,10 @@ public Counter newCounter(Meter.Id id) { List tagValues = tagValues(id); List tagKeys = tagKeys(id); String familyName = counterMetricName(conventionName(id), id.getName()); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, - family -> counterSnapshot(family, family.getConventionName(), helpText(id.getDescription())), - new CounterDataPointSnapshot(counter.count(), Labels.of(tagKeys, tagValues), - counter.exemplar(), createdTimestampMillis))), + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, + family -> counterSnapshot(family, family.getConventionName(), helpText(id.getDescription())), + new CounterDataPointSnapshot(counter.count(), Labels.of(tagKeys, tagValues), counter.exemplar(), + createdTimestampMillis))), registeredFamily(MetricType.COUNTER, familyName, tagKeys, id.getDescription())); }); return counter; @@ -260,7 +259,8 @@ public DistributionSummary newDistributionSummary(Meter.Id id, Exemplars exemplars = summary.exemplars(); families.add(new MicrometerCollector.Family<>(conventionName, - family -> summarySnapshot(family, family.getConventionName(), helpText(id.getDescription())), + family -> summarySnapshot(family, family.getConventionName(), + helpText(id.getDescription())), new SummaryDataPointSnapshot(count, sum, quantiles, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); } @@ -289,8 +289,8 @@ public DistributionSummary newDistributionSummary(Meter.Id id, Exemplars exemplars = summary.exemplars(); families.add(new MicrometerCollector.Family<>(conventionName, - family -> histogramSnapshot(family, family.getConventionName(), helpText(id.getDescription()), - false), + family -> histogramSnapshot(family, family.getConventionName(), + helpText(id.getDescription()), false), new HistogramDataPointSnapshot(ClassicHistogramBuckets.of(buckets, counts), sum, Labels.of(tagKeys, tagValues), exemplars, createdTimestampMillis))); @@ -335,18 +335,16 @@ protected io.micrometer.core.instrument.Gauge newGauge(Meter.Id id, @Nullabl List tagKeys = tagKeys(id); if (id.getName().endsWith(".info")) { String familyName = infoMetricName(conventionName(id), id.getName()); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, - family -> infoSnapshot(family, family.getConventionName(), helpText(id.getDescription())), - new InfoDataPointSnapshot(Labels.of(tagKeys, tagValues)))), + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, + family -> infoSnapshot(family, family.getConventionName(), helpText(id.getDescription())), + new InfoDataPointSnapshot(Labels.of(tagKeys, tagValues)))), registeredFamily(MetricType.INFO, familyName, tagKeys, id.getDescription())); } else { String familyName = gaugeMetricName(conventionName(id), id.getName()); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, - family -> gaugeSnapshot(family, family.getConventionName(), helpText(id.getDescription())), - new GaugeDataPointSnapshot(gauge.value(), Labels.of(tagKeys, tagValues), null))), + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, + family -> gaugeSnapshot(family, family.getConventionName(), helpText(id.getDescription())), + new GaugeDataPointSnapshot(gauge.value(), Labels.of(tagKeys, tagValues), null))), registeredFamily(MetricType.GAUGE, familyName, tagKeys, id.getDescription())); } }); @@ -370,11 +368,10 @@ protected FunctionTimer newFunctionTimer(Meter.Id id, T obj, ToLongFunction< applyToCollector(id, (collector) -> { List tagValues = tagValues(id); List tagKeys = tagKeys(id); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> summarySnapshot(family, family.getConventionName(), helpText(id.getDescription())), - new SummaryDataPointSnapshot((long) ft.count(), ft.totalTime(getBaseTimeUnit()), - Quantiles.EMPTY, Labels.of(tagKeys, tagValues), null, createdTimestampMillis))), + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, + family -> summarySnapshot(family, family.getConventionName(), helpText(id.getDescription())), + new SummaryDataPointSnapshot((long) ft.count(), ft.totalTime(getBaseTimeUnit()), Quantiles.EMPTY, + Labels.of(tagKeys, tagValues), null, createdTimestampMillis))), registeredFamily(MetricType.SUMMARY, conventionName(id), tagKeys, id.getDescription())); }); return ft; @@ -388,11 +385,10 @@ protected FunctionCounter newFunctionCounter(Meter.Id id, T obj, ToDoubleFun List tagValues = tagValues(id); List tagKeys = tagKeys(id); String familyName = counterMetricName(conventionName(id), id.getName()); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, - family -> counterSnapshot(family, family.getConventionName(), helpText(id.getDescription())), - new CounterDataPointSnapshot(fc.count(), Labels.of(tagKeys, tagValues), null, - createdTimestampMillis))), + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(familyName, + family -> counterSnapshot(family, family.getConventionName(), helpText(id.getDescription())), + new CounterDataPointSnapshot(fc.count(), Labels.of(tagKeys, tagValues), null, + createdTimestampMillis))), registeredFamily(MetricType.COUNTER, familyName, tagKeys, id.getDescription())); }); return fc; @@ -469,8 +465,8 @@ private MicrometerCollector.Family customCounterFamily new CounterDataPointSnapshot(value, labels, null, createdTimestampMillis)); } - private MicrometerCollector.Family customGaugeFamily(Meter.Id id, - CustomMeterMetric metric, Labels labels, double value) { + private MicrometerCollector.Family customGaugeFamily(Meter.Id id, CustomMeterMetric metric, + Labels labels, double value) { return new MicrometerCollector.Family<>(metric.name, family -> gaugeSnapshot(family, metric.name, helpText(id.getDescription())), new GaugeDataPointSnapshot(value, labels, null)); @@ -625,8 +621,8 @@ private void onMeterRemoved(Meter meter) { } } - private CounterSnapshot counterSnapshot(MicrometerCollector.Family family, - String name, String help) { + private CounterSnapshot counterSnapshot(MicrometerCollector.Family family, String name, + String help) { CounterSnapshot.Builder builder = CounterSnapshot.builder().name(name).help(help); family.dataPointSnapshots.forEach(builder::dataPoint); return builder.build(); @@ -666,8 +662,8 @@ private io.prometheus.metrics.model.snapshots.HistogramSnapshot histogramSnapsho } private String counterMetricName(String prometheusName, String originalName) { - return normalizeBaseName(prometheusName, originalName, ".bucket", "_bucket", ".created", "_created", - ".info", "_info", ".total", "_total"); + return normalizeBaseName(prometheusName, originalName, ".bucket", "_bucket", ".created", "_created", ".info", + "_info", ".total", "_total"); } private String infoMetricName(String prometheusName, String originalName) { @@ -675,8 +671,8 @@ private String infoMetricName(String prometheusName, String originalName) { } private String gaugeMetricName(String prometheusName, String originalName) { - return normalizeBaseName(prometheusName, originalName, ".bucket", "_bucket", ".created", "_created", - ".total", "_total"); + return normalizeBaseName(prometheusName, originalName, ".bucket", "_bucket", ".created", "_created", ".total", + "_total"); } private static String normalizeBaseName(String name, String originalName, String... suffixMappings) { diff --git a/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java b/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java index ca279d0d42..904a9d70b8 100644 --- a/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java +++ b/implementations/micrometer-registry-prometheus/src/test/java/io/micrometer/prometheusmetrics/MicrometerCollectorTest.java @@ -47,13 +47,11 @@ void manyTags() { CounterSnapshot.CounterDataPointSnapshot sample = new CounterSnapshot.CounterDataPointSnapshot(1.0, Labels.of("k", Integer.toString(i)), null, 0); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample))); + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); } // Threw StackOverflowException because of too many nested streams originally @@ -73,19 +71,17 @@ void sameValuesDifferentOrder() { Meter.Id sample2Id = id.withTags(Tags.of("k", "v2", "k2", "v1")); collector.add(sampleId, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample))); + (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); collector.add(sample2Id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample2))); + (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample2))); assertThat(collector.collect().get(0).getDataPoints()).hasSize(2); } @@ -102,20 +98,16 @@ void sameMetricDifferentTagKeysCounter() { Labels.of(asList("k1", "k4"), asList("v1", "v4")), null, 0); Meter.Id id2 = id.replaceTags(Tags.of("k1", "v1", "k4", "v4")); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample))); - collector.add(id2, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample2))); + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); + collector.add(id2, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample2))); assertThat(collector.collect().get(0).getDataPoints()).hasSize(2); } @@ -132,20 +124,16 @@ void oneSampleHasSubsetOfTagKeysOfAnotherSample() { Labels.of(asList("k1", "k2"), asList("v1", "v2")), null, 0); Meter.Id id2 = id.replaceTags(Tags.of("k1", "v1", "k2", "v2")); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample))); - collector.add(id2, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample2))); + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); + collector.add(id2, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample2))); assertThat(collector.collect().get(0).getDataPoints()).hasSize(2); } @@ -162,20 +150,16 @@ void sameMetricNameWithNoTagsAndAListOfTags() { Labels.EMPTY, null, 0); Meter.Id id2 = id.replaceTags(Tags.empty()); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample))); - collector.add(id2, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample2))); + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample))); + collector.add(id2, (conventionName) -> Stream.of(new MicrometerCollector.Family<>(conventionName, family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name(family.getConventionName()); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample2))); assertThat(collector.collect().get(0).getDataPoints()).hasSize(2); } @@ -187,15 +171,12 @@ void registrationDescriptorUsesPrometheusFamilyName() { CounterSnapshot.CounterDataPointSnapshot sample = new CounterSnapshot.CounterDataPointSnapshot(1.0, Labels.of("k", "v"), null, 0); - collector.add(id, - (conventionName) -> Stream.of(new MicrometerCollector.Family<>("my_counter", - family -> { - CounterSnapshot.Builder builder = CounterSnapshot.builder().name("my_counter"); - family.dataPointSnapshots.forEach(builder::dataPoint); - return builder.build(); - }, sample)), - new MicrometerCollector.RegisteredFamily( - MetricFamilyDescriptor.counter("my_counter").help("help").labelNames(asList("k")).build())); + collector.add(id, (conventionName) -> Stream.of(new MicrometerCollector.Family<>("my_counter", family -> { + CounterSnapshot.Builder builder = CounterSnapshot.builder().name("my_counter"); + family.dataPointSnapshots.forEach(builder::dataPoint); + return builder.build(); + }, sample)), new MicrometerCollector.RegisteredFamily( + MetricFamilyDescriptor.counter("my_counter").help("help").labelNames(asList("k")).build())); assertThat(collector.getPrometheusNames()).containsExactly("my_counter"); assertThat(collector.getMetricType("my_counter")).isEqualTo(MetricType.COUNTER);