Skip to content

Commit b5b3def

Browse files
committed
fix: normalize legacy gauge names from raw metadata
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
1 parent 74917b8 commit b5b3def

5 files changed

Lines changed: 103 additions & 32 deletions

File tree

‎prometheus-metrics-exposition-formats/src/main/java/io/prometheus/metrics/expositionformats/internal/PrometheusProtobufWriterImpl.java‎

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import io.prometheus.metrics.model.snapshots.MetricSnapshot;
2222
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
2323
import io.prometheus.metrics.model.snapshots.NativeHistogramBuckets;
24-
import io.prometheus.metrics.model.snapshots.PrometheusNaming;
2524
import io.prometheus.metrics.model.snapshots.Quantiles;
2625
import io.prometheus.metrics.model.snapshots.SnapshotEscaper;
2726
import io.prometheus.metrics.model.snapshots.StateSetSnapshot;
@@ -51,7 +50,10 @@ public String toDebugString(MetricSnapshots metricSnapshots, EscapingScheme esca
5150
for (MetricSnapshot s : merged) {
5251
MetricSnapshot snapshot = SnapshotEscaper.escapeMetricSnapshot(s, escapingScheme);
5352
if (!snapshot.getDataPoints().isEmpty()) {
54-
stringBuilder.append(TextFormat.printer().printToString(convert(snapshot, escapingScheme)));
53+
stringBuilder.append(
54+
TextFormat.printer()
55+
.printToString(
56+
convert(snapshot, s.getMetadata().getOriginalName(), escapingScheme)));
5557
}
5658
}
5759
return stringBuilder.toString();
@@ -65,12 +67,17 @@ public void write(
6567
for (MetricSnapshot s : merged) {
6668
MetricSnapshot snapshot = SnapshotEscaper.escapeMetricSnapshot(s, escapingScheme);
6769
if (!snapshot.getDataPoints().isEmpty()) {
68-
convert(snapshot, escapingScheme).writeDelimitedTo(out);
70+
convert(snapshot, s.getMetadata().getOriginalName(), escapingScheme).writeDelimitedTo(out);
6971
}
7072
}
7173
}
7274

7375
public Metrics.MetricFamily convert(MetricSnapshot snapshot, EscapingScheme scheme) {
76+
return convert(snapshot, snapshot.getMetadata().getOriginalName(), scheme);
77+
}
78+
79+
private Metrics.MetricFamily convert(
80+
MetricSnapshot snapshot, String rawOriginalName, EscapingScheme scheme) {
7481
Metrics.MetricFamily.Builder builder = Metrics.MetricFamily.newBuilder();
7582
if (snapshot instanceof CounterSnapshot) {
7683
for (CounterDataPointSnapshot data : ((CounterSnapshot) snapshot).getDataPoints()) {
@@ -83,7 +90,13 @@ public Metrics.MetricFamily convert(MetricSnapshot snapshot, EscapingScheme sche
8390
builder.addMetric(convert(data, scheme));
8491
}
8592
setMetadataUnlessEmpty(
86-
builder, snapshot.getMetadata(), null, Metrics.MetricType.GAUGE, scheme, true);
93+
builder,
94+
snapshot.getMetadata(),
95+
rawOriginalName,
96+
null,
97+
Metrics.MetricType.GAUGE,
98+
scheme,
99+
true);
87100
} else if (snapshot instanceof HistogramSnapshot) {
88101
HistogramSnapshot histogram = (HistogramSnapshot) snapshot;
89102
for (HistogramSnapshot.HistogramDataPointSnapshot data : histogram.getDataPoints()) {
@@ -291,12 +304,14 @@ private void setMetadataUnlessEmpty(
291304
@Nullable String nameSuffix,
292305
Metrics.MetricType type,
293306
EscapingScheme scheme) {
294-
setMetadataUnlessEmpty(builder, metadata, nameSuffix, type, scheme, false);
307+
setMetadataUnlessEmpty(
308+
builder, metadata, metadata.getOriginalName(), nameSuffix, type, scheme, false);
295309
}
296310

297311
private void setMetadataUnlessEmpty(
298312
Metrics.MetricFamily.Builder builder,
299313
MetricMetadata metadata,
314+
String rawOriginalName,
300315
@Nullable String nameSuffix,
301316
Metrics.MetricType type,
302317
EscapingScheme scheme,
@@ -305,7 +320,8 @@ private void setMetadataUnlessEmpty(
305320
return;
306321
}
307322
builder.setName(
308-
resolveMetricFamilyName(metadata, nameSuffix, scheme, normalizeLegacyGaugeName));
323+
resolveMetricFamilyName(
324+
metadata, rawOriginalName, nameSuffix, scheme, normalizeLegacyGaugeName));
309325
if (metadata.getHelp() != null) {
310326
builder.setHelp(metadata.getHelp());
311327
}
@@ -314,19 +330,12 @@ private void setMetadataUnlessEmpty(
314330

315331
private String resolveMetricFamilyName(
316332
MetricMetadata metadata,
333+
String rawOriginalName,
317334
@Nullable String nameSuffix,
318335
EscapingScheme scheme,
319336
boolean normalizeLegacyGaugeName) {
320337
if (normalizeLegacyGaugeName) {
321-
String originalName = metadata.getOriginalName();
322-
if (originalName.endsWith(".created")) {
323-
return PrometheusNaming.escapeName(
324-
originalName.substring(0, originalName.length() - ".created".length()), scheme);
325-
}
326-
if (originalName.endsWith(".total")) {
327-
return PrometheusNaming.escapeName(
328-
originalName.substring(0, originalName.length() - ".total".length()), scheme);
329-
}
338+
return SnapshotEscaper.getLegacyGaugeName(metadata, rawOriginalName, scheme);
330339
}
331340
if (nameSuffix == null) {
332341
return SnapshotEscaper.getMetadataName(metadata, scheme);

‎prometheus-metrics-exposition-formats/src/test/java/io/prometheus/metrics/expositionformats/DuplicateNamesProtobufTest.java‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,21 @@ void testDifferentMetrics_producesSeparateMetricFamilies() throws IOException {
239239
assertThat(gaugeFamily.getMetric(0).getGauge().getValue()).isEqualTo(50.0);
240240
}
241241

242+
@Test
243+
void testLegacyGaugeNameWithAlternateEscapingSchemes_usesBaseName() throws IOException {
244+
MetricSnapshots snapshots =
245+
MetricSnapshots.of(
246+
GaugeSnapshot.builder()
247+
.name("legacy.name.total")
248+
.dataPoint(GaugeSnapshot.GaugeDataPointSnapshot.builder().value(7).build())
249+
.build());
250+
251+
assertThat(getSingleMetricFamilyName(snapshots, EscapingScheme.DOTS_ESCAPING))
252+
.isEqualTo("legacy_dot_name");
253+
assertThat(getSingleMetricFamilyName(snapshots, EscapingScheme.VALUE_ENCODING_ESCAPING))
254+
.isEqualTo("U__legacy_2e_name");
255+
}
256+
242257
@Test
243258
void testLegacyGaugeNameWithDotTotal_usesBaseName() throws IOException {
244259
MetricSnapshots snapshots =
@@ -261,6 +276,16 @@ void testLegacyGaugeNameWithDotTotal_usesBaseName() throws IOException {
261276
assertThat(family.getMetric(0).getGauge().getValue()).isEqualTo(7.0);
262277
}
263278

279+
private static String getSingleMetricFamilyName(
280+
MetricSnapshots snapshots, EscapingScheme escapingScheme) throws IOException {
281+
ByteArrayOutputStream out = new ByteArrayOutputStream();
282+
PrometheusProtobufWriterImpl writer = new PrometheusProtobufWriterImpl();
283+
writer.write(out, snapshots, escapingScheme);
284+
List<Metrics.MetricFamily> metricFamilies = parseProtobufOutput(out);
285+
assertThat(metricFamilies).hasSize(1);
286+
return metricFamilies.get(0).getName();
287+
}
288+
264289
private static MetricSnapshots getMetricSnapshots() {
265290
PrometheusRegistry registry = new PrometheusRegistry();
266291

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

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static io.prometheus.metrics.expositionformats.TextFormatUtil.writePrometheusTimestamp;
99
import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.escapeMetricSnapshot;
1010
import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getExpositionBaseMetadataName;
11+
import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getLegacyGaugeName;
1112
import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getMetadataName;
1213
import static io.prometheus.metrics.model.snapshots.SnapshotEscaper.getSnapshotLabelName;
1314

@@ -123,7 +124,7 @@ public void write(OutputStream out, MetricSnapshots metricSnapshots, EscapingSch
123124
if (snapshot instanceof CounterSnapshot) {
124125
writeCounter(writer, (CounterSnapshot) snapshot, scheme);
125126
} else if (snapshot instanceof GaugeSnapshot) {
126-
writeGauge(writer, (GaugeSnapshot) snapshot, scheme);
127+
writeGauge(writer, (GaugeSnapshot) snapshot, s.getMetadata().getOriginalName(), scheme);
127128
} else if (snapshot instanceof HistogramSnapshot) {
128129
writeHistogram(writer, (HistogramSnapshot) snapshot, scheme);
129130
} else if (snapshot instanceof SummarySnapshot) {
@@ -189,10 +190,11 @@ private void writeCounter(Writer writer, CounterSnapshot snapshot, EscapingSchem
189190
}
190191
}
191192

192-
private void writeGauge(Writer writer, GaugeSnapshot snapshot, EscapingScheme scheme)
193+
private void writeGauge(
194+
Writer writer, GaugeSnapshot snapshot, String rawOriginalName, EscapingScheme scheme)
193195
throws IOException {
194196
MetricMetadata metadata = snapshot.getMetadata();
195-
String gaugeName = resolveLegacyGaugeName(metadata, scheme);
197+
String gaugeName = getLegacyGaugeName(metadata, rawOriginalName, scheme);
196198
writeMetadataWithFullName(writer, gaugeName, "gauge", metadata);
197199
for (GaugeSnapshot.GaugeDataPointSnapshot data : snapshot.getDataPoints()) {
198200
writeNameAndLabels(writer, gaugeName, null, data.getLabels(), scheme);
@@ -471,19 +473,6 @@ private static String resolveBaseName(String fullName, String suffix) {
471473
return fullName;
472474
}
473475

474-
private static String resolveLegacyGaugeName(MetricMetadata metadata, EscapingScheme scheme) {
475-
String originalName = metadata.getOriginalName();
476-
if (originalName.endsWith(".created")) {
477-
return PrometheusNaming.escapeName(
478-
originalName.substring(0, originalName.length() - ".created".length()), scheme);
479-
}
480-
if (originalName.endsWith(".total")) {
481-
return PrometheusNaming.escapeName(
482-
originalName.substring(0, originalName.length() - ".total".length()), scheme);
483-
}
484-
return getMetadataName(metadata, scheme);
485-
}
486-
487476
private void writeEscapedHelp(Writer writer, String s) throws IOException {
488477
for (int i = 0; i < s.length(); i++) {
489478
char c = s.charAt(i);

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,29 @@ void testGaugeWithDots() throws IOException {
666666
assertPrometheusProtobuf(prometheusProtobuf, gauge);
667667
}
668668

669+
@Test
670+
void testGaugeReservedSuffixCompatibilityWithAlternateEscapingSchemes() throws IOException {
671+
GaugeSnapshot totalGauge =
672+
GaugeSnapshot.builder()
673+
.name("legacy.name.total")
674+
.dataPoint(GaugeDataPointSnapshot.builder().value(6).build())
675+
.build();
676+
assertPrometheusText(
677+
"""
678+
# TYPE legacy_dot_name gauge
679+
legacy_dot_name 6.0
680+
""",
681+
totalGauge,
682+
EscapingScheme.DOTS_ESCAPING);
683+
assertPrometheusText(
684+
"""
685+
# TYPE U__legacy_2e_name gauge
686+
U__legacy_2e_name 6.0
687+
""",
688+
totalGauge,
689+
EscapingScheme.VALUE_ENCODING_ESCAPING);
690+
}
691+
669692
@Test
670693
void testGaugeReservedSuffixCompatibilityOutsideOpenMetrics() throws IOException {
671694
GaugeSnapshot createdGauge =
@@ -3145,9 +3168,14 @@ private void assertOpenMetricsTextWithoutCreated(String expected, MetricSnapshot
31453168
}
31463169

31473170
private void assertPrometheusText(String expected, MetricSnapshot snapshot) throws IOException {
3171+
assertPrometheusText(expected, snapshot, EscapingScheme.UNDERSCORE_ESCAPING);
3172+
}
3173+
3174+
private void assertPrometheusText(
3175+
String expected, MetricSnapshot snapshot, EscapingScheme escapingScheme) throws IOException {
31483176
ByteArrayOutputStream out = new ByteArrayOutputStream();
31493177
getPrometheusWriter(PrometheusTextFormatWriter.builder().setIncludeCreatedTimestamps(true))
3150-
.write(out, MetricSnapshots.of(snapshot), EscapingScheme.UNDERSCORE_ESCAPING);
3178+
.write(out, MetricSnapshots.of(snapshot), escapingScheme);
31513179
assertThat(out).hasToString(expected);
31523180
}
31533181

‎prometheus-metrics-model/src/main/java/io/prometheus/metrics/model/snapshots/SnapshotEscaper.java‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,26 @@ public static String getOriginalMetadataName(MetricMetadata metadata, EscapingSc
113113
}
114114
}
115115

116+
public static String getLegacyGaugeName(
117+
MetricMetadata metadata, String rawOriginalName, EscapingScheme scheme) {
118+
String legacyGaugeBaseName = stripLegacyGaugeSuffix(rawOriginalName);
119+
if (legacyGaugeBaseName != null) {
120+
return PrometheusNaming.escapeName(legacyGaugeBaseName, scheme);
121+
}
122+
return getMetadataName(metadata, scheme);
123+
}
124+
125+
@Nullable
126+
private static String stripLegacyGaugeSuffix(String rawOriginalName) {
127+
if (rawOriginalName.endsWith(".created")) {
128+
return rawOriginalName.substring(0, rawOriginalName.length() - ".created".length());
129+
}
130+
if (rawOriginalName.endsWith(".total")) {
131+
return rawOriginalName.substring(0, rawOriginalName.length() - ".total".length());
132+
}
133+
return null;
134+
}
135+
116136
public static Labels escapeLabels(Labels labels, EscapingScheme scheme) {
117137
Labels.Builder outLabelsBuilder = Labels.builder();
118138

0 commit comments

Comments
 (0)