1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use core::fmt;

use vector_common::byte_size_of::ByteSizeOf;
use vector_config::configurable_component;

use super::{write_list, write_word, MetricTags, TagValue};

/// Metrics series.
#[configurable_component]
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct MetricSeries {
    #[serde(flatten)]
    pub name: MetricName,

    #[configurable(derived)]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<MetricTags>,
}

impl MetricSeries {
    /// Gets a reference to the name of the series.
    pub fn name(&self) -> &MetricName {
        &self.name
    }

    /// Gets a mutable reference to the name of the series.
    pub fn name_mut(&mut self) -> &mut MetricName {
        &mut self.name
    }

    /// Gets an optional reference to the tags of the series.
    pub fn tags(&self) -> Option<&MetricTags> {
        self.tags.as_ref()
    }

    /// Gets an optional mutable reference to the tags of the series.
    pub fn tags_mut(&mut self) -> &mut Option<MetricTags> {
        &mut self.tags
    }

    /// Sets or updates the string value of a tag.
    ///
    /// *Note:* This will create the tags map if it is not present.
    pub fn replace_tag(&mut self, key: String, value: impl Into<TagValue>) -> Option<String> {
        (self.tags.get_or_insert_with(Default::default)).replace(key, value)
    }

    pub fn set_multi_value_tag(&mut self, key: String, values: impl IntoIterator<Item = TagValue>) {
        (self.tags.get_or_insert_with(Default::default)).set_multi_value(key, values);
    }

    /// Removes all the tags.
    pub fn remove_tags(&mut self) {
        self.tags = None;
    }

    /// Removes the tag entry for the named key, if it exists, and returns the old value.
    ///
    /// *Note:* This will drop the tags map if the tag was the last entry in it.
    pub fn remove_tag(&mut self, key: &str) -> Option<String> {
        match &mut self.tags {
            None => None,
            Some(tags) => {
                let result = tags.remove(key);
                if tags.is_empty() {
                    self.tags = None;
                }
                result
            }
        }
    }
}

impl ByteSizeOf for MetricSeries {
    fn allocated_bytes(&self) -> usize {
        self.name.allocated_bytes() + self.tags.allocated_bytes()
    }
}

/// Metric name.
#[configurable_component]
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct MetricName {
    /// The name of the metric.
    ///
    /// This would typically be a name for the metric itself, unrelated to where the metric
    /// originates from. For example, if the metric represented the amount of used system memory, it
    /// may be called `memory.used`.
    pub name: String,

    /// The namespace of the metric.
    ///
    /// Namespace represents a grouping for a metric where the name itself may otherwise be too
    /// generic. For example, while the name of a metric may be `memory.used` for the amount of used
    /// system memory, the namespace could differentiate that by being `system` for the total amount
    /// of used memory across the system, or `vector` for the amount of used system memory specific
    /// to Vector, and so on.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub namespace: Option<String>,
}

impl MetricName {
    /// Gets a reference to the name component of this name.
    pub fn name(&self) -> &str {
        self.name.as_str()
    }

    /// Gets a mutable reference to the name component of this name.
    pub fn name_mut(&mut self) -> &mut String {
        &mut self.name
    }

    /// Gets a reference to the namespace component of this name.
    pub fn namespace(&self) -> Option<&String> {
        self.namespace.as_ref()
    }

    /// Gets a mutable reference to the namespace component of this name.
    pub fn namespace_mut(&mut self) -> &mut Option<String> {
        &mut self.namespace
    }
}

impl fmt::Display for MetricSeries {
    /// Display a metric series name using something like Prometheus' text format:
    ///
    /// ```text
    /// NAMESPACE_NAME{TAGS}
    /// ```
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        if let Some(namespace) = &self.name.namespace {
            write_word(fmt, namespace)?;
            write!(fmt, "_")?;
        }
        write_word(fmt, &self.name.name)?;
        write!(fmt, "{{")?;
        if let Some(tags) = &self.tags {
            write_list(fmt, ",", tags.iter_all(), |fmt, (tag, value)| {
                write_word(fmt, tag).and_then(|()| match value {
                    Some(value) => write!(fmt, "={value:?}"),
                    None => Ok(()),
                })
            })?;
        }
        write!(fmt, "}}")
    }
}

impl ByteSizeOf for MetricName {
    fn allocated_bytes(&self) -> usize {
        self.name.allocated_bytes() + self.namespace.allocated_bytes()
    }
}