saluki_metrics/
builder.rs

1use std::sync::Arc;
2
3use metrics::{counter, gauge, histogram, Counter, Gauge, Histogram, Label, Level, SharedString};
4
5mod private {
6    use metrics::SharedString;
7
8    pub trait Sealed {}
9
10    impl Sealed for &'static str {}
11    impl Sealed for String {}
12    impl<T> Sealed for (&'static str, T) where T: Into<SharedString> {}
13}
14
15/// A metric tag.
16///
17/// Marker trait for types which can support being used as a metric tag, in order to optimize their internal
18/// representation to avoid unnecessary allocations.
19///
20/// This trait is sealed and cannot be implemented outside of this crate.
21pub trait MetricTag: private::Sealed {
22    /// Consumes `self` and converts it to a tag.
23    ///
24    /// Under the hood, the [`metrics`][metrics] crate is used, which calls tags "labels" instead, which is where the
25    /// return type naming comes from.
26    ///
27    /// [metrics]: https://docs.rs/metrics
28    fn into_label(self) -> Label;
29}
30
31impl MetricTag for &'static str {
32    fn into_label(self) -> Label {
33        match self.split_once(':') {
34            Some((key, value)) => Label::from_static_parts(key, value),
35            None => Label::from_static_parts(self, ""),
36        }
37    }
38}
39
40impl MetricTag for String {
41    fn into_label(self) -> Label {
42        match self.split_once(':') {
43            Some((key, value)) => Label::new(key.to_string(), value.to_string()),
44            None => Label::new(self, ""),
45        }
46    }
47}
48
49impl<T> MetricTag for (&'static str, T)
50where
51    T: Into<SharedString>,
52{
53    fn into_label(self) -> Label {
54        Label::new(SharedString::const_str(self.0), self.1.into())
55    }
56}
57
58/// Builder for constructing metrics.
59///
60/// This builder is simplistic, but supports constructing metrics with default tags, and in an API-driven way to help
61/// ensure consistent tagging across the board.
62#[derive(Clone, Default)]
63pub struct MetricsBuilder {
64    default_tags: Arc<Vec<Label>>,
65}
66
67impl MetricsBuilder {
68    /// Adds an additional default tag to use when constructing metrics.
69    ///
70    /// These tags will be included along with any existing default tags configured in the builder.
71    ///
72    /// Tags can be provided in numerous forms:
73    /// - individual tags (`"tag_name"` or `"tag_name:tag_value"`, either as `&'static str` or `String`)
74    /// - key/value tuples (`("tag_name", "tag_value")`, with the name as `&'static str` and the value as either
75    ///   `&'static str` or `String`)
76    pub fn add_default_tag<T>(mut self, tag: T) -> Self
77    where
78        T: MetricTag,
79    {
80        let default_tags = Arc::make_mut(&mut self.default_tags);
81        default_tags.push(tag.into_label());
82        self
83    }
84
85    /// Registers a counter at trace verbosity.
86    ///
87    /// The counter will include the configured default tags for this builder.
88    pub fn register_trace_counter(&self, metric_name: &'static str) -> Counter {
89        counter!(level: Level::TRACE, metric_name, self.default_tags.iter())
90    }
91
92    /// Registers a counter at trace verbosity with additional tags.
93    ///
94    /// The counter will include the configured default tags for this builder, in addition to the additional tags provided.
95    ///
96    /// See [`add_default_tag`](MetricsBuilder::add_default_tag) for information on the supported tag formats.
97    pub fn register_trace_counter_with_tags<I, T>(&self, metric_name: &'static str, additional_tags: I) -> Counter
98    where
99        I: IntoIterator<Item = T>,
100        T: MetricTag,
101    {
102        let mut tags = (*self.default_tags).clone();
103        tags.extend(additional_tags.into_iter().map(MetricTag::into_label));
104
105        counter!(level: Level::TRACE, metric_name, tags)
106    }
107
108    /// Registers a gauge at trace verbosity.
109    ///
110    /// The gauge will include the configured default tags for this builder.
111    pub fn register_trace_gauge(&self, metric_name: &'static str) -> Gauge {
112        gauge!(level: Level::TRACE, metric_name, self.default_tags.iter())
113    }
114
115    /// Registers a gauge at trace verbosity with additional tags.
116    ///
117    /// The gauge will include the configured default tags for this builder, in addition to the additional tags provided.
118    ///
119    /// See [`add_default_tag`](MetricsBuilder::add_default_tag) for information on the supported tag formats.
120    pub fn register_trace_gauge_with_tags<I, T>(&self, metric_name: &'static str, additional_tags: I) -> Gauge
121    where
122        I: IntoIterator<Item = T>,
123        T: MetricTag,
124    {
125        let mut tags = (*self.default_tags).clone();
126        tags.extend(additional_tags.into_iter().map(MetricTag::into_label));
127
128        gauge!(level: Level::TRACE, metric_name, tags)
129    }
130
131    /// Registers a histogram at trace verbosity.
132    ///
133    /// The histogram will include the configured default tags for this builder.
134    pub fn register_trace_histogram(&self, metric_name: &'static str) -> Histogram {
135        histogram!(level: Level::TRACE, metric_name, self.default_tags.iter())
136    }
137
138    /// Registers a histogram at trace verbosity with additional tags.
139    ///
140    /// The histogram will include the configured default tags for this builder, in addition to the additional tags provided.
141    ///
142    /// See [`add_default_tag`](MetricsBuilder::add_default_tag) for information on the supported tag formats.
143    pub fn register_trace_histogram_with_tags<I, T>(&self, metric_name: &'static str, additional_tags: I) -> Histogram
144    where
145        I: IntoIterator<Item = T>,
146        T: MetricTag,
147    {
148        let mut tags = (*self.default_tags).clone();
149        tags.extend(additional_tags.into_iter().map(MetricTag::into_label));
150
151        histogram!(level: Level::TRACE, metric_name, tags)
152    }
153
154    /// Registers a counter at debug verbosity.
155    ///
156    /// The counter will include the configured default tags for this builder.
157    pub fn register_debug_counter(&self, metric_name: &'static str) -> Counter {
158        counter!(level: Level::DEBUG, metric_name, self.default_tags.iter())
159    }
160
161    /// Registers a counter at debug verbosity with additional tags.
162    ///
163    /// The counter will include the configured default tags for this builder, in addition to the additional tags provided.
164    ///
165    /// See [`add_default_tag`](MetricsBuilder::add_default_tag) for information on the supported tag formats.
166    pub fn register_debug_counter_with_tags<I, T>(&self, metric_name: &'static str, additional_tags: I) -> Counter
167    where
168        I: IntoIterator<Item = T>,
169        T: MetricTag,
170    {
171        let mut tags = (*self.default_tags).clone();
172        tags.extend(additional_tags.into_iter().map(MetricTag::into_label));
173
174        counter!(level: Level::DEBUG, metric_name, tags)
175    }
176
177    /// Registers a gauge at debug verbosity.
178    ///
179    /// The gauge will include the configured default tags for this builder.
180    pub fn register_debug_gauge(&self, metric_name: &'static str) -> Gauge {
181        gauge!(level: Level::DEBUG, metric_name, self.default_tags.iter())
182    }
183
184    /// Registers a gauge at debug verbosity with additional tags.
185    ///
186    /// The gauge will include the configured default tags for this builder, in addition to the additional tags provided.
187    ///
188    /// See [`add_default_tag`](MetricsBuilder::add_default_tag) for information on the supported tag formats.
189    pub fn register_debug_gauge_with_tags<I, T>(&self, metric_name: &'static str, additional_tags: I) -> Gauge
190    where
191        I: IntoIterator<Item = T>,
192        T: MetricTag,
193    {
194        let mut tags = (*self.default_tags).clone();
195        tags.extend(additional_tags.into_iter().map(MetricTag::into_label));
196
197        gauge!(level: Level::DEBUG, metric_name, tags)
198    }
199
200    /// Registers a histogram at debug verbosity.
201    ///
202    /// The histogram will include the configured default tags for this builder.
203    pub fn register_debug_histogram(&self, metric_name: &'static str) -> Histogram {
204        histogram!(level: Level::DEBUG, metric_name, self.default_tags.iter())
205    }
206
207    /// Registers a histogram at debug verbosity with additional tags.
208    ///
209    /// The histogram will include the configured default tags for this builder, in addition to the additional tags provided.
210    ///
211    /// See [`add_default_tag`](MetricsBuilder::add_default_tag) for information on the supported tag formats.
212    pub fn register_debug_histogram_with_tags<I, T>(&self, metric_name: &'static str, additional_tags: I) -> Histogram
213    where
214        I: IntoIterator<Item = T>,
215        T: MetricTag,
216    {
217        let mut tags = (*self.default_tags).clone();
218        tags.extend(additional_tags.into_iter().map(MetricTag::into_label));
219
220        histogram!(level: Level::DEBUG, metric_name, tags)
221    }
222
223    /// Registers a counter at info verbosity.
224    ///
225    /// The counter will include the configured default tags for this builder.
226    pub fn register_counter(&self, metric_name: &'static str) -> Counter {
227        counter!(level: Level::INFO, metric_name, self.default_tags.iter())
228    }
229
230    /// Registers a counter at info verbosity with additional tags.
231    ///
232    /// The counter will include the configured default tags for this builder, in addition to the additional tags provided.
233    ///
234    /// See [`add_default_tag`](MetricsBuilder::add_default_tag) for information on the supported tag formats.
235    pub fn register_counter_with_tags<I, T>(&self, metric_name: &'static str, additional_tags: I) -> Counter
236    where
237        I: IntoIterator<Item = T>,
238        T: MetricTag,
239    {
240        let mut tags = (*self.default_tags).clone();
241        tags.extend(additional_tags.into_iter().map(MetricTag::into_label));
242
243        counter!(level: Level::INFO, metric_name, tags)
244    }
245
246    /// Registers a gauge at info verbosity.
247    ///
248    /// The gauge will include the configured default tags for this builder.
249    pub fn register_gauge(&self, metric_name: &'static str) -> Gauge {
250        gauge!(level: Level::INFO, metric_name, self.default_tags.iter())
251    }
252
253    /// Registers a gauge at info verbosity with additional tags.
254    ///
255    /// The gauge will include the configured default tags for this builder, in addition to the additional tags provided.
256    ///
257    /// See [`add_default_tag`](MetricsBuilder::add_default_tag) for information on the supported tag formats.
258    pub fn register_gauge_with_tags<I, T>(&self, metric_name: &'static str, additional_tags: I) -> Gauge
259    where
260        I: IntoIterator<Item = T>,
261        T: MetricTag,
262    {
263        let mut tags = (*self.default_tags).clone();
264        tags.extend(additional_tags.into_iter().map(MetricTag::into_label));
265
266        gauge!(level: Level::INFO, metric_name, tags)
267    }
268
269    /// Registers a histogram at info verbosity.
270    ///
271    /// The histogram will include the configured default tags for this builder.
272    pub fn register_histogram(&self, metric_name: &'static str) -> Histogram {
273        histogram!(level: Level::INFO, metric_name, self.default_tags.iter())
274    }
275
276    /// Registers a histogram at info verbosity with additional tags.
277    ///
278    /// The histogram will include the configured default tags for this builder, in addition to the additional tags provided.
279    ///
280    /// See [`add_default_tag`](MetricsBuilder::add_default_tag) for information on the supported tag formats.
281    pub fn register_histogram_with_tags<I, T>(&self, metric_name: &'static str, additional_tags: I) -> Histogram
282    where
283        I: IntoIterator<Item = T>,
284        T: MetricTag,
285    {
286        let mut tags = (*self.default_tags).clone();
287        tags.extend(additional_tags.into_iter().map(MetricTag::into_label));
288
289        histogram!(level: Level::INFO, metric_name, tags)
290    }
291}