Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions metrics-exporter-prometheus/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl PrometheusBuilder {
/// It only affects matching metrics if set_buckets was not used.
pub fn set_buckets_for_metric(mut self, matcher: Matcher, values: &[f64]) -> Self {
let buckets = self.bucket_overrides.get_or_insert_with(HashMap::new);
buckets.insert(matcher, values.to_vec());
buckets.insert(matcher.sanitized(), values.to_vec());
self
}

Expand Down Expand Up @@ -349,27 +349,27 @@ mod tests {

let recorder = PrometheusBuilder::new()
.set_buckets_for_metric(
Matcher::Full("metrics_testing_foo".to_owned()),
Matcher::Full("metrics.testing foo".to_owned()),
&FULL_VALUES[..],
)
.set_buckets_for_metric(
Matcher::Prefix("metrics_testing".to_owned()),
Matcher::Prefix("metrics.testing".to_owned()),
&PREFIX_VALUES[..],
)
.set_buckets_for_metric(Matcher::Suffix("foo".to_owned()), &SUFFIX_VALUES[..])
.set_buckets(&DEFAULT_VALUES[..])
.build();

let full_key = Key::from_name("metrics_testing_foo");
let full_key = Key::from_name("metrics.testing_foo");
recorder.record_histogram(&full_key, FULL_VALUES[0]);

let prefix_key = Key::from_name("metrics_testing_bar");
let prefix_key = Key::from_name("metrics.testing_bar");
recorder.record_histogram(&prefix_key, PREFIX_VALUES[1]);

let suffix_key = Key::from_name("metrics_testin_foo");
recorder.record_histogram(&suffix_key, SUFFIX_VALUES[2]);

let default_key = Key::from_name("metrics_wee");
let default_key = Key::from_name("metrics.wee");
recorder.record_histogram(&default_key, DEFAULT_VALUES[2] + 1.0);

let full_data = concat!(
Expand Down
35 changes: 35 additions & 0 deletions metrics-exporter-prometheus/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ impl Matcher {
Matcher::Full(full) => key == full,
}
}

/// Creates a sanitized version of this matcher.
pub(crate) fn sanitized(self) -> Matcher {
match self {
Matcher::Prefix(prefix) => Matcher::Prefix(sanitize_key_name(prefix.as_str())),
Matcher::Suffix(suffix) => Matcher::Suffix(sanitize_key_name(suffix.as_str())),
Matcher::Full(full) => Matcher::Full(sanitize_key_name(full.as_str())),
}
}
}

/// Errors that could occur while installing a Prometheus recorder/exporter.
Expand All @@ -53,3 +62,29 @@ pub struct Snapshot {
pub gauges: HashMap<String, HashMap<Vec<String>, f64>>,
pub distributions: HashMap<String, HashMap<Vec<String>, Distribution>>,
}

pub fn sanitize_key_name(key: &str) -> String {
// Replace anything that isn't [a-zA-Z0-9_:].
let sanitize = |c: char| !(c.is_alphanumeric() || c == '_' || c == ':');
key.to_string().replace(sanitize, "_")
}

#[cfg(test)]
mod tests {
use super::sanitize_key_name;

#[test]
fn test_sanitize_key_name() {
let test_cases = vec![
("____", "____"),
("foo bar", "foo_bar"),
("abcd:efgh", "abcd:efgh"),
("lars.andersen", "lars_andersen"),
];

for (input, expected) in test_cases {
let result = sanitize_key_name(input);
assert_eq!(expected, result);
}
}
}
5 changes: 2 additions & 3 deletions metrics-exporter-prometheus/src/recorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use parking_lot::RwLock;
use metrics::{GaugeValue, Key, Recorder, Unit};
use metrics_util::{Handle, MetricKind, Recency, Registry};

use crate::common::Snapshot;
use crate::common::{sanitize_key_name, Snapshot};
use crate::distribution::{Distribution, DistributionBuilder};

pub(crate) struct Inner {
Expand Down Expand Up @@ -294,8 +294,7 @@ impl PrometheusHandle {
}

fn key_to_parts(key: &Key, defaults: &HashMap<String, String>) -> (String, Vec<String>) {
let sanitize = |c| c == '.' || c == '=' || c == '{' || c == '}' || c == '+' || c == '-';
let name = key.name().to_string().replace(sanitize, "_");
let name = sanitize_key_name(key.name());
let mut values = defaults.clone();
key.labels().into_iter().for_each(|label| {
values.insert(label.key().into(), label.value().into());
Expand Down