Skip to content

Commit

Permalink
fix prometheus metric name and label key sanitizer (metrics-rs#296)
Browse files Browse the repository at this point in the history
Co-authored-by: Toby Lawrence <[email protected]>
  • Loading branch information
wx-csy and tobz authored Apr 8, 2022
1 parent ba36096 commit 5330399
Showing 1 changed file with 22 additions and 6 deletions.
28 changes: 22 additions & 6 deletions metrics-exporter-prometheus/src/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,17 @@ pub fn sanitize_metric_name(name: &str) -> String {
/// [data model]: https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
pub fn sanitize_label_key(key: &str) -> String {
// The first character must be [a-zA-Z_], and all subsequent characters must be [a-zA-Z0-9_].
key.replacen(invalid_label_key_start_character, "_", 1)
.replace(invalid_label_key_character, "_")
.replacen("__", "___", 1)
let mut out = String::with_capacity(key.len());
let mut is_invalid: fn(char) -> bool = invalid_label_key_start_character;
for c in key.chars() {
if is_invalid(c) {
out.push('_');
} else {
out.push(c);
}
is_invalid = invalid_label_key_character;
}
out
}

/// Sanitizes a label value to be valid under the Prometheus [data model].
Expand Down Expand Up @@ -241,6 +249,8 @@ mod tests {
("foo_bar", "foo_bar"),
("foo1_bar", "foo1_bar"),
("1foobar", "_foobar"),
("foo1:bar2", "foo1:bar2"),
("123", "_23"),
];

for (input, expected) in cases {
Expand All @@ -257,7 +267,9 @@ mod tests {
(":", "_"),
("foo_bar", "foo_bar"),
("1foobar", "_foobar"),
("__foobar", "___foobar"),
("__foobar", "__foobar"),
("foo1bar2", "foo1bar2"),
("123", "_23"),
];

for (input, expected) in cases {
Expand Down Expand Up @@ -329,13 +341,17 @@ mod tests {

// Label keys cannot begin with two underscores, as that format is reserved for internal
// use.
if as_chars.len() == 2 {
//
// TODO: More closely examine how official Prometheus client libraries handle label key sanitization
// and follow whatever they do, so it's not actually clear if transforming `__foo` to `___foo` would
// be valid, given that it still technically starts with two underscores.
/*if as_chars.len() == 2 {
assert!(!(as_chars[0] == '_' && as_chars[1] == '_'));
} else if as_chars.len() == 3 {
if as_chars[0] == '_' && as_chars[1] == '_' {
assert_eq!(as_chars[2], '_');
}
}
}*/

assert!(!as_chars.iter().any(|c| invalid_label_key_character(*c)),
"invalid character in label key");
Expand Down

0 comments on commit 5330399

Please sign in to comment.