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(&opts, &[])
48 }
49
50 fn with_opts_and_label_values(opts: &Opts, label_values: &[&str]) -> 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(&self, opts: &Opts, vals: &[&str]) -> 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::EPSILON;
327
328 use super::*;
329 use crate::metrics::{Collector, Opts};
330
331 #[test]
332 fn test_counter() {
333 let opts = Opts::new("test", "test help")
334 .const_label("a", "1")
335 .const_label("b", "2");
336 let counter = Counter::with_opts(opts).unwrap();
337 counter.inc();
338 assert_eq!(counter.get() as u64, 1);
339 counter.inc_by(42.0);
340 assert_eq!(counter.get() as u64, 43);
341
342 let mut mfs = counter.collect();
343 assert_eq!(mfs.len(), 1);
344
345 let mf = mfs.pop().unwrap();
346 let m = mf.get_metric().get(0).unwrap();
347 assert_eq!(m.get_label().len(), 2);
348 assert_eq!(m.get_counter().get_value() as u64, 43);
349
350 counter.reset();
351 assert_eq!(counter.get() as u64, 0);
352 }
353
354 #[test]
355 fn test_int_counter() {
356 let counter = IntCounter::new("foo", "bar").unwrap();
357 counter.inc();
358 assert_eq!(counter.get(), 1);
359 counter.inc_by(11);
360 assert_eq!(counter.get(), 12);
361
362 let mut mfs = counter.collect();
363 assert_eq!(mfs.len(), 1);
364
365 let mf = mfs.pop().unwrap();
366 let m = mf.get_metric().get(0).unwrap();
367 assert_eq!(m.get_label().len(), 0);
368 assert_eq!(m.get_counter().get_value() as u64, 12);
369
370 counter.reset();
371 assert_eq!(counter.get() as u64, 0);
372 }
373
374 #[test]
375 fn test_local_counter() {
376 let counter = Counter::new("counter", "counter helper").unwrap();
377 let local_counter1 = counter.local();
378 let local_counter2 = counter.local();
379
380 local_counter1.inc();
381 local_counter2.inc();
382 assert_eq!(local_counter1.get() as u64, 1);
383 assert_eq!(local_counter2.get() as u64, 1);
384 assert_eq!(counter.get() as u64, 0);
385 local_counter1.flush();
386 assert_eq!(local_counter1.get() as u64, 0);
387 assert_eq!(counter.get() as u64, 1);
388 local_counter2.flush();
389 assert_eq!(counter.get() as u64, 2);
390
391 local_counter1.reset();
392 local_counter2.reset();
393 counter.reset();
394 assert_eq!(counter.get() as u64, 0);
395 local_counter1.flush();
396 assert_eq!(counter.get() as u64, 0);
397 local_counter2.flush();
398 assert_eq!(counter.get() as u64, 0);
399 }
400
401 #[test]
402 fn test_int_local_counter() {
403 let counter = IntCounter::new("foo", "bar").unwrap();
404 let local_counter = counter.local();
405
406 local_counter.inc();
407 assert_eq!(local_counter.get(), 1);
408 assert_eq!(counter.get(), 0);
409
410 local_counter.inc_by(5);
411 local_counter.flush();
412 assert_eq!(local_counter.get(), 0);
413 assert_eq!(counter.get(), 6);
414
415 local_counter.reset();
416 counter.reset();
417 assert_eq!(counter.get() as u64, 0);
418 local_counter.flush();
419 assert_eq!(counter.get() as u64, 0);
420 }
421
422 #[test]
423 fn test_counter_vec_with_labels() {
424 let vec = CounterVec::new(
425 Opts::new("test_couter_vec", "test counter vec help"),
426 &["l1", "l2"],
427 )
428 .unwrap();
429
430 let mut labels = HashMap::new();
431 labels.insert("l1", "v1");
432 labels.insert("l2", "v2");
433 assert!(vec.remove(&labels).is_err());
434
435 vec.with(&labels).inc();
436 assert!(vec.remove(&labels).is_ok());
437 assert!(vec.remove(&labels).is_err());
438
439 let mut labels2 = HashMap::new();
440 labels2.insert("l1", "v2");
441 labels2.insert("l2", "v1");
442
443 vec.with(&labels).inc();
444 assert!(vec.remove(&labels2).is_err());
445
446 vec.with(&labels).inc();
447
448 let mut labels3 = HashMap::new();
449 labels3.insert("l1", "v1");
450 assert!(vec.remove(&labels3).is_err());
451 }
452
453 #[test]
454 fn test_int_counter_vec() {
455 let vec = IntCounterVec::new(Opts::new("foo", "bar"), &["l1", "l2"]).unwrap();
456
457 vec.with_label_values(&["v1", "v3"]).inc();
458 assert_eq!(vec.with_label_values(&["v1", "v3"]).get(), 1);
459
460 vec.with_label_values(&["v1", "v2"]).inc_by(12);
461 assert_eq!(vec.with_label_values(&["v1", "v3"]).get(), 1);
462 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 12);
463
464 vec.with_label_values(&["v4", "v2"]).inc_by(2);
465 assert_eq!(vec.with_label_values(&["v1", "v3"]).get(), 1);
466 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 12);
467 assert_eq!(vec.with_label_values(&["v4", "v2"]).get(), 2);
468
469 vec.with_label_values(&["v1", "v3"]).inc_by(5);
470 assert_eq!(vec.with_label_values(&["v1", "v3"]).get(), 6);
471 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 12);
472 assert_eq!(vec.with_label_values(&["v4", "v2"]).get(), 2);
473 }
474
475 #[test]
476 fn test_counter_vec_with_label_values() {
477 let vec = CounterVec::new(
478 Opts::new("test_vec", "test counter vec help"),
479 &["l1", "l2"],
480 )
481 .unwrap();
482
483 assert!(vec.remove_label_values(&["v1", "v2"]).is_err());
484 vec.with_label_values(&["v1", "v2"]).inc();
485 assert!(vec.remove_label_values(&["v1", "v2"]).is_ok());
486
487 vec.with_label_values(&["v1", "v2"]).inc();
488 assert!(vec.remove_label_values(&["v1"]).is_err());
489 assert!(vec.remove_label_values(&["v1", "v3"]).is_err());
490 }
491
492 #[test]
493 fn test_counter_vec_local() {
494 let vec = CounterVec::new(
495 Opts::new("test_vec_local", "test counter vec help"),
496 &["l1", "l2"],
497 )
498 .unwrap();
499 let mut local_vec_1 = vec.local();
500 let mut local_vec_2 = local_vec_1.clone();
501
502 assert!(local_vec_1.remove_label_values(&["v1", "v2"]).is_err());
503
504 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(23.0);
505 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 23.0) <= EPSILON);
506 assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
507
508 local_vec_1.flush();
509 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
510 assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= EPSILON);
511
512 local_vec_1.flush();
513 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
514 assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= EPSILON);
515
516 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(11.0);
517 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 11.0) <= EPSILON);
518 assert!((vec.with_label_values(&["v1", "v2"]).get() - 23.0) <= EPSILON);
519
520 local_vec_1.flush();
521 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
522 assert!((vec.with_label_values(&["v1", "v2"]).get() - 34.0) <= EPSILON);
523
524 assert!(local_vec_1.remove_label_values(&["v1", "v2"]).is_ok());
526 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
527 assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
528
529 local_vec_1.with_label_values(&["v1", "v2"]).inc();
530 assert!(local_vec_1.remove_label_values(&["v1"]).is_err());
531 assert!(local_vec_1.remove_label_values(&["v1", "v3"]).is_err());
532
533 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(13.0);
534 assert!((local_vec_1.with_label_values(&["v1", "v2"]).get() - 14.0) <= EPSILON);
535 assert!((vec.with_label_values(&["v1", "v2"]).get() - 0.0) <= EPSILON);
536
537 local_vec_2.with_label_values(&["v1", "v2"]).inc_by(7.0);
538 assert!((local_vec_2.with_label_values(&["v1", "v2"]).get() - 7.0) <= EPSILON);
539
540 local_vec_1.flush();
541 local_vec_2.flush();
542 assert!((vec.with_label_values(&["v1", "v2"]).get() - 21.0) <= EPSILON);
543
544 local_vec_1.flush();
545 local_vec_2.flush();
546 assert!((vec.with_label_values(&["v1", "v2"]).get() - 21.0) <= EPSILON);
547 }
548
549 #[test]
550 fn test_int_counter_vec_local() {
551 let vec = IntCounterVec::new(Opts::new("foo", "bar"), &["l1", "l2"]).unwrap();
552 let mut local_vec_1 = vec.local();
553 assert!(local_vec_1.remove_label_values(&["v1", "v2"]).is_err());
554
555 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(23);
556 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 23);
557 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 0);
558
559 local_vec_1.flush();
560 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 0);
561 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 23);
562
563 local_vec_1.flush();
564 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 0);
565 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 23);
566
567 local_vec_1.with_label_values(&["v1", "v2"]).inc_by(11);
568 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 11);
569 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 23);
570
571 local_vec_1.flush();
572 assert_eq!(local_vec_1.with_label_values(&["v1", "v2"]).get(), 0);
573 assert_eq!(vec.with_label_values(&["v1", "v2"]).get(), 34);
574 }
575
576 #[cfg(debug_assertions)]
577 #[test]
578 #[should_panic(expected = "assertion failed")]
579 fn test_counter_negative_inc() {
580 let counter = Counter::new("foo", "bar").unwrap();
581 counter.inc_by(-42.0);
582 }
583
584 #[cfg(debug_assertions)]
585 #[test]
586 #[should_panic(expected = "assertion failed")]
587 fn test_local_counter_negative_inc() {
588 let counter = Counter::new("foo", "bar").unwrap();
589 let local = counter.local();
590 local.inc_by(-42.0);
591 }
592}