metrics_exporter_plotly/
pattern.rs1use regex::Regex;
2use std::collections::HashMap;
3
4#[derive(Debug)]
5pub struct PatternGroup {
6 patterns: Vec<(Regex, PlotKind)>,
7}
8
9impl Default for PatternGroup {
10 fn default() -> Self {
11 Self::new()
12 }
13}
14
15impl PatternGroup {
16 pub fn new() -> Self {
17 Self { patterns: vec![] }
18 }
19
20 pub fn pattern(mut self, regex: &str, kind: PlotKind) -> Self {
42 let regex = Regex::new(regex).unwrap();
43 self.patterns.push((regex, kind));
44 self
45 }
46
47 pub(crate) fn apply(&self, metrics: &[&str]) -> Vec<Vec<(String, PlotKind)>> {
49 let mut m: HashMap<_, Vec<(String, PlotKind)>> = HashMap::new();
50
51 for metric in metrics {
52 for (re, plot_kind) in &self.patterns {
53 let Some(caps) = re.captures(metric) else {
54 continue;
55 };
56
57 let cap = caps
58 .iter()
59 .skip(1)
60 .map(|c| c.unwrap().as_str())
61 .take(1)
62 .collect::<Vec<_>>();
63 let [cap] = cap[..] else { continue };
64
65 if let Some(v) = m.get_mut(cap) {
66 v.push((metric.to_string(), *plot_kind));
67 } else {
68 m.insert(cap, vec![(metric.to_string(), *plot_kind)]);
69 }
70 }
71 }
72
73 m.drain().map(|(_, group)| group).collect()
74 }
75}
76
77#[derive(Debug, Copy, Clone, PartialEq)]
78pub enum PlotKind {
79 Line,
80 Rate,
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn test_finds_patterns() {
89 let group = PatternGroup::new()
90 .pattern(r"(?<scenario>.*)_success", PlotKind::Rate)
91 .pattern(r"(?<scenario>.*)_error", PlotKind::Line);
92
93 let metrics = vec![
94 "foo_success",
95 "bar_success",
96 "foo_error",
97 "bar_error",
98 "baz_drror_",
99 ];
100
101 let groups = group.apply(&metrics);
102
103 assert!(groups.contains(&vec![
104 ("foo_success".to_string(), PlotKind::Rate),
105 ("foo_error".to_string(), PlotKind::Line)
106 ]));
107
108 assert!(groups.contains(&vec![
109 ("bar_success".to_string(), PlotKind::Rate),
110 ("bar_error".to_string(), PlotKind::Line)
111 ]));
112 }
113}