vector_core/config/
metrics_expiration.rs

1use vector_config::configurable_component;
2
3/// Per metric set expiration options.
4#[configurable_component]
5#[derive(Clone, Debug, PartialEq, Default)]
6pub struct PerMetricSetExpiration {
7    /// Metric name to apply this expiration to. Ignores metric name if not defined.
8    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
9    pub name: Option<MetricNameMatcherConfig>,
10    /// Labels to apply this expiration to. Ignores labels if not defined.
11    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
12    #[configurable(metadata(
13        docs::enum_tag_field = "type",
14        docs::enum_tagging = "internal",
15        docs::enum_tag_description = "Metric label matcher type."
16    ))]
17    pub labels: Option<MetricLabelMatcherConfig>,
18    /// The amount of time, in seconds, that internal metrics will persist after having not been
19    /// updated before they expire and are removed.
20    ///
21    /// Set this to a value larger than your `internal_metrics` scrape interval (default 5 minutes)
22    /// so that metrics live long enough to be emitted and captured.
23    #[configurable(metadata(docs::examples = 60.0))]
24    pub expire_secs: f64,
25}
26
27/// Configuration for metric name matcher.
28#[configurable_component]
29#[derive(Clone, Debug, PartialEq)]
30#[serde(tag = "type", rename_all = "snake_case")]
31#[configurable(metadata(docs::enum_tag_description = "Metric name matcher type."))]
32pub enum MetricNameMatcherConfig {
33    /// Only considers exact name matches.
34    Exact {
35        /// The exact metric name.
36        value: String,
37    },
38    /// Compares metric name to the provided pattern.
39    Regex {
40        /// Pattern to compare to.
41        pattern: String,
42    },
43}
44
45/// Configuration for metric labels matcher.
46#[configurable_component]
47#[derive(Clone, Debug, PartialEq)]
48#[serde(tag = "type", rename_all = "snake_case")]
49#[configurable(metadata(docs::enum_tag_description = "Metric label matcher type."))]
50pub enum MetricLabelMatcher {
51    /// Looks for an exact match of one label key value pair.
52    Exact {
53        /// Metric key to look for.
54        key: String,
55        /// The exact metric label value.
56        value: String,
57    },
58    /// Compares label value with given key to the provided pattern.
59    Regex {
60        /// Metric key to look for.
61        key: String,
62        /// Pattern to compare metric label value to.
63        value_pattern: String,
64    },
65}
66
67/// Configuration for metric labels matcher group.
68#[configurable_component]
69#[derive(Clone, Debug, PartialEq)]
70#[serde(tag = "type", rename_all = "snake_case")]
71#[configurable(metadata(docs::enum_tag_description = "Metric label group matcher type."))]
72pub enum MetricLabelMatcherConfig {
73    /// Checks that any of the provided matchers can be applied to given metric.
74    Any {
75        /// List of matchers to check.
76        matchers: Vec<MetricLabelMatcher>,
77    },
78    /// Checks that all of the provided matchers can be applied to given metric.
79    All {
80        /// List of matchers to check.
81        matchers: Vec<MetricLabelMatcher>,
82    },
83}
84
85/// Tests to confirm complex examples configuration
86#[cfg(test)]
87mod tests {
88    use vrl::prelude::indoc;
89
90    use super::*;
91
92    #[test]
93    fn just_expiration_config() {
94        // This configuration should maybe be treated as invalid - because it turns into a global
95        // configuration, matching every metric
96        let config = serde_yaml::from_str::<PerMetricSetExpiration>(indoc! {r"
97            expire_secs: 10.0
98            "})
99        .unwrap();
100
101        assert!(config.name.is_none());
102        assert!(config.labels.is_none());
103        assert_eq!(10.0, config.expire_secs);
104    }
105
106    #[test]
107    fn simple_name_config() {
108        let config = serde_yaml::from_str::<PerMetricSetExpiration>(indoc! {r#"
109            name:
110                type: "exact"
111                value: "test_metric"
112            expire_secs: 1.0
113            "#})
114        .unwrap();
115
116        if let Some(MetricNameMatcherConfig::Exact { value }) = config.name {
117            assert_eq!("test_metric", value);
118        } else {
119            panic!("Expected exact name matcher");
120        }
121        assert!(config.labels.is_none());
122        assert_eq!(1.0, config.expire_secs);
123    }
124
125    #[test]
126    fn simple_labels_config() {
127        let config = serde_yaml::from_str::<PerMetricSetExpiration>(indoc! {r#"
128            labels:
129                type: "all"
130                matchers :
131                    - type: "exact"
132                      key: "test_metric_label"
133                      value: "test_value"
134            expire_secs: 1.0
135            "#})
136        .unwrap();
137
138        if let Some(MetricLabelMatcherConfig::All { matchers }) = config.labels {
139            if let MetricLabelMatcher::Exact { key, value } = &matchers[0] {
140                assert_eq!("test_metric_label", key);
141                assert_eq!("test_value", value);
142            } else {
143                panic!("Expected exact metric matcher");
144            }
145        } else {
146            panic!("Expected all matcher");
147        }
148        assert!(config.name.is_none());
149        assert_eq!(1.0, config.expire_secs);
150    }
151
152    #[test]
153    fn complex_config() {
154        let config = serde_yaml::from_str::<PerMetricSetExpiration>(indoc! {r#"
155            name:
156                type: "regex"
157                pattern: "test_metric.*"
158            labels:
159                type: "all"
160                matchers:
161                  - type: "exact"
162                    key: "component_kind"
163                    value: "sink"
164                  - type: "exact"
165                    key: "component_kind"
166                    value: "source"
167            expire_secs: 1.0
168            "#})
169        .unwrap();
170
171        if let Some(MetricNameMatcherConfig::Regex { ref pattern }) = config.name {
172            assert_eq!("test_metric.*", pattern);
173        } else {
174            panic!("Expected regex name matcher");
175        }
176
177        let Some(MetricLabelMatcherConfig::All {
178            matchers: all_matchers,
179        }) = config.labels
180        else {
181            panic!("Expected all label matcher");
182        };
183        assert_eq!(2, all_matchers.len());
184
185        let MetricLabelMatcher::Exact { key, value } = &all_matchers[0] else {
186            panic!("Expected first label matcher to be exact matcher");
187        };
188        assert_eq!("component_kind", key);
189        assert_eq!("sink", value);
190        let MetricLabelMatcher::Exact { key, value } = &all_matchers[1] else {
191            panic!("Expected second label matcher to be exact matcher");
192        };
193        assert_eq!("component_kind", key);
194        assert_eq!("source", value);
195    }
196}