1use std::collections::HashMap;
5use std::hash::{BuildHasher, 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::nohash::BuildNoHashHasher;
15use crate::proto::{MetricFamily, MetricType};
16
17pub trait MetricVecBuilder: Send + Sync + Clone {
19 type M: Metric;
21 type P: Describer + Sync + Send + Clone;
23
24 fn build<V: AsRef<str>>(&self, _: &Self::P, _: &[V]) -> Result<Self::M>;
26}
27
28#[derive(Debug)]
29pub(crate) struct MetricVecCore<T: MetricVecBuilder> {
30 pub children: RwLock<HashMap<u64, T::M, BuildNoHashHasher>>,
32 pub desc: Desc,
33 pub metric_type: MetricType,
34 pub new_metric: T,
35 pub opts: T::P,
36}
37
38impl<T: MetricVecBuilder> MetricVecCore<T> {
39 pub fn collect(&self) -> MetricFamily {
40 let mut m = MetricFamily::default();
41 m.set_name(self.desc.fq_name.clone());
42 m.set_help(self.desc.help.clone());
43 m.set_field_type(self.metric_type);
44
45 let children = self.children.read();
46 let mut metrics = Vec::with_capacity(children.len());
47 for child in children.values() {
48 metrics.push(child.metric());
49 }
50 m.set_metric(metrics);
51 m
52 }
53
54 pub fn get_metric_with_label_values<V>(&self, vals: &[V]) -> Result<T::M>
55 where
56 V: AsRef<str> + std::fmt::Debug,
57 {
58 let h = self.hash_label_values(vals)?;
59
60 if let Some(metric) = self.children.read().get(&h).cloned() {
61 return Ok(metric);
62 }
63
64 self.get_or_create_metric(h, vals)
65 }
66
67 pub fn get_metric_with<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<T::M>
68 where
69 V: AsRef<str> + std::fmt::Debug,
70 {
71 let h = self.hash_labels(labels)?;
72
73 if let Some(metric) = self.children.read().get(&h).cloned() {
74 return Ok(metric);
75 }
76
77 let vals = self.get_label_values(labels)?;
78 self.get_or_create_metric(h, &vals)
79 }
80
81 pub fn delete_label_values<V>(&self, vals: &[V]) -> Result<()>
82 where
83 V: AsRef<str> + std::fmt::Debug,
84 {
85 let h = self.hash_label_values(vals)?;
86
87 let mut children = self.children.write();
88 if children.remove(&h).is_none() {
89 return Err(Error::Msg(format!("missing label values {:?}", vals)));
90 }
91
92 Ok(())
93 }
94
95 pub fn delete<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<()>
96 where
97 V: AsRef<str> + std::fmt::Debug,
98 {
99 let h = self.hash_labels(labels)?;
100
101 let mut children = self.children.write();
102 if children.remove(&h).is_none() {
103 return Err(Error::Msg(format!("missing labels {:?}", labels)));
104 }
105
106 Ok(())
107 }
108
109 pub fn reset(&self) {
111 self.children.write().clear();
112 }
113
114 pub(crate) fn hash_label_values<V>(&self, vals: &[V]) -> Result<u64>
115 where
116 V: AsRef<str> + std::fmt::Debug,
117 {
118 if vals.len() != self.desc.variable_labels.len() {
119 return Err(Error::InconsistentCardinality {
120 expect: self.desc.variable_labels.len(),
121 got: vals.len(),
122 });
123 }
124
125 let mut h = FnvHasher::default();
126 for val in vals {
127 h.write(val.as_ref().as_bytes());
128 }
129
130 Ok(h.finish())
131 }
132
133 fn hash_labels<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<u64>
134 where
135 V: AsRef<str> + std::fmt::Debug,
136 {
137 if labels.len() != self.desc.variable_labels.len() {
138 return Err(Error::InconsistentCardinality {
139 expect: self.desc.variable_labels.len(),
140 got: labels.len(),
141 });
142 }
143
144 let mut h = FnvHasher::default();
145 for name in &self.desc.variable_labels {
146 match labels.get(&name.as_ref()) {
147 Some(val) => h.write(val.as_ref().as_bytes()),
148 None => {
149 return Err(Error::Msg(format!(
150 "label name {} missing in label map",
151 name
152 )));
153 }
154 }
155 }
156
157 Ok(h.finish())
158 }
159
160 fn get_label_values<'a, V, S: BuildHasher>(
161 &'a self,
162 labels: &'a HashMap<&str, V, S>,
163 ) -> Result<Vec<&'a str>>
164 where
165 V: AsRef<str> + std::fmt::Debug,
166 {
167 let mut values = Vec::new();
168 for name in &self.desc.variable_labels {
169 match labels.get(&name.as_ref()) {
170 Some(val) => values.push(val.as_ref()),
171 None => {
172 return Err(Error::Msg(format!(
173 "label name {} missing in label map",
174 name
175 )));
176 }
177 }
178 }
179 Ok(values)
180 }
181
182 fn get_or_create_metric<V>(&self, hash: u64, label_values: &[V]) -> Result<T::M>
183 where
184 V: AsRef<str> + std::fmt::Debug,
185 {
186 let mut children = self.children.write();
187 if let Some(metric) = children.get(&hash).cloned() {
189 return Ok(metric);
190 }
191
192 let metric = self.new_metric.build(&self.opts, label_values)?;
193 children.insert(hash, metric.clone());
194 Ok(metric)
195 }
196}
197
198#[derive(Clone)]
204pub struct MetricVec<T: MetricVecBuilder> {
205 pub(crate) v: Arc<MetricVecCore<T>>,
206}
207
208impl<T: MetricVecBuilder> std::fmt::Debug for MetricVec<T> {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 write!(f, "MetricVec")
211 }
212}
213
214impl<T: MetricVecBuilder> MetricVec<T> {
215 pub fn create(metric_type: MetricType, new_metric: T, opts: T::P) -> Result<MetricVec<T>> {
218 let desc = opts.describe()?;
219 let v = MetricVecCore {
220 children: RwLock::new(HashMap::default()),
221 desc,
222 metric_type,
223 new_metric,
224 opts,
225 };
226
227 Ok(MetricVec { v: Arc::new(v) })
228 }
229
230 pub fn get_metric_with_label_values<V>(&self, vals: &[V]) -> Result<T::M>
254 where
255 V: AsRef<str> + std::fmt::Debug,
256 {
257 self.v.get_metric_with_label_values(vals)
258 }
259
260 pub fn get_metric_with<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<T::M>
273 where
274 V: AsRef<str> + std::fmt::Debug,
275 {
276 self.v.get_metric_with(labels)
277 }
278
279 pub fn with_label_values<V>(&self, vals: &[V]) -> T::M
293 where
294 V: AsRef<str> + std::fmt::Debug,
295 {
296 self.get_metric_with_label_values(vals).unwrap()
297 }
298
299 pub fn with<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> T::M
303 where
304 V: AsRef<str> + std::fmt::Debug,
305 {
306 self.get_metric_with(labels).unwrap()
307 }
308
309 pub fn remove_label_values<V>(&self, vals: &[V]) -> Result<()>
322 where
323 V: AsRef<str> + std::fmt::Debug,
324 {
325 self.v.delete_label_values(vals)
326 }
327
328 pub fn remove<V, S: BuildHasher>(&self, labels: &HashMap<&str, V, S>) -> Result<()>
337 where
338 V: AsRef<str> + std::fmt::Debug,
339 {
340 self.v.delete(labels)
341 }
342
343 pub fn reset(&self) {
345 self.v.reset()
346 }
347}
348
349impl<T: MetricVecBuilder> Collector for MetricVec<T> {
350 fn desc(&self) -> Vec<&Desc> {
351 vec![&self.v.desc]
352 }
353
354 fn collect(&self) -> Vec<MetricFamily> {
355 vec![self.v.collect()]
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use std::collections::HashMap;
362
363 use crate::counter::CounterVec;
364 use crate::gauge::GaugeVec;
365 use crate::metrics::{Metric, Opts};
366
367 #[test]
368 fn test_counter_vec_with_labels() {
369 let vec = CounterVec::new(
370 Opts::new("test_couter_vec", "test counter vec help"),
371 &["l1", "l2"],
372 )
373 .unwrap();
374
375 let mut labels = HashMap::new();
376 labels.insert("l1", "v1");
377 labels.insert("l2", "v2");
378 assert!(vec.remove(&labels).is_err());
379
380 vec.with(&labels).inc();
381 assert!(vec.remove(&labels).is_ok());
382 assert!(vec.remove(&labels).is_err());
383
384 let mut labels2 = HashMap::new();
385 labels2.insert("l1", "v2");
386 labels2.insert("l2", "v1");
387
388 vec.with(&labels).inc();
389 assert!(vec.remove(&labels2).is_err());
390
391 vec.with(&labels).inc();
392
393 let mut labels3 = HashMap::new();
394 labels3.insert("l1", "v1");
395 assert!(vec.remove(&labels3).is_err());
396 }
397
398 #[test]
399 fn test_counter_vec_with_owned_labels() {
400 let vec = CounterVec::new(
401 Opts::new("test_couter_vec", "test counter vec help"),
402 &["l1", "l2"],
403 )
404 .unwrap();
405
406 let v1 = "v1".to_string();
407 let v2 = "v2".to_string();
408
409 let mut labels = HashMap::new();
410 labels.insert("l1", v1.clone());
411 labels.insert("l2", v2.clone());
412 assert!(vec.remove(&labels).is_err());
413
414 vec.with(&labels).inc();
415 assert!(vec.remove(&labels).is_ok());
416 assert!(vec.remove(&labels).is_err());
417
418 let mut labels2 = HashMap::new();
419 labels2.insert("l1", v2.clone());
420 labels2.insert("l2", v1.clone());
421
422 vec.with(&labels).inc();
423 assert!(vec.remove(&labels2).is_err());
424
425 vec.with(&labels).inc();
426
427 let mut labels3 = HashMap::new();
428 labels3.insert("l1", v1.clone());
429 assert!(vec.remove(&labels3).is_err());
430 }
431
432 #[test]
433 fn test_counter_vec_with_label_values() {
434 let vec = CounterVec::new(
435 Opts::new("test_vec", "test counter vec help"),
436 &["l1", "l2"],
437 )
438 .unwrap();
439
440 assert!(vec.remove_label_values(&["v1", "v2"]).is_err());
441 vec.with_label_values(&["v1", "v2"]).inc();
442 assert!(vec.remove_label_values(&["v1", "v2"]).is_ok());
443
444 vec.with_label_values(&["v1", "v2"]).inc();
445 assert!(vec.remove_label_values(&["v1"]).is_err());
446 assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
447 }
448
449 #[test]
450 fn test_counter_vec_with_owned_label_values() {
451 let vec = CounterVec::new(
452 Opts::new("test_vec", "test counter vec help"),
453 &["l1", "l2"],
454 )
455 .unwrap();
456
457 let v1 = "v1".to_string();
458 let v2 = "v2".to_string();
459 let v3 = "v3".to_string();
460
461 assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_err());
462 vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
463 assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_ok());
464
465 vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
466 assert!(vec.remove_label_values(&[v1.clone()]).is_err());
467 assert!(vec.remove_label_values(&[v1.clone(), v3.clone()]).is_err());
468 }
469
470 #[test]
471 fn test_gauge_vec_with_labels() {
472 let vec = GaugeVec::new(
473 Opts::new("test_gauge_vec", "test gauge vec help"),
474 &["l1", "l2"],
475 )
476 .unwrap();
477
478 let mut labels = HashMap::new();
479 labels.insert("l1", "v1");
480 labels.insert("l2", "v2");
481 assert!(vec.remove(&labels).is_err());
482
483 vec.with(&labels).inc();
484 vec.with(&labels).dec();
485 vec.with(&labels).add(42.0);
486 vec.with(&labels).sub(42.0);
487 vec.with(&labels).set(42.0);
488
489 assert!(vec.remove(&labels).is_ok());
490 assert!(vec.remove(&labels).is_err());
491 }
492
493 #[test]
494 fn test_gauge_vec_with_owned_labels() {
495 let vec = GaugeVec::new(
496 Opts::new("test_gauge_vec", "test gauge vec help"),
497 &["l1", "l2"],
498 )
499 .unwrap();
500
501 let v1 = "v1".to_string();
502 let v2 = "v2".to_string();
503
504 let mut labels = HashMap::new();
505 labels.insert("l1", v1.clone());
506 labels.insert("l2", v2.clone());
507 assert!(vec.remove(&labels).is_err());
508
509 vec.with(&labels).inc();
510 vec.with(&labels).dec();
511 vec.with(&labels).add(42.0);
512 vec.with(&labels).sub(42.0);
513 vec.with(&labels).set(42.0);
514
515 assert!(vec.remove(&labels).is_ok());
516 assert!(vec.remove(&labels).is_err());
517 }
518
519 #[test]
520 fn test_gauge_vec_with_label_values() {
521 let vec = GaugeVec::new(
522 Opts::new("test_gauge_vec", "test gauge vec help"),
523 &["l1", "l2"],
524 )
525 .unwrap();
526
527 assert!(vec.remove_label_values(&["v1", "v2"]).is_err());
528 vec.with_label_values(&["v1", "v2"]).inc();
529 assert!(vec.remove_label_values(&["v1", "v2"]).is_ok());
530
531 vec.with_label_values(&["v1", "v2"]).inc();
532 vec.with_label_values(&["v1", "v2"]).dec();
533 vec.with_label_values(&["v1", "v2"]).add(42.0);
534 vec.with_label_values(&["v1", "v2"]).sub(42.0);
535 vec.with_label_values(&["v1", "v2"]).set(42.0);
536
537 assert!(vec.remove_label_values(&["v1"]).is_err());
538 assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
539 }
540
541 #[test]
542 fn test_gauge_vec_with_owned_label_values() {
543 let vec = GaugeVec::new(
544 Opts::new("test_gauge_vec", "test gauge vec help"),
545 &["l1", "l2"],
546 )
547 .unwrap();
548
549 let v1 = "v1".to_string();
550 let v2 = "v2".to_string();
551 let v3 = "v3".to_string();
552
553 assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_err());
554 vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
555 assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_ok());
556
557 vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
558 vec.with_label_values(&[v1.clone(), v2.clone()]).dec();
559 vec.with_label_values(&[v1.clone(), v2.clone()]).add(42.0);
560 vec.with_label_values(&[v1.clone(), v2.clone()]).sub(42.0);
561 vec.with_label_values(&[v1.clone(), v2.clone()]).set(42.0);
562
563 assert!(vec.remove_label_values(&[v1.clone()]).is_err());
564 assert!(vec.remove_label_values(&[v1.clone(), v3.clone()]).is_err());
565 }
566
567 #[test]
568 fn test_vec_get_metric_with() {
569 let vec = CounterVec::new(
570 Opts::new("test_vec", "test counter vec help"),
571 &["b", "c", "a"],
572 )
573 .unwrap();
574
575 let mut labels = HashMap::new();
577 labels.insert("a", "b");
578 labels.insert("b", "c");
579 labels.insert("c", "a");
580 let c = vec.get_metric_with(&labels).unwrap();
581 let m = c.metric();
582 let label_pairs = m.get_label();
583 assert_eq!(label_pairs.len(), labels.len());
584 for lp in label_pairs.iter() {
585 assert_eq!(lp.value(), labels[lp.name()]);
586 }
587 }
588}