Coverage Report

Created: 2025-11-16 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}