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}