/rust/registry/src/index.crates.io-6f17d22bba15001f/prometheus-client-0.22.3/src/metrics/counter.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Module implementing an Open Metrics counter. |
2 | | //! |
3 | | //! See [`Counter`] for details. |
4 | | |
5 | | use crate::encoding::{EncodeMetric, MetricEncoder}; |
6 | | |
7 | | use super::{MetricType, TypedMetric}; |
8 | | use std::marker::PhantomData; |
9 | | #[cfg(target_has_atomic = "64")] |
10 | | use std::sync::atomic::AtomicU64; |
11 | | use std::sync::atomic::{AtomicU32, Ordering}; |
12 | | use std::sync::Arc; |
13 | | |
14 | | /// Open Metrics [`Counter`] to measure discrete events. |
15 | | /// |
16 | | /// Single monotonically increasing value metric. |
17 | | /// |
18 | | /// [`Counter`] is generic over the actual data type tracking the [`Counter`] |
19 | | /// state as well as the data type used to interact with the [`Counter`]. Out of |
20 | | /// convenience the generic type parameters are set to use an [`AtomicU64`] as a |
21 | | /// storage and [`u64`] on the interface by default. |
22 | | /// |
23 | | /// # Examples |
24 | | /// |
25 | | /// ## Using [`AtomicU64`] as storage and [`u64`] on the interface |
26 | | /// |
27 | | /// ``` |
28 | | /// # use prometheus_client::metrics::counter::Counter; |
29 | | /// let counter: Counter = Counter::default(); |
30 | | /// counter.inc(); |
31 | | /// let _value: u64 = counter.get(); |
32 | | /// ``` |
33 | | /// |
34 | | /// ## Using [`AtomicU64`] as storage and [`f64`] on the interface |
35 | | /// |
36 | | /// ``` |
37 | | /// # use prometheus_client::metrics::counter::Counter; |
38 | | /// # use std::sync::atomic::AtomicU64; |
39 | | /// let counter = Counter::<f64, AtomicU64>::default(); |
40 | | /// counter.inc(); |
41 | | /// let _value: f64 = counter.get(); |
42 | | /// ``` |
43 | | #[cfg(target_has_atomic = "64")] |
44 | | #[derive(Debug)] |
45 | | pub struct Counter<N = u64, A = AtomicU64> { |
46 | | value: Arc<A>, |
47 | | phantom: PhantomData<N>, |
48 | | } |
49 | | |
50 | | /// Open Metrics [`Counter`] to measure discrete events. |
51 | | #[cfg(not(target_has_atomic = "64"))] |
52 | | #[derive(Debug)] |
53 | | pub struct Counter<N = u32, A = AtomicU32> { |
54 | | value: Arc<A>, |
55 | | phantom: PhantomData<N>, |
56 | | } |
57 | | |
58 | | impl<N, A> Clone for Counter<N, A> { |
59 | 0 | fn clone(&self) -> Self { |
60 | 0 | Self { |
61 | 0 | value: self.value.clone(), |
62 | 0 | phantom: PhantomData, |
63 | 0 | } |
64 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::counter::Counter as core::clone::Clone>::clone Unexecuted instantiation: <prometheus_client::metrics::counter::Counter<_, _> as core::clone::Clone>::clone Unexecuted instantiation: <prometheus_client::metrics::counter::Counter as core::clone::Clone>::clone |
65 | | } |
66 | | |
67 | | impl<N, A: Default> Default for Counter<N, A> { |
68 | 0 | fn default() -> Self { |
69 | 0 | Counter { |
70 | 0 | value: Arc::new(A::default()), |
71 | 0 | phantom: PhantomData, |
72 | 0 | } |
73 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::counter::Counter as core::default::Default>::default Unexecuted instantiation: <prometheus_client::metrics::counter::Counter<_, _> as core::default::Default>::default Unexecuted instantiation: <prometheus_client::metrics::counter::Counter as core::default::Default>::default Unexecuted instantiation: <prometheus_client::metrics::counter::Counter as core::default::Default>::default |
74 | | } |
75 | | |
76 | | impl<N, A: Atomic<N>> Counter<N, A> { |
77 | | /// Increase the [`Counter`] by 1, returning the previous value. |
78 | 0 | pub fn inc(&self) -> N { |
79 | 0 | self.value.inc() |
80 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::counter::Counter<_, _>>::inc Unexecuted instantiation: <prometheus_client::metrics::counter::Counter>::inc |
81 | | |
82 | | /// Increase the [`Counter`] by `v`, returning the previous value. |
83 | 0 | pub fn inc_by(&self, v: N) -> N { |
84 | 0 | self.value.inc_by(v) |
85 | 0 | } |
86 | | |
87 | | /// Get the current value of the [`Counter`]. |
88 | 0 | pub fn get(&self) -> N { |
89 | 0 | self.value.get() |
90 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::counter::Counter>::get Unexecuted instantiation: <prometheus_client::metrics::counter::Counter<_, _>>::get Unexecuted instantiation: <prometheus_client::metrics::counter::Counter>::get |
91 | | |
92 | | /// Exposes the inner atomic type of the [`Counter`]. |
93 | | /// |
94 | | /// This should only be used for advanced use-cases which are not directly |
95 | | /// supported by the library. |
96 | | /// |
97 | | /// The caller of this function has to uphold the property of an Open |
98 | | /// Metrics counter namely that the value is monotonically increasing, i.e. |
99 | | /// either stays the same or increases. |
100 | 0 | pub fn inner(&self) -> &A { |
101 | 0 | &self.value |
102 | 0 | } |
103 | | } |
104 | | |
105 | | /// Atomic operations for a [`Counter`] value store. |
106 | | pub trait Atomic<N> { |
107 | | /// Increase the value by `1`. |
108 | | fn inc(&self) -> N; |
109 | | |
110 | | /// Increase the value. |
111 | | fn inc_by(&self, v: N) -> N; |
112 | | |
113 | | /// Get the the value. |
114 | | fn get(&self) -> N; |
115 | | } |
116 | | |
117 | | #[cfg(target_has_atomic = "64")] |
118 | | impl Atomic<u64> for AtomicU64 { |
119 | 0 | fn inc(&self) -> u64 { |
120 | 0 | self.inc_by(1) |
121 | 0 | } |
122 | | |
123 | 0 | fn inc_by(&self, v: u64) -> u64 { |
124 | 0 | self.fetch_add(v, Ordering::Relaxed) |
125 | 0 | } |
126 | | |
127 | 0 | fn get(&self) -> u64 { |
128 | 0 | self.load(Ordering::Relaxed) |
129 | 0 | } |
130 | | } |
131 | | |
132 | | impl Atomic<u32> for AtomicU32 { |
133 | 0 | fn inc(&self) -> u32 { |
134 | 0 | self.inc_by(1) |
135 | 0 | } |
136 | | |
137 | 0 | fn inc_by(&self, v: u32) -> u32 { |
138 | 0 | self.fetch_add(v, Ordering::Relaxed) |
139 | 0 | } |
140 | | |
141 | 0 | fn get(&self) -> u32 { |
142 | 0 | self.load(Ordering::Relaxed) |
143 | 0 | } |
144 | | } |
145 | | |
146 | | #[cfg(target_has_atomic = "64")] |
147 | | impl Atomic<f64> for AtomicU64 { |
148 | 0 | fn inc(&self) -> f64 { |
149 | 0 | self.inc_by(1.0) |
150 | 0 | } |
151 | | |
152 | 0 | fn inc_by(&self, v: f64) -> f64 { |
153 | 0 | let mut old_u64 = self.load(Ordering::Relaxed); |
154 | | let mut old_f64; |
155 | | loop { |
156 | 0 | old_f64 = f64::from_bits(old_u64); |
157 | 0 | let new = f64::to_bits(old_f64 + v); |
158 | 0 | match self.compare_exchange_weak(old_u64, new, Ordering::Relaxed, Ordering::Relaxed) { |
159 | 0 | Ok(_) => break, |
160 | 0 | Err(x) => old_u64 = x, |
161 | | } |
162 | | } |
163 | | |
164 | 0 | old_f64 |
165 | 0 | } |
166 | | |
167 | 0 | fn get(&self) -> f64 { |
168 | 0 | f64::from_bits(self.load(Ordering::Relaxed)) |
169 | 0 | } |
170 | | } |
171 | | |
172 | | impl<N, A> TypedMetric for Counter<N, A> { |
173 | | const TYPE: MetricType = MetricType::Counter; |
174 | | } |
175 | | |
176 | | impl<N, A> EncodeMetric for Counter<N, A> |
177 | | where |
178 | | N: crate::encoding::EncodeCounterValue, |
179 | | A: Atomic<N>, |
180 | | { |
181 | 0 | fn encode(&self, mut encoder: MetricEncoder) -> Result<(), std::fmt::Error> { |
182 | 0 | encoder.encode_counter::<(), _, u64>(&self.get(), None) |
183 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::counter::Counter as prometheus_client::encoding::EncodeMetric>::encode Unexecuted instantiation: <prometheus_client::metrics::counter::Counter<_, _> as prometheus_client::encoding::EncodeMetric>::encode Unexecuted instantiation: <prometheus_client::metrics::counter::Counter as prometheus_client::encoding::EncodeMetric>::encode |
184 | | |
185 | 0 | fn metric_type(&self) -> MetricType { |
186 | 0 | Self::TYPE |
187 | 0 | } |
188 | | } |
189 | | |
190 | | /// As a [`Counter`], but constant, meaning it cannot change once created. |
191 | | /// |
192 | | /// Needed for advanced use-cases, e.g. in combination with [`Collector`](crate::collector::Collector). |
193 | | #[derive(Debug, Default)] |
194 | | pub struct ConstCounter<N = u64> { |
195 | | value: N, |
196 | | } |
197 | | |
198 | | impl<N> ConstCounter<N> { |
199 | | /// Creates a new [`ConstCounter`]. |
200 | 0 | pub fn new(value: N) -> Self { |
201 | 0 | Self { value } |
202 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::counter::ConstCounter<_>>::new Unexecuted instantiation: <prometheus_client::metrics::counter::ConstCounter<f64>>::new |
203 | | } |
204 | | |
205 | | impl<N> TypedMetric for ConstCounter<N> { |
206 | | const TYPE: MetricType = MetricType::Counter; |
207 | | } |
208 | | |
209 | | impl<N> EncodeMetric for ConstCounter<N> |
210 | | where |
211 | | N: crate::encoding::EncodeCounterValue, |
212 | | { |
213 | 0 | fn encode(&self, mut encoder: MetricEncoder) -> Result<(), std::fmt::Error> { |
214 | 0 | encoder.encode_counter::<(), _, u64>(&self.value, None) |
215 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::counter::ConstCounter<_> as prometheus_client::encoding::EncodeMetric>::encode Unexecuted instantiation: <prometheus_client::metrics::counter::ConstCounter<f64> as prometheus_client::encoding::EncodeMetric>::encode |
216 | | |
217 | 0 | fn metric_type(&self) -> MetricType { |
218 | 0 | Self::TYPE |
219 | 0 | } |
220 | | } |
221 | | |
222 | | #[cfg(test)] |
223 | | mod tests { |
224 | | use super::*; |
225 | | use quickcheck::QuickCheck; |
226 | | |
227 | | #[test] |
228 | | fn inc_and_get() { |
229 | | let counter: Counter = Counter::default(); |
230 | | assert_eq!(0, counter.inc()); |
231 | | assert_eq!(1, counter.get()); |
232 | | } |
233 | | |
234 | | #[cfg(target_has_atomic = "64")] |
235 | | #[test] |
236 | | fn f64_stored_in_atomic_u64() { |
237 | | fn prop(fs: Vec<f64>) { |
238 | | let fs: Vec<f64> = fs |
239 | | .into_iter() |
240 | | // Map infinite, subnormal and NaN to 0.0. |
241 | | .map(|f| if f.is_normal() { f } else { 0.0 }) |
242 | | .collect(); |
243 | | let sum = fs.iter().sum(); |
244 | | let counter = Counter::<f64, AtomicU64>::default(); |
245 | | for f in fs { |
246 | | counter.inc_by(f); |
247 | | } |
248 | | assert_eq!(counter.get(), sum) |
249 | | } |
250 | | |
251 | | QuickCheck::new().tests(10).quickcheck(prop as fn(_)) |
252 | | } |
253 | | } |