/rust/registry/src/index.crates.io-1949cf8c6b5b557f/prometheus-client-0.24.0/src/metrics/gauge.rs
Line | Count | Source |
1 | | //! Module implementing an Open Metrics gauge. |
2 | | //! |
3 | | //! See [`Gauge`] for details. |
4 | | |
5 | | use crate::encoding::{EncodeGaugeValue, EncodeMetric, MetricEncoder}; |
6 | | |
7 | | use super::{MetricType, TypedMetric}; |
8 | | use std::marker::PhantomData; |
9 | | use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; |
10 | | #[cfg(target_has_atomic = "64")] |
11 | | use std::sync::atomic::{AtomicI64, AtomicU64}; |
12 | | use std::sync::Arc; |
13 | | |
14 | | /// Open Metrics [`Gauge`] to record current measurements. |
15 | | /// |
16 | | /// Single increasing, decreasing or constant value metric. |
17 | | /// |
18 | | /// [`Gauge`] is generic over the actual data type tracking the [`Gauge`] state |
19 | | /// as well as the data type used to interact with the [`Gauge`]. Out of |
20 | | /// convenience the generic type parameters are set to use an [`AtomicI64`] as a |
21 | | /// storage and [`i64`] on the interface by default. |
22 | | /// |
23 | | /// # Examples |
24 | | /// |
25 | | /// ## Using [`AtomicI64`] as storage and [`i64`] on the interface |
26 | | /// |
27 | | /// ``` |
28 | | /// # use prometheus_client::metrics::gauge::Gauge; |
29 | | /// let gauge: Gauge = Gauge::default(); |
30 | | /// gauge.set(42); |
31 | | /// let _value = gauge.get(); |
32 | | /// ``` |
33 | | /// |
34 | | /// ## Using [`AtomicU64`] as storage and [`f64`] on the interface |
35 | | /// |
36 | | /// ``` |
37 | | /// # use prometheus_client::metrics::gauge::Gauge; |
38 | | /// # use std::sync::atomic::AtomicU64; |
39 | | /// let gauge = Gauge::<f64, AtomicU64>::default(); |
40 | | /// gauge.set(42.0); |
41 | | /// let _value: f64 = gauge.get(); |
42 | | /// ``` |
43 | | #[cfg(target_has_atomic = "64")] |
44 | | #[derive(Debug)] |
45 | | pub struct Gauge<N = i64, A = AtomicI64> { |
46 | | value: Arc<A>, |
47 | | phantom: PhantomData<N>, |
48 | | } |
49 | | |
50 | | /// Open Metrics [`Gauge`] to record current measurements. |
51 | | #[cfg(not(target_has_atomic = "64"))] |
52 | | #[derive(Debug)] |
53 | | pub struct Gauge<N = i32, A = AtomicI32> { |
54 | | value: Arc<A>, |
55 | | phantom: PhantomData<N>, |
56 | | } |
57 | | |
58 | | impl<N, A> Clone for Gauge<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::gauge::Gauge as core::clone::Clone>::clone Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge<_, _> as core::clone::Clone>::clone |
65 | | } |
66 | | |
67 | | impl<N, A: Default> Default for Gauge<N, A> { |
68 | 0 | fn default() -> Self { |
69 | 0 | Self { |
70 | 0 | value: Arc::new(A::default()), |
71 | 0 | phantom: PhantomData, |
72 | 0 | } |
73 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge as core::default::Default>::default Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge<_, _> as core::default::Default>::default |
74 | | } |
75 | | |
76 | | impl<N, A: Atomic<N>> Gauge<N, A> { |
77 | | /// Increase the [`Gauge`] by 1, returning the previous value. |
78 | 0 | pub fn inc(&self) -> N { |
79 | 0 | self.value.inc() |
80 | 0 | } |
81 | | |
82 | | /// Increase the [`Gauge`] 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 | | /// Decrease the [`Gauge`] by 1, returning the previous value. |
88 | 0 | pub fn dec(&self) -> N { |
89 | 0 | self.value.dec() |
90 | 0 | } |
91 | | |
92 | | /// Decrease the [`Gauge`] by `v`, returning the previous value. |
93 | 0 | pub fn dec_by(&self, v: N) -> N { |
94 | 0 | self.value.dec_by(v) |
95 | 0 | } |
96 | | |
97 | | /// Sets the [`Gauge`] to `v`, returning the previous value. |
98 | 0 | pub fn set(&self, v: N) -> N { |
99 | 0 | self.value.set(v) |
100 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge>::set Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge<_, _>>::set |
101 | | |
102 | | /// Get the current value of the [`Gauge`]. |
103 | 0 | pub fn get(&self) -> N { |
104 | 0 | self.value.get() |
105 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge>::get Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge<_, _>>::get |
106 | | |
107 | | /// Exposes the inner atomic type of the [`Gauge`]. |
108 | | /// |
109 | | /// This should only be used for advanced use-cases which are not directly |
110 | | /// supported by the library. |
111 | 0 | pub fn inner(&self) -> &A { |
112 | 0 | &self.value |
113 | 0 | } |
114 | | } |
115 | | |
116 | | /// Atomic operations for a [`Gauge`] value store. |
117 | | pub trait Atomic<N> { |
118 | | /// Increase the value by `1`. |
119 | | fn inc(&self) -> N; |
120 | | |
121 | | /// Increase the value. |
122 | | fn inc_by(&self, v: N) -> N; |
123 | | |
124 | | /// Decrease the value by `1`. |
125 | | fn dec(&self) -> N; |
126 | | |
127 | | /// Decrease the value. |
128 | | fn dec_by(&self, v: N) -> N; |
129 | | |
130 | | /// Set the value. |
131 | | fn set(&self, v: N) -> N; |
132 | | |
133 | | /// Get the value. |
134 | | fn get(&self) -> N; |
135 | | } |
136 | | |
137 | | impl Atomic<i32> for AtomicI32 { |
138 | 0 | fn inc(&self) -> i32 { |
139 | 0 | self.inc_by(1) |
140 | 0 | } |
141 | | |
142 | 0 | fn inc_by(&self, v: i32) -> i32 { |
143 | 0 | self.fetch_add(v, Ordering::Relaxed) |
144 | 0 | } |
145 | | |
146 | 0 | fn dec(&self) -> i32 { |
147 | 0 | self.dec_by(1) |
148 | 0 | } |
149 | | |
150 | 0 | fn dec_by(&self, v: i32) -> i32 { |
151 | 0 | self.fetch_sub(v, Ordering::Relaxed) |
152 | 0 | } |
153 | | |
154 | 0 | fn set(&self, v: i32) -> i32 { |
155 | 0 | self.swap(v, Ordering::Relaxed) |
156 | 0 | } |
157 | | |
158 | 0 | fn get(&self) -> i32 { |
159 | 0 | self.load(Ordering::Relaxed) |
160 | 0 | } |
161 | | } |
162 | | |
163 | | impl Atomic<u32> for AtomicU32 { |
164 | 0 | fn inc(&self) -> u32 { |
165 | 0 | self.inc_by(1) |
166 | 0 | } |
167 | | |
168 | 0 | fn inc_by(&self, v: u32) -> u32 { |
169 | 0 | self.fetch_add(v, Ordering::Relaxed) |
170 | 0 | } |
171 | | |
172 | 0 | fn dec(&self) -> u32 { |
173 | 0 | self.dec_by(1) |
174 | 0 | } |
175 | | |
176 | 0 | fn dec_by(&self, v: u32) -> u32 { |
177 | 0 | self.fetch_sub(v, Ordering::Relaxed) |
178 | 0 | } |
179 | | |
180 | 0 | fn set(&self, v: u32) -> u32 { |
181 | 0 | self.swap(v, Ordering::Relaxed) |
182 | 0 | } |
183 | | |
184 | 0 | fn get(&self) -> u32 { |
185 | 0 | self.load(Ordering::Relaxed) |
186 | 0 | } |
187 | | } |
188 | | |
189 | | #[cfg(target_has_atomic = "64")] |
190 | | impl Atomic<i64> for AtomicI64 { |
191 | 0 | fn inc(&self) -> i64 { |
192 | 0 | self.inc_by(1) |
193 | 0 | } |
194 | | |
195 | 0 | fn inc_by(&self, v: i64) -> i64 { |
196 | 0 | self.fetch_add(v, Ordering::Relaxed) |
197 | 0 | } |
198 | | |
199 | 0 | fn dec(&self) -> i64 { |
200 | 0 | self.dec_by(1) |
201 | 0 | } |
202 | | |
203 | 0 | fn dec_by(&self, v: i64) -> i64 { |
204 | 0 | self.fetch_sub(v, Ordering::Relaxed) |
205 | 0 | } |
206 | | |
207 | 0 | fn set(&self, v: i64) -> i64 { |
208 | 0 | self.swap(v, Ordering::Relaxed) |
209 | 0 | } |
210 | | |
211 | 0 | fn get(&self) -> i64 { |
212 | 0 | self.load(Ordering::Relaxed) |
213 | 0 | } |
214 | | } |
215 | | |
216 | | #[cfg(target_has_atomic = "64")] |
217 | | impl Atomic<u64> for AtomicU64 { |
218 | 0 | fn inc(&self) -> u64 { |
219 | 0 | self.inc_by(1) |
220 | 0 | } |
221 | | |
222 | 0 | fn inc_by(&self, v: u64) -> u64 { |
223 | 0 | self.fetch_add(v, Ordering::Relaxed) |
224 | 0 | } |
225 | | |
226 | 0 | fn dec(&self) -> u64 { |
227 | 0 | self.dec_by(1) |
228 | 0 | } |
229 | | |
230 | 0 | fn dec_by(&self, v: u64) -> u64 { |
231 | 0 | self.fetch_sub(v, Ordering::Relaxed) |
232 | 0 | } |
233 | | |
234 | 0 | fn set(&self, v: u64) -> u64 { |
235 | 0 | self.swap(v, Ordering::Relaxed) |
236 | 0 | } |
237 | | |
238 | 0 | fn get(&self) -> u64 { |
239 | 0 | self.load(Ordering::Relaxed) |
240 | 0 | } |
241 | | } |
242 | | |
243 | | #[cfg(target_has_atomic = "64")] |
244 | | impl Atomic<f64> for AtomicU64 { |
245 | 0 | fn inc(&self) -> f64 { |
246 | 0 | self.inc_by(1.0) |
247 | 0 | } |
248 | | |
249 | 0 | fn inc_by(&self, v: f64) -> f64 { |
250 | 0 | let mut old_u64 = self.load(Ordering::Relaxed); |
251 | | let mut old_f64; |
252 | | loop { |
253 | 0 | old_f64 = f64::from_bits(old_u64); |
254 | 0 | let new = f64::to_bits(old_f64 + v); |
255 | 0 | match self.compare_exchange_weak(old_u64, new, Ordering::Relaxed, Ordering::Relaxed) { |
256 | 0 | Ok(_) => break, |
257 | 0 | Err(x) => old_u64 = x, |
258 | | } |
259 | | } |
260 | | |
261 | 0 | old_f64 |
262 | 0 | } |
263 | | |
264 | 0 | fn dec(&self) -> f64 { |
265 | 0 | self.dec_by(1.0) |
266 | 0 | } |
267 | | |
268 | 0 | fn dec_by(&self, v: f64) -> f64 { |
269 | 0 | let mut old_u64 = self.load(Ordering::Relaxed); |
270 | | let mut old_f64; |
271 | | loop { |
272 | 0 | old_f64 = f64::from_bits(old_u64); |
273 | 0 | let new = f64::to_bits(old_f64 - v); |
274 | 0 | match self.compare_exchange_weak(old_u64, new, Ordering::Relaxed, Ordering::Relaxed) { |
275 | 0 | Ok(_) => break, |
276 | 0 | Err(x) => old_u64 = x, |
277 | | } |
278 | | } |
279 | | |
280 | 0 | old_f64 |
281 | 0 | } |
282 | | |
283 | 0 | fn set(&self, v: f64) -> f64 { |
284 | 0 | f64::from_bits(self.swap(f64::to_bits(v), Ordering::Relaxed)) |
285 | 0 | } |
286 | | |
287 | 0 | fn get(&self) -> f64 { |
288 | 0 | f64::from_bits(self.load(Ordering::Relaxed)) |
289 | 0 | } |
290 | | } |
291 | | |
292 | | impl Atomic<f32> for AtomicU32 { |
293 | 0 | fn inc(&self) -> f32 { |
294 | 0 | self.inc_by(1.0) |
295 | 0 | } |
296 | | |
297 | 0 | fn inc_by(&self, v: f32) -> f32 { |
298 | 0 | let mut old_u32 = self.load(Ordering::Relaxed); |
299 | | let mut old_f32; |
300 | | loop { |
301 | 0 | old_f32 = f32::from_bits(old_u32); |
302 | 0 | let new = f32::to_bits(old_f32 + v); |
303 | 0 | match self.compare_exchange_weak(old_u32, new, Ordering::Relaxed, Ordering::Relaxed) { |
304 | 0 | Ok(_) => break, |
305 | 0 | Err(x) => old_u32 = x, |
306 | | } |
307 | | } |
308 | | |
309 | 0 | old_f32 |
310 | 0 | } |
311 | | |
312 | 0 | fn dec(&self) -> f32 { |
313 | 0 | self.dec_by(1.0) |
314 | 0 | } |
315 | | |
316 | 0 | fn dec_by(&self, v: f32) -> f32 { |
317 | 0 | let mut old_u32 = self.load(Ordering::Relaxed); |
318 | | let mut old_f32; |
319 | | loop { |
320 | 0 | old_f32 = f32::from_bits(old_u32); |
321 | 0 | let new = f32::to_bits(old_f32 - v); |
322 | 0 | match self.compare_exchange_weak(old_u32, new, Ordering::Relaxed, Ordering::Relaxed) { |
323 | 0 | Ok(_) => break, |
324 | 0 | Err(x) => old_u32 = x, |
325 | | } |
326 | | } |
327 | | |
328 | 0 | old_f32 |
329 | 0 | } |
330 | | |
331 | 0 | fn set(&self, v: f32) -> f32 { |
332 | 0 | f32::from_bits(self.swap(f32::to_bits(v), Ordering::Relaxed)) |
333 | 0 | } |
334 | | |
335 | 0 | fn get(&self) -> f32 { |
336 | 0 | f32::from_bits(self.load(Ordering::Relaxed)) |
337 | 0 | } |
338 | | } |
339 | | |
340 | | impl<N, A> TypedMetric for Gauge<N, A> { |
341 | | const TYPE: MetricType = MetricType::Gauge; |
342 | | } |
343 | | |
344 | | impl<N, A> EncodeMetric for Gauge<N, A> |
345 | | where |
346 | | N: EncodeGaugeValue, |
347 | | A: Atomic<N>, |
348 | | { |
349 | 0 | fn encode(&self, mut encoder: MetricEncoder) -> Result<(), std::fmt::Error> { |
350 | 0 | encoder.encode_gauge(&self.get()) |
351 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge as prometheus_client::encoding::EncodeMetric>::encode Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge<_, _> as prometheus_client::encoding::EncodeMetric>::encode |
352 | 0 | fn metric_type(&self) -> MetricType { |
353 | 0 | Self::TYPE |
354 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge as prometheus_client::encoding::EncodeMetric>::metric_type Unexecuted instantiation: <prometheus_client::metrics::gauge::Gauge<_, _> as prometheus_client::encoding::EncodeMetric>::metric_type |
355 | | } |
356 | | |
357 | | /// As a [`Gauge`], but constant, meaning it cannot change once created. |
358 | | /// |
359 | | /// Needed for advanced use-cases, e.g. in combination with [`Collector`](crate::collector::Collector). |
360 | | #[derive(Debug, Default)] |
361 | | pub struct ConstGauge<N = i64> { |
362 | | value: N, |
363 | | } |
364 | | |
365 | | impl<N> ConstGauge<N> { |
366 | | /// Creates a new [`ConstGauge`]. |
367 | 0 | pub fn new(value: N) -> Self { |
368 | 0 | Self { value } |
369 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::gauge::ConstGauge<u64>>::new Unexecuted instantiation: <prometheus_client::metrics::gauge::ConstGauge<_>>::new |
370 | | } |
371 | | |
372 | | impl<N> TypedMetric for ConstGauge<N> { |
373 | | const TYPE: MetricType = MetricType::Gauge; |
374 | | } |
375 | | |
376 | | impl<N> EncodeMetric for ConstGauge<N> |
377 | | where |
378 | | N: EncodeGaugeValue, |
379 | | { |
380 | 0 | fn encode(&self, mut encoder: MetricEncoder) -> Result<(), std::fmt::Error> { |
381 | 0 | encoder.encode_gauge(&self.value) |
382 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::gauge::ConstGauge<u64> as prometheus_client::encoding::EncodeMetric>::encode Unexecuted instantiation: <prometheus_client::metrics::gauge::ConstGauge<_> as prometheus_client::encoding::EncodeMetric>::encode |
383 | | |
384 | 0 | fn metric_type(&self) -> MetricType { |
385 | 0 | Self::TYPE |
386 | 0 | } Unexecuted instantiation: <prometheus_client::metrics::gauge::ConstGauge<u64> as prometheus_client::encoding::EncodeMetric>::metric_type Unexecuted instantiation: <prometheus_client::metrics::gauge::ConstGauge<_> as prometheus_client::encoding::EncodeMetric>::metric_type |
387 | | } |
388 | | |
389 | | #[cfg(test)] |
390 | | mod tests { |
391 | | use super::*; |
392 | | |
393 | | #[test] |
394 | | fn inc_dec_and_get() { |
395 | | let gauge: Gauge = Gauge::default(); |
396 | | assert_eq!(0, gauge.inc()); |
397 | | assert_eq!(1, gauge.get()); |
398 | | |
399 | | assert_eq!(1, gauge.dec()); |
400 | | assert_eq!(0, gauge.get()); |
401 | | |
402 | | assert_eq!(0, gauge.set(10)); |
403 | | assert_eq!(10, gauge.get()); |
404 | | } |
405 | | } |