vector_core/event/metric/
series.rs

1use core::fmt;
2
3use vector_common::byte_size_of::ByteSizeOf;
4use vector_config::configurable_component;
5
6use super::{write_list, write_word, MetricTags, TagValue};
7
8/// Metrics series.
9#[configurable_component]
10#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
11pub struct MetricSeries {
12    #[serde(flatten)]
13    pub name: MetricName,
14
15    #[configurable(derived)]
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub tags: Option<MetricTags>,
18}
19
20impl MetricSeries {
21    /// Gets a reference to the name of the series.
22    pub fn name(&self) -> &MetricName {
23        &self.name
24    }
25
26    /// Gets a mutable reference to the name of the series.
27    pub fn name_mut(&mut self) -> &mut MetricName {
28        &mut self.name
29    }
30
31    /// Gets an optional reference to the tags of the series.
32    pub fn tags(&self) -> Option<&MetricTags> {
33        self.tags.as_ref()
34    }
35
36    /// Gets an optional mutable reference to the tags of the series.
37    pub fn tags_mut(&mut self) -> &mut Option<MetricTags> {
38        &mut self.tags
39    }
40
41    /// Sets or updates the string value of a tag.
42    ///
43    /// *Note:* This will create the tags map if it is not present.
44    pub fn replace_tag(&mut self, key: String, value: impl Into<TagValue>) -> Option<String> {
45        (self.tags.get_or_insert_with(Default::default)).replace(key, value)
46    }
47
48    pub fn set_multi_value_tag(&mut self, key: String, values: impl IntoIterator<Item = TagValue>) {
49        (self.tags.get_or_insert_with(Default::default)).set_multi_value(key, values);
50    }
51
52    /// Removes all the tags.
53    pub fn remove_tags(&mut self) {
54        self.tags = None;
55    }
56
57    /// Removes the tag entry for the named key, if it exists, and returns the old value.
58    ///
59    /// *Note:* This will drop the tags map if the tag was the last entry in it.
60    pub fn remove_tag(&mut self, key: &str) -> Option<String> {
61        match &mut self.tags {
62            None => None,
63            Some(tags) => {
64                let result = tags.remove(key);
65                if tags.is_empty() {
66                    self.tags = None;
67                }
68                result
69            }
70        }
71    }
72}
73
74impl ByteSizeOf for MetricSeries {
75    fn allocated_bytes(&self) -> usize {
76        self.name.allocated_bytes() + self.tags.allocated_bytes()
77    }
78}
79
80/// Metric name.
81#[configurable_component]
82#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
83pub struct MetricName {
84    /// The name of the metric.
85    ///
86    /// This would typically be a name for the metric itself, unrelated to where the metric
87    /// originates from. For example, if the metric represented the amount of used system memory, it
88    /// may be called `memory.used`.
89    pub name: String,
90
91    /// The namespace of the metric.
92    ///
93    /// Namespace represents a grouping for a metric where the name itself may otherwise be too
94    /// generic. For example, while the name of a metric may be `memory.used` for the amount of used
95    /// system memory, the namespace could differentiate that by being `system` for the total amount
96    /// of used memory across the system, or `vector` for the amount of used system memory specific
97    /// to Vector, and so on.
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub namespace: Option<String>,
100}
101
102impl MetricName {
103    /// Gets a reference to the name component of this name.
104    pub fn name(&self) -> &str {
105        self.name.as_str()
106    }
107
108    /// Gets a mutable reference to the name component of this name.
109    pub fn name_mut(&mut self) -> &mut String {
110        &mut self.name
111    }
112
113    /// Gets a reference to the namespace component of this name.
114    pub fn namespace(&self) -> Option<&String> {
115        self.namespace.as_ref()
116    }
117
118    /// Gets a mutable reference to the namespace component of this name.
119    pub fn namespace_mut(&mut self) -> &mut Option<String> {
120        &mut self.namespace
121    }
122}
123
124impl fmt::Display for MetricSeries {
125    /// Display a metric series name using something like Prometheus' text format:
126    ///
127    /// ```text
128    /// NAMESPACE_NAME{TAGS}
129    /// ```
130    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
131        if let Some(namespace) = &self.name.namespace {
132            write_word(fmt, namespace)?;
133            write!(fmt, "_")?;
134        }
135        write_word(fmt, &self.name.name)?;
136        write!(fmt, "{{")?;
137        if let Some(tags) = &self.tags {
138            write_list(fmt, ",", tags.iter_all(), |fmt, (tag, value)| {
139                write_word(fmt, tag).and_then(|()| match value {
140                    Some(value) => write!(fmt, "={value:?}"),
141                    None => Ok(()),
142                })
143            })?;
144        }
145        write!(fmt, "}}")
146    }
147}
148
149impl ByteSizeOf for MetricName {
150    fn allocated_bytes(&self) -> usize {
151        self.name.allocated_bytes() + self.namespace.allocated_bytes()
152    }
153}