open_metrics_client/metrics/
exemplar.rs1use super::counter::{self, Counter};
6use super::histogram::Histogram;
7use owning_ref::OwningRef;
8use std::collections::HashMap;
9use std::sync::atomic::AtomicU64;
10use std::sync::{Arc, RwLock, RwLockReadGuard};
11
12pub struct Exemplar<S, V> {
13 pub(crate) label_set: S,
14 pub(crate) value: V,
15}
16
17pub struct CounterWithExemplar<S, N = u64, A = AtomicU64> {
30 pub(crate) inner: Arc<RwLock<CounterWithExemplarInner<S, N, A>>>,
31}
32
33impl<S, N, A> Clone for CounterWithExemplar<S, N, A> {
34 fn clone(&self) -> Self {
35 CounterWithExemplar {
36 inner: self.inner.clone(),
37 }
38 }
39}
40
41pub struct CounterWithExemplarInner<S, N, A> {
42 pub(crate) exemplar: Option<Exemplar<S, N>>,
43 pub(crate) counter: Counter<N, A>,
44}
45
46impl<S, N, A: Default> Default for CounterWithExemplar<S, N, A> {
47 fn default() -> Self {
48 Self {
49 inner: Arc::new(RwLock::new(CounterWithExemplarInner {
50 exemplar: None,
51 counter: Default::default(),
52 })),
53 }
54 }
55}
56
57impl<S, N: Clone, A: counter::Atomic<N>> CounterWithExemplar<S, N, A> {
58 pub fn inc_by(&self, v: N, label_set: Option<S>) -> N {
64 let mut inner = self.inner.write().expect("Lock not to be poisoned.");
65
66 inner.exemplar = label_set.map(|label_set| Exemplar {
67 label_set,
68 value: v.clone(),
69 });
70
71 inner.counter.inc_by(v)
72 }
73
74 pub fn get(&self) -> (N, RwLockGuardedCounterWithExemplar<S, N, A>) {
77 let inner = self.inner.read().expect("Lock not to be poisoned.");
78 let value = inner.counter.get();
79 let exemplar = OwningRef::new(inner).map(|inner| &inner.exemplar);
80 (value, exemplar)
81 }
82
83 pub fn inner(&self) -> OwningRef<RwLockReadGuard<CounterWithExemplarInner<S, N, A>>, A> {
92 OwningRef::new(self.inner.read().expect("Lock not to be poisoned."))
93 .map(|inner| inner.counter.inner())
94 }
95}
96
97type RwLockGuardedCounterWithExemplar<'a, S, N, A> =
98 OwningRef<RwLockReadGuard<'a, CounterWithExemplarInner<S, N, A>>, Option<Exemplar<S, N>>>;
99
100pub struct HistogramWithExemplars<S> {
113 pub(crate) inner: Arc<RwLock<HistogramWithExemplarsInner<S>>>,
115}
116
117impl<S> Clone for HistogramWithExemplars<S> {
118 fn clone(&self) -> Self {
119 Self {
120 inner: self.inner.clone(),
121 }
122 }
123}
124
125pub struct HistogramWithExemplarsInner<S> {
126 pub(crate) exemplars: HashMap<usize, Exemplar<S, f64>>,
127 pub(crate) histogram: Histogram,
128}
129
130impl<S> HistogramWithExemplars<S> {
131 pub fn new(buckets: impl Iterator<Item = f64>) -> Self {
132 Self {
133 inner: Arc::new(RwLock::new(HistogramWithExemplarsInner {
134 exemplars: Default::default(),
135 histogram: Histogram::new(buckets),
136 })),
137 }
138 }
139
140 pub fn observe(&self, v: f64, label_set: Option<S>) {
141 let mut inner = self.inner.write().expect("Lock not to be poisoned.");
142 let bucket = inner.histogram.observe_and_bucket(v);
143 if let (Some(bucket), Some(label_set)) = (bucket, label_set) {
144 inner.exemplars.insert(
145 bucket,
146 Exemplar {
147 label_set,
148 value: v,
149 },
150 );
151 }
152 }
153
154 pub(crate) fn inner(&self) -> RwLockReadGuard<HistogramWithExemplarsInner<S>> {
155 self.inner.read().expect("Lock not to be poisoned.")
156 }
157}