1use std::cell::RefCell;
5use std::collections::HashMap;
6use std::marker::PhantomData;
7use std::sync::Arc;
8
9use crate::atomic64::{Atomic, AtomicF64, AtomicU64, Number};
10use crate::desc::Desc;
11use crate::errors::Result;
12use crate::metrics::{Collector, LocalMetric, Metric, Opts};
13use crate::proto;
14use crate::value::{Value, ValueType};
15use crate::vec::{MetricVec, MetricVecBuilder};
16
17#[derive(Debug)]
19pub struct GenericCounter<P: Atomic> {
20 v: Arc<Value<P>>,
21}
22
23pub type Counter = GenericCounter<AtomicF64>;
25
26pub type IntCounter = GenericCounter<AtomicU64>;
29
30impl<P: Atomic> Clone for GenericCounter<P> {
31 fn clone(&self) -> Self {
32 Self {
33 v: Arc::clone(&self.v),
34 }
35 }
36}
37
38impl<P: Atomic> GenericCounter<P> {
39 pub fn new<S1: Into<String>, S2: Into<String>>(name: S1, help: S2) -> Result<Self> {
41 let opts = Opts::new(name, help);
42 Self::with_opts(opts)
43 }
44
45 pub fn with_opts(opts: Opts) -> Result<Self> {
47 Self::with_opts_and_label_values::<&str>(&opts, &[])
48 }
49
50 fn with_opts_and_label_values<V: AsRef<str>>(opts: &Opts, label_values: &[V]) -> Result<Self> {
51 let v = Value::new(opts, ValueType::Counter, P::T::from_i64(0), label_values)?;
52 Ok(Self { v: Arc::new(v) })
53 }
54
55 #[inline]
61 pub fn inc_by(&self, v: P::T) {
62 debug_assert!(v >= P::T::from_i64(0));
63 self.v.inc_by(v);
64 }
65
66 #[inline]
68 pub fn inc(&self) {
69 self.v.inc();
70 }
71
72 #[inline]
74 pub fn get(&self) -> P::T {
75 self.v.get()
76 }
77
78 #[inline]
80 pub fn reset(&self) {
81 self.v.set(P::T::from_i64(0))
82 }
83
84 pub fn local(&self) -> GenericLocalCounter<P> {
86 GenericLocalCounter::new(self.clone())
87 }
88}
89
90impl<P: Atomic> Collector for GenericCounter<P> {
91 fn desc(&self) -> Vec<&Desc> {
92 vec![&self.v.desc]
93 }
94
95 fn collect(&self) -> Vec<proto::MetricFamily> {
96 vec![self.v.collect()]
97 }
98}
99
100impl<P: Atomic> Metric for GenericCounter<P> {
101 fn metric(&self) -> proto::Metric {
102 self.v.metric()
103 }
104}
105
106#[derive(Debug)]
107pub struct CounterVecBuilder<P: Atomic> {
108 _phantom: PhantomData<P>,
109}
110
111impl<P: Atomic> CounterVecBuilder<P> {
112 pub fn new() -> Self {
113 Self {
114 _phantom: PhantomData,
115 }
116 }
117}
118
119impl<P: Atomic> Clone for CounterVecBuilder<P> {
120 fn clone(&self) -> Self {
121 Self::new()
122 }
123}
124
125impl<P: Atomic> MetricVecBuilder for CounterVecBuilder<P> {
126 type M = GenericCounter<P>;
127 type P = Opts;
128
129 fn build<V: AsRef<str>>(&self, opts: &Opts, vals: &[V]) -> Result<Self::M> {
130 Self::M::with_opts_and_label_values(opts, vals)
131 }
132}
133
134pub type GenericCounterVec<P> = MetricVec<CounterVecBuilder<P>>;
136
137pub type CounterVec = GenericCounterVec<AtomicF64>;
142
143pub type IntCounterVec = GenericCounterVec<AtomicU64>;
146
147impl<P: Atomic> GenericCounterVec<P> {
148 pub fn new(opts: Opts, label_names: &[&str]) -> Result<Self> {
152 let variable_names = label_names.iter().map(|s| (*s).to_owned()).collect();
153 let opts = opts.variable_labels(variable_names);
154 let metric_vec =
155 MetricVec::create(proto::MetricType::COUNTER, CounterVecBuilder::new(), opts)?;
156
157 Ok(metric_vec as Self)
158 }
159
160 pub fn local(&self) -> GenericLocalCounterVec<P> {
162 GenericLocalCounterVec::new(self.clone())
163 }
164}
165
166#[derive(Debug)]
169pub struct GenericLocalCounter<P: Atomic> {
170 counter: GenericCounter<P>,
171 val: RefCell<P::T>,
172}
173
174pub trait CounterWithValueType {
176 type ValueType: Atomic;
178}
179
180impl<P: Atomic> CounterWithValueType for GenericLocalCounter<P> {
181 type ValueType = P;
182}
183
184pub type LocalCounter = GenericLocalCounter<AtomicF64>;
186
187pub type LocalIntCounter = GenericLocalCounter<AtomicU64>;
190
191impl<P: Atomic> GenericLocalCounter<P> {
192 fn new(counter: GenericCounter<P>) -> Self {
193 Self {
194 counter,
195 val: RefCell::new(P::T::from_i64(0)),
196 }
197 }
198
199 #[inline]
205 pub fn inc_by(&self, v: P::T) {
206 debug_assert!(v >= P::T::from_i64(0));
207 *self.val.borrow_mut() += v;
208 }
209
210 #[inline]
212 pub fn inc(&self) {
213 *self.val.borrow_mut() += P::T::from_i64(1);
214 }
215
216 #[inline]
218 pub fn get(&self) -> P::T {
219 *self.val.borrow()
220 }
221
222 #[inline]
224 pub fn reset(&self) {
225 *self.val.borrow_mut() = P::T::from_i64(0);
226 }
227
228 #[inline]
230 pub fn flush(&self) {
231 if *self.val.borrow() == P::T::from_i64(0) {
232 return;
233 }
234 self.counter.inc_by(*self.val.borrow());
235 *self.val.borrow_mut() = P::T::from_i64(0);
236 }
237}
238
239impl<P: Atomic> LocalMetric for GenericLocalCounter<P> {
240 #[inline]
242 fn flush(&self) {
243 GenericLocalCounter::flush(self);
244 }
245}
246
247impl<P: Atomic> Clone for GenericLocalCounter<P> {
248 fn clone(&self) -> Self {
249 Self::new(self.counter.clone())
250 }
251}
252
253pub struct GenericLocalCounterVec<P: Atomic> {
256 vec: GenericCounterVec<P>,
257 local: HashMap<u64, GenericLocalCounter<P>>,
258}
259
260impl<P: Atomic> std::fmt::Debug for GenericLocalCounterVec<P> {
261 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
262 write!(
263 f,
264 "GenericLocalCounterVec ({} locals)",
265 self.local.keys().len()
266 )
267 }
268}
269
270pub type LocalCounterVec = GenericLocalCounterVec<AtomicF64>;
272
273pub type LocalIntCounterVec = GenericLocalCounterVec<AtomicU64>;
277
278impl<P: Atomic> GenericLocalCounterVec<P> {
279 fn new(vec: GenericCounterVec<P>) -> Self {
280 let local = HashMap::with_capacity(vec.v.children.read().len());
281 Self { vec, local }
282 }
283
284 pub fn with_label_values<'a>(&'a mut self, vals: &[&str]) -> &'a mut GenericLocalCounter<P> {
287 let hash = self.vec.v.hash_label_values(vals).unwrap();
288 let vec = &self.vec;
289 self.local
290 .entry(hash)
291 .or_insert_with(|| vec.with_label_values(vals).local())
292 }
293
294 pub fn remove_label_values(&mut self, vals: &[&str]) -> Result<()> {
297 let hash = self.vec.v.hash_label_values(vals)?;
298 self.local.remove(&hash);
299 self.vec.v.delete_label_values(vals)
300 }
301
302 pub fn flush(&self) {
304 for h in self.local.values() {
305 h.flush();
306 }
307 }
308}
309
310impl<P: Atomic> LocalMetric for GenericLocalCounterVec<P> {
311 fn flush(&self) {
313 GenericLocalCounterVec::flush(self);
314 }
315}
316
317impl<P: Atomic> Clone for GenericLocalCounterVec<P> {
318 fn clone(&self) -> Self {
319 Self::new(self.vec.clone())
320 }
321}
322
323#[cfg(test)]
324mod tests {
325 use std::collections::HashMap;
326 use std::f64;
327
328 use super::*;
329 use crate::metrics::{Collector, Opts};
330 #[cfg(feature = "protobuf")]
331 use crate::proto_ext::MessageFieldExt;
332
333 #[test]
334 fn test_counter() {
335 let opts = Opts::new("test", "test help")
336 .const_label("a", "1")
337 .const_label("b", "2");
338 let counter = Counter::with_opts(opts).unwrap();
339 counter.inc();
340 assert_eq!(counter.get() as u64, 1);
341 counter.inc_by(42.0);
342 assert_eq!(counter.get() as u64, 43);
343
344 let mut mfs = counter.collect();
345 assert_eq!(mfs.len(), 1);
346
347 let mf = mfs.pop().unwrap();
348 let m = mf.get_metric().first().unwrap();
349 assert_eq!(m.get_label().len(), 2);
350 assert_eq!(m.get_counter().get_value() as u64, 43);
351
352 counter.reset();
353 assert_eq!(counter.get() as u64, 0);
354 }
355
356 #[test]
357 fn test_int_counter() {
358 let counter = IntCounter::new("foo", "bar").unwrap();
359 counter.inc();
360 assert_eq!(counter.get(), 1);
361 counter.inc_by(11);
362 assert_eq!(counter.get(), 12);
363
364 let mut mfs = counter.collect();
365 assert_eq!(mfs.len(), 1);
366
367 let mf = mfs.pop().unwrap();
368 let m = mf.get_metric().first().unwrap();
369 assert_eq!(m.get_label().len(), 0);
370 assert_eq!(m.get_counter().get_value() as u64, 12);
371
372 counter.reset();
373 assert_eq!(counter.get(), 0);
374 }
375
376 #[test]
377 fn test_local_counter() {
378 let counter = Counter::new("counter", "counter helper").unwrap();
379 let local_counter1 = counter.local();
380 let local_counter2 = counter.local();
381
382 local_counter1.inc();
383 local_counter2.inc();
384 assert_eq!(local_counter1.get() as u64, 1);
385 assert_eq!(local_counter2.get() as u64, 1);
386 assert_eq!(counter.get() as u64, 0);
387 local_counter1.flush();
388 assert_eq!(local_counter1.get() as u64, 0);
389 assert_eq!(counter.get() as u64, 1);
390 local_counter2.flush();
391 assert_eq!(counter.get() as u64, 2);
392
393 local_counter1.reset();
394 local_counter2.reset();
395 counter.reset();
396 assert_eq!(counter.get() as u64, 0);
397 local_counter1.flush();
398 assert_eq!(counter.get() as u64, 0);
399 local_counter2.flush();
400 assert_eq!(counter.get() as u64, 0);
401 }
402
403 #[test]
404 fn test_int_local_counter() {
405 let counter = IntCounter::new("foo", "bar").unwrap();
406 let local_counter = counter.local();
407
408 local_counter.inc();
409 assert_eq!(local_counter.get(), 1);
410 assert_eq!(counter.get(), 0);
411
412 local_counter.inc_by(5);
413 local_counter.flush();
414 assert_eq!(local_counter.get(), 0);
415 assert_eq!(counter.get(), 6);
416
417 local_counter.reset();
418 counter.reset();
419 assert_eq!(counter.get(), 0);
420 local_counter.flush();
421 assert_eq!(counter.get(), 0);
422 }
423
424 #[test]
425 fn test_counter_vec_with_labels() {
426 let vec = CounterVec::new(
427 Opts::new("test_couter_vec", "test counter vec help"),
428 &["l1", "l2"],
429 )
430 .unwrap();
431
432 let mut labels = HashMap::new();
433 labels.insert("l1", "v1");
434 labels.insert("l2", "v2");
435 assert!(vec.remove(&labels).is_err());
436
437 vec.with(&labels).inc();
438 assert!(vec.remove(&labels).is_ok());
439 assert!(vec.remove(&labels).is_err());
440
441 let mut labels2 = HashMap::new();
442 labels2.insert("l1", "v2");
443 labels2.insert("l2", "v1");
444
445 vec.with(&labels).inc();
446 assert!(vec.remove(&labels2).is_err());
447
448 vec.with(&labels).inc();
449
450 let mut labels3 = HashMap::new();
451 labels3.insert("l1", "v1");
452 assert!(vec.remove(&labels3).is_err());
453 }
454
455 #[test]
456 fn test_counter_vec_with_owned_labels() {
457 let vec = CounterVec::new(
458 Opts::new("test_couter_vec", "test counter vec help"),
459 &["l1", "l2"],
460 )
461 .unwrap();
462
463 let v1 = "v1".to_string();
464 let v2 = "v2".to_string();
465
466 let mut labels = HashMap::new();
467 labels.insert("l1", v1.clone());
468 labels.insert("l2", v2.clone());
469 assert!(vec.remove(&labels).is_err());
470
471 vec.with(&labels).inc();
472 assert!(vec.remove(&labels).is_ok());
473 assert!(vec.remove(&labels).is_err());
474
475 let mut labels2 = HashMap::new();
476 labels2.insert("l1", v2.clone());
477 labels2.insert("l2", v1.clone());
478
479 vec.with(&labels).inc();
480 assert!(vec.remove(&labels2).is_err());
481
482 vec.with(&labels).inc();
483
484 let mut labels3 = HashMap::new();
485 labels3.insert("l1", v1.clone());
486 assert!(vec.remove(&labels3).is_err());
487 }
488
489 #[test]
490 fn test_int_counter_vec() {
491 let vec = IntCounterVec::new(Opts::new("foo", "bar"), &["l1", "l2"]).unwrap();
492
493 vec.with_label_values(&["v1", "v3"]).inc();
494 assert_eq!(vec.with_label_values(&["v1", "v3"]).get(), 1);
495
496 vec.with_label_values(&["v1", "v2"]).inc_by(12);
497 assert_eq!(vec.with_label_values(&["v1", "v3"]).get(), 1);
498 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 12);
499
500 vec.with_label_values(&["v4", "v2"]).inc_by(2);
501 assert_eq!(vec.with_label_values(&["v1", "v3"]).get(), 1);
502 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 12);
503 assert_eq!(vec.with_label_values(&["v4", "v2"]).get(), 2);
504
505 vec.with_label_values(&["v1", "v3"]).inc_by(5);
506 assert_eq!(vec.with_label_values(&["v1", "v3"]).get(), 6);
507 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 12);
508 assert_eq!(vec.with_label_values(&["v4", "v2"]).get(), 2);
509 }
510
511 #[test]
512 fn test_counter_vec_with_label_values() {
513 let vec = CounterVec::new(
514 Opts::new("test_vec", "test counter vec help"),
515 &["l1", "l2"],
516 )
517 .unwrap();
518
519 assert!(vec.remove_label_values(&["v1", "v2"]).is_err());
520 vec.with_label_values(&["v1", "v2"]).inc();
521 assert!(vec.remove_label_values(&["v1", "v2"]).is_ok());
522
523 vec.with_label_values(&["v1", "v2"]).inc();
524 assert!(vec.remove_label_values(&["v1"]).is_err());
525 assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
526 }
527
528 #[test]
529 fn test_counter_vec_with_owned_label_values() {
530 let vec = CounterVec::new(
531 Opts::new("test_vec", "test counter vec help"),
532 &["l1", "l2"],
533 )
534 .unwrap();
535
536 let v1 = "v1".to_string();
537 let v2 = "v2".to_string();
538 let v3 = "v3".to_string();
539
540 assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_err());
541 vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
542 assert!(vec.remove_label_values(&[v1.clone(), v2.clone()]).is_ok());
543
544 vec.with_label_values(&[v1.clone(), v2.clone()]).inc();
545 assert!(vec.remove_label_values(&[v1.clone()]).is_err());
546 assert!(vec.remove_label_values(&[v1.clone(), v3.clone()]).is_err());
547 }
548
549 #[test]
550 fn test_counter_vec_local() {
551 let vec = CounterVec::new(
552 Opts::new("test_vec_local", "test counter vec help"),
553 &["l1", "l2"],
554 )
555 .unwrap();
556 let mut local_vec_1 = vec.local();
557 let mut local_vec_2 = local_vec_1.clone();
558
559 assert!(local_vec_1.remove_label_values(&["v1", "v2"]).is_err());
560
561 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(23.0);
562 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 23.0) <= f64::EPSILON);
563 assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
564
565 local_vec_1.flush();
566 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
567 assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= f64::EPSILON);
568
569 local_vec_1.flush();
570 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
571 assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= f64::EPSILON);
572
573 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(11.0);
574 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 11.0) <= f64::EPSILON);
575 assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= f64::EPSILON);
576
577 local_vec_1.flush();
578 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
579 assert!((vec.with_label_values(&["v1", "v2"]).get() - 34.0) <= f64::EPSILON);
580
581 assert!(local_vec_1.remove_label_values(&["v1", "v2"]).is_ok());
583 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
584 assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
585
586 local_vec_1.with_label_values(&["v1", "v2"]).inc();
587 assert!(local_vec_1.remove_label_values(&["v1"]).is_err());
588 assert!(local_vec_1.remove_label_values(&["v1", "v3"]).is_err());
589
590 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(13.0);
591 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 14.0) <= f64::EPSILON);
592 assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= f64::EPSILON);
593
594 local_vec_2.with_label_values(&["v1", "v2"]).inc_by(7.0);
595 assert!((local_vec_2.with_label_values(&["v1", "v2"]).get() - 7.0) <= f64::EPSILON);
596
597 local_vec_1.flush();
598 local_vec_2.flush();
599 assert!((vec.with_label_values(&["v1", "v2"]).get() - 21.0) <= f64::EPSILON);
600
601 local_vec_1.flush();
602 local_vec_2.flush();
603 assert!((vec.with_label_values(&["v1", "v2"]).get() - 21.0) <= f64::EPSILON);
604 }
605
606 #[test]
607 fn test_int_counter_vec_local() {
608 let vec = IntCounterVec::new(Opts::new("foo", "bar"), &["l1", "l2"]).unwrap();
609 let mut local_vec_1 = vec.local();
610 assert!(local_vec_1.remove_label_values(&["v1", "v2"]).is_err());
611
612 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(23);
613 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 23);
614 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 0);
615
616 local_vec_1.flush();
617 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 0);
618 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 23);
619
620 local_vec_1.flush();
621 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 0);
622 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 23);
623
624 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(11);
625 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 11);
626 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 23);
627
628 local_vec_1.flush();
629 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 0);
630 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 34);
631 }
632
633 #[cfg(debug_assertions)]
634 #[test]
635 #[should_panic(expected = "assertion failed")]
636 fn test_counter_negative_inc() {
637 let counter = Counter::new("foo", "bar").unwrap();
638 counter.inc_by(-42.0);
639 }
640
641 #[cfg(debug_assertions)]
642 #[test]
643 #[should_panic(expected = "assertion failed")]
644 fn test_local_counter_negative_inc() {
645 let counter = Counter::new("foo", "bar").unwrap();
646 let local = counter.local();
647 local.inc_by(-42.0);
648 }
649}