Skip to content

Commit 12a1d97

Browse files
barchettatjquinno
andauthored
Allow colon in Prometheus meter name; add test (#9689) (#9763)
Co-authored-by: Tim Quinn <[email protected]>
1 parent 7b00751 commit 12a1d97

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

metrics/providers/micrometer/src/main/java/io/helidon/metrics/providers/micrometer/MicrometerPrometheusFormatter.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, 2024 Oracle and/or its affiliates.
2+
* Copyright (c) 2023, 2025 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -92,7 +92,7 @@ public static String normalizeNameToPrometheus(String name) {
9292
}
9393

9494
// Replace non-identifier characters.
95-
result = result.replaceAll("[^A-Za-z0-9_]", "_");
95+
result = result.replaceAll("[^A-Za-z0-9_:]", "_");
9696

9797
return result;
9898
}

metrics/providers/micrometer/src/test/java/io/helidon/metrics/providers/micrometer/TestPrometheusFormatting.java

+37-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023 Oracle and/or its affiliates.
2+
* Copyright (c) 2023, 2025 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -202,6 +202,42 @@ void testRetrievingByScope() {
202202
endsWith(OPENMETRICS_EOF)));
203203
}
204204

205+
@Test
206+
void testMeterNameWithColon() {
207+
Counter withColon = meterRegistry.getOrCreate(Counter.builder("c:withColon"));
208+
withColon.increment();
209+
210+
Counter withoutColon = meterRegistry.getOrCreate(Counter.builder("cWithoutColon"));
211+
withoutColon.increment(2L);
212+
213+
Counter withQuestionMark = meterRegistry.getOrCreate(Counter.builder("c?withQuestionMark"));
214+
withQuestionMark.increment();
215+
216+
MicrometerPrometheusFormatter formatter = MicrometerPrometheusFormatter.builder(meterRegistry)
217+
.resultMediaType(MediaTypes.APPLICATION_OPENMETRICS_TEXT)
218+
.scopeTagName(SCOPE_TAG_NAME)
219+
.scopeSelection(Set.of("app"))
220+
.build();
221+
222+
Optional<Object> outputOpt = formatter.format();
223+
224+
assertThat("Formatted output",
225+
checkAndCast(outputOpt),
226+
allOf(containsString(scopeExpr("c:withColon_total",
227+
"this_scope",
228+
"app",
229+
"1.0")),
230+
containsString(scopeExpr("cWithoutColon_total",
231+
"this_scope",
232+
"app",
233+
"2.0")),
234+
containsString(scopeExpr("c_withQuestionMark_total",
235+
"this_scope",
236+
"app",
237+
"1.0")),
238+
endsWith(OPENMETRICS_EOF)));
239+
}
240+
205241
private static String scopeExpr(String meterName, String key, String value, String suffix) {
206242
return meterName + "{" + key + "=\"" + value + "\"} " + suffix;
207243
}

0 commit comments

Comments
 (0)