metrics/
label.rs

1use std::slice::Iter;
2
3use crate::SharedString;
4
5/// Metadata for a metric key in the form of a key/value pair.
6///
7/// Metrics are always defined by a name, but can optionally be assigned "labels", which are
8/// key/value pairs that provide metadata about the key.  Labels are typically used for
9/// differentiating the context of when an where a metric are emitted.
10///
11/// For example, in a web service, you might wish to label metrics with the user ID responsible for
12/// the request currently being processed, or the request path being processed.  Another example may
13/// be that if you were running a piece o code that was turned on or off by a feature toggle, you may
14/// wish to include a label in metrics to indicate whether or not they were using the feature toggle.
15#[derive(PartialEq, Eq, Hash, Clone, Debug, PartialOrd, Ord)]
16pub struct Label(pub(crate) SharedString, pub(crate) SharedString);
17
18impl Label {
19    /// Creates a [`Label`] from a key and value.
20    pub fn new<K, V>(key: K, value: V) -> Self
21    where
22        K: Into<SharedString>,
23        V: Into<SharedString>,
24    {
25        Label(key.into(), value.into())
26    }
27
28    /// Creates a [`Label`] from a static key and value.
29    pub const fn from_static_parts(key: &'static str, value: &'static str) -> Self {
30        Label(SharedString::const_str(key), SharedString::const_str(value))
31    }
32
33    /// Key of this label.
34    pub fn key(&self) -> &str {
35        self.0.as_ref()
36    }
37
38    /// Value of this label.
39    pub fn value(&self) -> &str {
40        self.1.as_ref()
41    }
42
43    /// Consumes this [`Label`], returning the key and value.
44    pub fn into_parts(self) -> (SharedString, SharedString) {
45        (self.0, self.1)
46    }
47}
48
49impl<K, V> From<&(K, V)> for Label
50where
51    K: Into<SharedString> + Clone,
52    V: Into<SharedString> + Clone,
53{
54    fn from(pair: &(K, V)) -> Label {
55        Label::new(pair.0.clone(), pair.1.clone())
56    }
57}
58
59impl<K, V> From<(&K, &V)> for Label
60where
61    K: Into<SharedString> + Clone,
62    V: Into<SharedString> + Clone,
63{
64    fn from(pair: (&K, &V)) -> Label {
65        Label::new(pair.0.clone(), pair.1.clone())
66    }
67}
68
69/// A value that can be converted to a vector of [`Label`]s.
70pub trait IntoLabels {
71    /// Consumes this value, turning it into a vector of [`Label`]s.
72    fn into_labels(self) -> Vec<Label>;
73}
74
75impl IntoLabels for Vec<Label> {
76    fn into_labels(self) -> Vec<Label> {
77        self
78    }
79}
80
81impl IntoLabels for Iter<'_, Label> {
82    fn into_labels(self) -> Vec<Label> {
83        self.cloned().collect()
84    }
85}
86
87impl<T: ?Sized, L> IntoLabels for &T
88where
89    Self: IntoIterator<Item = L>,
90    L: Into<Label>,
91{
92    fn into_labels(self) -> Vec<Label> {
93        self.into_iter().map(|l| l.into()).collect()
94    }
95}
96
97#[cfg(test)]
98mod label_tests {
99    use super::*;
100
101    #[test]
102    fn slice_labels() {
103        let labels = [("x", "a"), ("y", "b")];
104
105        fn from_slice_to_labels(labels: &[(&'static str, &'static str)]) -> Vec<Label> {
106            labels.into_labels()
107        }
108
109        let expected = vec![Label::new("x", "a"), Label::new("y", "b")];
110        assert_eq!(from_slice_to_labels(&labels), expected);
111    }
112
113    #[test]
114    fn btreemap_to_labels() {
115        use std::collections::BTreeMap;
116
117        let labels_btreemap = BTreeMap::from([("customer", "Rust Foundation")]);
118
119        let expected = vec![Label::new("customer", "Rust Foundation")];
120        assert_eq!(labels_btreemap.into_labels(), expected);
121    }
122}