1use std::collections::HashMap;
5use std::hash::Hasher;
6use std::sync::Arc;
7
8use fnv::FnvHasher;
9use parking_lot::RwLock;
10
11use crate::desc::{Desc, Describer};
12use crate::errors::{Error, Result};
13use crate::metrics::{Collector, Metric};
14use crate::proto::{MetricFamily, MetricType};
15
16pub trait MetricVecBuilder: Send + Sync + Clone {
18 type M: Metric;
20 type P: Describer + Sync + Send + Clone;
22
23 fn build(&self, _: &Self::P, _: &[&str]) -> Result<Self::M>;
25}
26
27#[derive(Debug)]
28pub(crate) struct MetricVecCore<T: MetricVecBuilder> {
29 pub children: RwLock<HashMap<u64, T::M>>,
30 pub desc: Desc,
31 pub metric_type: MetricType,
32 pub new_metric: T,
33 pub opts: T::P,
34}
35
36impl<T: MetricVecBuilder> MetricVecCore<T> {
37 pub fn collect(&self) -> MetricFamily {
38 let mut m = MetricFamily::default();
39 m.set_name(self.desc.fq_name.clone());
40 m.set_help(self.desc.help.clone());
41 m.set_field_type(self.metric_type);
42
43 let children = self.children.read();
44 let mut metrics = Vec::with_capacity(children.len());
45 for child in children.values() {
46 metrics.push(child.metric());
47 }
48 m.set_metric(from_vec!(metrics));
49 m
50 }
51
52 pub fn get_metric_with_label_values(&self, vals: &[&str]) -> Result<T::M> {
53 let h = self.hash_label_values(vals)?;
54
55 if let Some(metric) = self.children.read().get(&h).cloned() {
56 return Ok(metric);
57 }
58
59 self.get_or_create_metric(h, vals)
60 }
61
62 pub fn get_metric_with(&self, labels: &HashMap<&str, &str>) -> Result<T::M> {
63 let h = self.hash_labels(labels)?;
64
65 if let Some(metric) = self.children.read().get(&h).cloned() {
66 return Ok(metric);
67 }
68
69 let vals = self.get_label_values(labels)?;
70 self.get_or_create_metric(h, &vals)
71 }
72
73 pub fn delete_label_values(&self, vals: &[&str]) -> Result<()> {
74 let h = self.hash_label_values(vals)?;
75
76 let mut children = self.children.write();
77 if children.remove(&h).is_none() {
78 return Err(Error::Msg(format!("missing label values {:?}", vals)));
79 }
80
81 Ok(())
82 }
83
84 pub fn delete(&self, labels: &HashMap<&str, &str>) -> Result<()> {
85 let h = self.hash_labels(labels)?;
86
87 let mut children = self.children.write();
88 if children.remove(&h).is_none() {
89 return Err(Error::Msg(format!("missing labels {:?}", labels)));
90 }
91
92 Ok(())
93 }
94
95 pub fn reset(&self) {
97 self.children.write().clear();
98 }
99
100 pub(crate) fn hash_label_values(&self, vals: &[&str]) -> Result<u64> {
101 if vals.len() != self.desc.variable_labels.len() {
102 return Err(Error::InconsistentCardinality {
103 expect: self.desc.variable_labels.len(),
104 got: vals.len(),
105 });
106 }
107
108 let mut h = FnvHasher::default();
109 for val in vals {
110 h.write(val.as_bytes());
111 }
112
113 Ok(h.finish())
114 }
115
116 fn hash_labels(&self, labels: &HashMap<&str, &str>) -> Result<u64> {
117 if labels.len() != self.desc.variable_labels.len() {
118 return Err(Error::InconsistentCardinality {
119 expect: self.desc.variable_labels.len(),
120 got: labels.len(),
121 });
122 }
123
124 let mut h = FnvHasher::default();
125 for name in &self.desc.variable_labels {
126 match labels.get(&name.as_ref()) {
127 Some(val) => h.write(val.as_bytes()),
128 None => {
129 return Err(Error::Msg(format!(
130 "label name {} missing in label map",
131 name
132 )));
133 }
134 }
135 }
136
137 Ok(h.finish())
138 }
139
140 fn get_label_values<'a>(&self, labels: &'a HashMap<&str, &str>) -> Result<Vec<&'a str>> {
141 let mut values = Vec::new();
142 for name in &self.desc.variable_labels {
143 match labels.get(&name.as_ref()) {
144 Some(val) => values.push(*val),
145 None => {
146 return Err(Error::Msg(format!(
147 "label name {} missing in label map",
148 name
149 )));
150 }
151 }
152 }
153 Ok(values)
154 }
155
156 fn get_or_create_metric(&self, hash: u64, label_values: &[&str]) -> Result<T::M> {
157 let mut children = self.children.write();
158 if let Some(metric) = children.get(&hash).cloned() {
160 return Ok(metric);
161 }
162
163 let metric = self.new_metric.build(&self.opts, label_values)?;
164 children.insert(hash, metric.clone());
165 Ok(metric)
166 }
167}
168
169#[derive(Clone)]
175pub struct MetricVec<T: MetricVecBuilder> {
176 pub(crate) v: Arc<MetricVecCore<T>>,
177}
178
179impl<T: MetricVecBuilder> std::fmt::Debug for MetricVec<T> {
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 write!(f, "MetricVec")
182 }
183}
184
185impl<T: MetricVecBuilder> MetricVec<T> {
186 pub fn create(metric_type: MetricType, new_metric: T, opts: T::P) -> Result<MetricVec<T>> {
189 let desc = opts.describe()?;
190 let v = MetricVecCore {
191 children: RwLock::new(HashMap::new()),
192 desc,
193 metric_type,
194 new_metric,
195 opts,
196 };
197
198 Ok(MetricVec { v: Arc::new(v) })
199 }
200
201 pub fn get_metric_with_label_values(&self, vals: &[&str]) -> Result<T::M> {
225 self.v.get_metric_with_label_values(vals)
226 }
227
228 pub fn get_metric_with(&self, labels: &HashMap<&str, &str>) -> Result<T::M> {
241 self.v.get_metric_with(labels)
242 }
243
244 pub fn with_label_values(&self, vals: &[&str]) -> T::M {
258 self.get_metric_with_label_values(vals).unwrap()
259 }
260
261 pub fn with(&self, labels: &HashMap<&str, &str>) -> T::M {
265 self.get_metric_with(labels).unwrap()
266 }
267
268 pub fn remove_label_values(&self, vals: &[&str]) -> Result<()> {
281 self.v.delete_label_values(vals)
282 }
283
284 pub fn remove(&self, labels: &HashMap<&str, &str>) -> Result<()> {
293 self.v.delete(labels)
294 }
295
296 pub fn reset(&self) {
298 self.v.reset()
299 }
300}
301
302impl<T: MetricVecBuilder> Collector for MetricVec<T> {
303 fn desc(&self) -> Vec<&Desc> {
304 vec![&self.v.desc]
305 }
306
307 fn collect(&self) -> Vec<MetricFamily> {
308 vec![self.v.collect()]
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use std::collections::HashMap;
315
316 use crate::counter::CounterVec;
317 use crate::gauge::GaugeVec;
318 use crate::metrics::{Metric, Opts};
319
320 #[test]
321 fn test_counter_vec_with_labels() {
322 let vec = CounterVec::new(
323 Opts::new("test_couter_vec", "test counter vec help"),
324 &["l1", "l2"],
325 )
326 .unwrap();
327
328 let mut labels = HashMap::new();
329 labels.insert("l1", "v1");
330 labels.insert("l2", "v2");
331 assert!(vec.remove(&labels).is_err());
332
333 vec.with(&labels).inc();
334 assert!(vec.remove(&labels).is_ok());
335 assert!(vec.remove(&labels).is_err());
336
337 let mut labels2 = HashMap::new();
338 labels2.insert("l1", "v2");
339 labels2.insert("l2", "v1");
340
341 vec.with(&labels).inc();
342 assert!(vec.remove(&labels2).is_err());
343
344 vec.with(&labels).inc();
345
346 let mut labels3 = HashMap::new();
347 labels3.insert("l1", "v1");
348 assert!(vec.remove(&labels3).is_err());
349 }
350
351 #[test]
352 fn test_counter_vec_with_label_values() {
353 let vec = CounterVec::new(
354 Opts::new("test_vec", "test counter vec help"),
355 &["l1", "l2"],
356 )
357 .unwrap();
358
359 assert!(vec.remove_label_values(&["v1", "v2"]).is_err());
360 vec.with_label_values(&["v1", "v2"]).inc();
361 assert!(vec.remove_label_values(&["v1", "v2"]).is_ok());
362
363 vec.with_label_values(&["v1", "v2"]).inc();
364 assert!(vec.remove_label_values(&["v1"]).is_err());
365 assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
366 }
367
368 #[test]
369 fn test_gauge_vec_with_labels() {
370 let vec = GaugeVec::new(
371 Opts::new("test_gauge_vec", "test gauge vec help"),
372 &["l1", "l2"],
373 )
374 .unwrap();
375
376 let mut labels = HashMap::new();
377 labels.insert("l1", "v1");
378 labels.insert("l2", "v2");
379 assert!(vec.remove(&labels).is_err());
380
381 vec.with(&labels).inc();
382 vec.with(&labels).dec();
383 vec.with(&labels).add(42.0);
384 vec.with(&labels).sub(42.0);
385 vec.with(&labels).set(42.0);
386
387 assert!(vec.remove(&labels).is_ok());
388 assert!(vec.remove(&labels).is_err());
389 }
390
391 #[test]
392 fn test_gauge_vec_with_label_values() {
393 let vec = GaugeVec::new(
394 Opts::new("test_gauge_vec", "test gauge vec help"),
395 &["l1", "l2"],
396 )
397 .unwrap();
398
399 assert!(vec.remove_label_values(&["v1", "v2"]).is_err());
400 vec.with_label_values(&["v1", "v2"]).inc();
401 assert!(vec.remove_label_values(&["v1", "v2"]).is_ok());
402
403 vec.with_label_values(&["v1", "v2"]).inc();
404 vec.with_label_values(&["v1", "v2"]).dec();
405 vec.with_label_values(&["v1", "v2"]).add(42.0);
406 vec.with_label_values(&["v1", "v2"]).sub(42.0);
407 vec.with_label_values(&["v1", "v2"]).set(42.0);
408
409 assert!(vec.remove_label_values(&["v1"]).is_err());
410 assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
411 }
412
413 #[test]
414 fn test_vec_get_metric_with() {
415 let vec = CounterVec::new(
416 Opts::new("test_vec", "test counter vec help"),
417 &["b", "c", "a"],
418 )
419 .unwrap();
420
421 let mut labels = HashMap::new();
423 labels.insert("a", "b");
424 labels.insert("b", "c");
425 labels.insert("c", "a");
426 let c = vec.get_metric_with(&labels).unwrap();
427 let m = c.metric();
428 let label_pairs = m.get_label();
429 assert_eq!(label_pairs.len(), labels.len());
430 for lp in label_pairs.iter() {
431 assert_eq!(lp.get_value(), labels[lp.get_name()]);
432 }
433 }
434}