Skip to content

Commit 9289e4a

Browse files
committed
cleanups, ironing out edge cases
Signed-off-by: Jay DeLuca <jaydeluca4@gmail.com>
1 parent 43ab4b1 commit 9289e4a

File tree

7 files changed

+408
-120
lines changed

7 files changed

+408
-120
lines changed

integration-tests/it-exporter/it-exporter-test/src/test/java/io/prometheus/metrics/it/exporter/test/DuplicateMetricsIT.java

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,6 @@
99
import java.util.List;
1010
import org.junit.jupiter.api.Test;
1111

12-
/**
13-
* Integration test for duplicate metric names with different label sets.
14-
*
15-
* <p>This test validates that:
16-
*
17-
* <ul>
18-
* <li>Multiple metrics with the same Prometheus name but different labels can be registered
19-
* <li>All exposition formats (text, OpenMetrics, protobuf) correctly merge and expose them
20-
* <li>The merged output is valid and scrapeable by Prometheus
21-
* </ul>
22-
*/
2312
class DuplicateMetricsIT extends ExporterTest {
2413

2514
public DuplicateMetricsIT() throws IOException, URISyntaxException {
@@ -111,8 +100,6 @@ void testDuplicateMetricsInPrometheusProtobufFormat() throws IOException {
111100

112101
List<Metrics.MetricFamily> metrics = response.protoBody();
113102

114-
// Should have exactly 3 metric families (active_connections, http_requests_total,
115-
// unique_metric_bytes_total)
116103
assertThat(metrics).hasSize(3);
117104

118105
// Metrics are sorted by name

prometheus-metrics-core/src/main/java/io/prometheus/metrics/core/metrics/MetricWithFixedMetadata.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,10 @@ public String getPrometheusName() {
5353

5454
@Override
5555
public Set<String> getLabelNames() {
56-
Set<String> names = new HashSet<>(Arrays.asList(labelNames));
56+
Set<String> names = new HashSet<>();
57+
for (String labelName : labelNames) {
58+
names.add(PrometheusNaming.prometheusName(labelName));
59+
}
5760
for (Label label : constLabels) {
5861
names.add(PrometheusNaming.prometheusName(label.getName()));
5962
}

prometheus-metrics-core/src/test/java/io/prometheus/metrics/core/metrics/CounterTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.prometheus.metrics.expositionformats.generated.com_google_protobuf_4_33_4.Metrics;
1313
import io.prometheus.metrics.expositionformats.internal.PrometheusProtobufWriterImpl;
1414
import io.prometheus.metrics.expositionformats.internal.ProtobufUtil;
15+
import io.prometheus.metrics.model.registry.PrometheusRegistry;
1516
import io.prometheus.metrics.model.snapshots.CounterSnapshot;
1617
import io.prometheus.metrics.model.snapshots.Exemplar;
1718
import io.prometheus.metrics.model.snapshots.Label;
@@ -377,4 +378,17 @@ public void testConstLabelsSecond() {
377378
.constLabels(Labels.of("const_a", "const_b"))
378379
.build());
379380
}
381+
382+
@Test
383+
public void testLabelNormalizationInRegistration() {
384+
PrometheusRegistry registry = new PrometheusRegistry();
385+
386+
Counter.builder().name("requests").labelNames("request.count").register(registry);
387+
388+
// request.count and request_count normalize to the same name
389+
assertThatExceptionOfType(IllegalArgumentException.class)
390+
.isThrownBy(
391+
() -> Counter.builder().name("requests").labelNames("request_count").register(registry))
392+
.withMessageContaining("duplicate metric name with identical label schema");
393+
}
380394
}

prometheus-metrics-exposition-textformats/src/main/java/io/prometheus/metrics/expositionformats/TextFormatUtil.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,6 @@ static void writeName(Writer writer, String name, NameType nameType) throws IOEx
218218
private static MetricSnapshot mergeSnapshots(List<MetricSnapshot> snapshots) {
219219
MetricSnapshot first = snapshots.get(0);
220220

221-
// Validate all snapshots are the same type and calculate total size
222221
int totalDataPoints = 0;
223222
for (MetricSnapshot snapshot : snapshots) {
224223
if (snapshot.getClass() != first.getClass()) {
@@ -231,13 +230,11 @@ private static MetricSnapshot mergeSnapshots(List<MetricSnapshot> snapshots) {
231230
totalDataPoints += snapshot.getDataPoints().size();
232231
}
233232

234-
// Pre-size the list to avoid resizing
235233
List<DataPointSnapshot> allDataPoints = new ArrayList<>(totalDataPoints);
236234
for (MetricSnapshot snapshot : snapshots) {
237235
allDataPoints.addAll(snapshot.getDataPoints());
238236
}
239237

240-
// Create merged snapshot based on type
241238
if (first instanceof CounterSnapshot) {
242239
return new CounterSnapshot(
243240
first.getMetadata(),

prometheus-metrics-exposition-textformats/src/test/java/io/prometheus/metrics/expositionformats/TextFormatUtilTest.java

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@
33
import static org.assertj.core.api.Assertions.assertThat;
44
import static org.junit.jupiter.api.Assertions.assertEquals;
55

6-
import java.io.IOException;
7-
import java.io.StringWriter;
8-
96
import io.prometheus.metrics.model.snapshots.CounterSnapshot;
107
import io.prometheus.metrics.model.snapshots.Labels;
118
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
9+
import java.io.IOException;
10+
import java.io.StringWriter;
1211
import org.junit.jupiter.api.Test;
1312

1413
class TextFormatUtilTest {
@@ -42,24 +41,24 @@ private static String writePrometheusTimestamp(boolean timestampsInMs) throws IO
4241
@Test
4342
public void testMergeDuplicates_sameName_mergesDataPoints() {
4443
CounterSnapshot counter1 =
45-
CounterSnapshot.builder()
46-
.name("api_responses")
47-
.dataPoint(
48-
CounterSnapshot.CounterDataPointSnapshot.builder()
49-
.labels(Labels.of("uri", "/hello", "outcome", "SUCCESS"))
50-
.value(100)
51-
.build())
52-
.build();
44+
CounterSnapshot.builder()
45+
.name("api_responses")
46+
.dataPoint(
47+
CounterSnapshot.CounterDataPointSnapshot.builder()
48+
.labels(Labels.of("uri", "/hello", "outcome", "SUCCESS"))
49+
.value(100)
50+
.build())
51+
.build();
5352

5453
CounterSnapshot counter2 =
55-
CounterSnapshot.builder()
56-
.name("api_responses")
57-
.dataPoint(
58-
CounterSnapshot.CounterDataPointSnapshot.builder()
59-
.labels(Labels.of("uri", "/hello", "outcome", "FAILURE"))
60-
.value(10)
61-
.build())
62-
.build();
54+
CounterSnapshot.builder()
55+
.name("api_responses")
56+
.dataPoint(
57+
CounterSnapshot.CounterDataPointSnapshot.builder()
58+
.labels(Labels.of("uri", "/hello", "outcome", "FAILURE"))
59+
.value(10)
60+
.build())
61+
.build();
6362

6463
MetricSnapshots snapshots = new MetricSnapshots(counter1, counter2);
6564
MetricSnapshots result = TextFormatUtil.mergeDuplicates(snapshots);
@@ -70,48 +69,48 @@ public void testMergeDuplicates_sameName_mergesDataPoints() {
7069

7170
CounterSnapshot merged = (CounterSnapshot) result.get(0);
7271
assertThat(merged.getDataPoints())
73-
.anyMatch(
74-
dp ->
75-
dp.getLabels().equals(Labels.of("uri", "/hello", "outcome", "SUCCESS"))
76-
&& dp.getValue() == 100);
72+
.anyMatch(
73+
dp ->
74+
dp.getLabels().equals(Labels.of("uri", "/hello", "outcome", "SUCCESS"))
75+
&& dp.getValue() == 100);
7776
assertThat(merged.getDataPoints())
78-
.anyMatch(
79-
dp ->
80-
dp.getLabels().equals(Labels.of("uri", "/hello", "outcome", "FAILURE"))
81-
&& dp.getValue() == 10);
77+
.anyMatch(
78+
dp ->
79+
dp.getLabels().equals(Labels.of("uri", "/hello", "outcome", "FAILURE"))
80+
&& dp.getValue() == 10);
8281
}
8382

8483
@Test
8584
public void testMergeDuplicates_multipleDataPoints_allMerged() {
8685
CounterSnapshot counter1 =
87-
CounterSnapshot.builder()
88-
.name("api_responses")
89-
.dataPoint(
90-
CounterSnapshot.CounterDataPointSnapshot.builder()
91-
.labels(Labels.of("uri", "/hello", "outcome", "SUCCESS"))
92-
.value(100)
93-
.build())
94-
.dataPoint(
95-
CounterSnapshot.CounterDataPointSnapshot.builder()
96-
.labels(Labels.of("uri", "/world", "outcome", "SUCCESS"))
97-
.value(200)
98-
.build())
99-
.build();
86+
CounterSnapshot.builder()
87+
.name("api_responses")
88+
.dataPoint(
89+
CounterSnapshot.CounterDataPointSnapshot.builder()
90+
.labels(Labels.of("uri", "/hello", "outcome", "SUCCESS"))
91+
.value(100)
92+
.build())
93+
.dataPoint(
94+
CounterSnapshot.CounterDataPointSnapshot.builder()
95+
.labels(Labels.of("uri", "/world", "outcome", "SUCCESS"))
96+
.value(200)
97+
.build())
98+
.build();
10099

101100
CounterSnapshot counter2 =
102-
CounterSnapshot.builder()
103-
.name("api_responses")
104-
.dataPoint(
105-
CounterSnapshot.CounterDataPointSnapshot.builder()
106-
.labels(Labels.of("uri", "/hello", "outcome", "FAILURE"))
107-
.value(10)
108-
.build())
109-
.dataPoint(
110-
CounterSnapshot.CounterDataPointSnapshot.builder()
111-
.labels(Labels.of("uri", "/world", "outcome", "FAILURE"))
112-
.value(5)
113-
.build())
114-
.build();
101+
CounterSnapshot.builder()
102+
.name("api_responses")
103+
.dataPoint(
104+
CounterSnapshot.CounterDataPointSnapshot.builder()
105+
.labels(Labels.of("uri", "/hello", "outcome", "FAILURE"))
106+
.value(10)
107+
.build())
108+
.dataPoint(
109+
CounterSnapshot.CounterDataPointSnapshot.builder()
110+
.labels(Labels.of("uri", "/world", "outcome", "FAILURE"))
111+
.value(5)
112+
.build())
113+
.build();
115114

116115
MetricSnapshots snapshots = new MetricSnapshots(counter1, counter2);
117116
MetricSnapshots result = TextFormatUtil.mergeDuplicates(snapshots);

0 commit comments

Comments
 (0)