prometheus_client/metrics/
gauge.rs1use crate::encoding::{EncodeGaugeValue, EncodeMetric, MetricEncoder};
6
7use super::{MetricType, TypedMetric};
8use std::marker::PhantomData;
9use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
10#[cfg(target_has_atomic = "64")]
11use std::sync::atomic::{AtomicI64, AtomicU64};
12use std::sync::Arc;
13
14#[cfg(target_has_atomic = "64")]
44#[derive(Debug)]
45pub struct Gauge<N = i64, A = AtomicI64> {
46 value: Arc<A>,
47 phantom: PhantomData<N>,
48}
49
50#[cfg(not(target_has_atomic = "64"))]
52#[derive(Debug)]
53pub struct Gauge<N = i32, A = AtomicI32> {
54 value: Arc<A>,
55 phantom: PhantomData<N>,
56}
57
58impl<N, A> Clone for Gauge<N, A> {
59 fn clone(&self) -> Self {
60 Self {
61 value: self.value.clone(),
62 phantom: PhantomData,
63 }
64 }
65}
66
67impl<N, A: Default> Default for Gauge<N, A> {
68 fn default() -> Self {
69 Self {
70 value: Arc::new(A::default()),
71 phantom: PhantomData,
72 }
73 }
74}
75
76impl<N, A: Atomic<N>> Gauge<N, A> {
77 pub fn inc(&self) -> N {
79 self.value.inc()
80 }
81
82 pub fn inc_by(&self, v: N) -> N {
84 self.value.inc_by(v)
85 }
86
87 pub fn dec(&self) -> N {
89 self.value.dec()
90 }
91
92 pub fn dec_by(&self, v: N) -> N {
94 self.value.dec_by(v)
95 }
96
97 pub fn set(&self, v: N) -> N {
99 self.value.set(v)
100 }
101
102 pub fn get(&self) -> N {
104 self.value.get()
105 }
106
107 pub fn inner(&self) -> &A {
112 &self.value
113 }
114}
115
116pub trait Atomic<N> {
118 fn inc(&self) -> N;
120
121 fn inc_by(&self, v: N) -> N;
123
124 fn dec(&self) -> N;
126
127 fn dec_by(&self, v: N) -> N;
129
130 fn set(&self, v: N) -> N;
132
133 fn get(&self) -> N;
135}
136
137impl Atomic<i32> for AtomicI32 {
138 fn inc(&self) -> i32 {
139 self.inc_by(1)
140 }
141
142 fn inc_by(&self, v: i32) -> i32 {
143 self.fetch_add(v, Ordering::Relaxed)
144 }
145
146 fn dec(&self) -> i32 {
147 self.dec_by(1)
148 }
149
150 fn dec_by(&self, v: i32) -> i32 {
151 self.fetch_sub(v, Ordering::Relaxed)
152 }
153
154 fn set(&self, v: i32) -> i32 {
155 self.swap(v, Ordering::Relaxed)
156 }
157
158 fn get(&self) -> i32 {
159 self.load(Ordering::Relaxed)
160 }
161}
162
163impl Atomic<u32> for AtomicU32 {
164 fn inc(&self) -> u32 {
165 self.inc_by(1)
166 }
167
168 fn inc_by(&self, v: u32) -> u32 {
169 self.fetch_add(v, Ordering::Relaxed)
170 }
171
172 fn dec(&self) -> u32 {
173 self.dec_by(1)
174 }
175
176 fn dec_by(&self, v: u32) -> u32 {
177 self.fetch_sub(v, Ordering::Relaxed)
178 }
179
180 fn set(&self, v: u32) -> u32 {
181 self.swap(v, Ordering::Relaxed)
182 }
183
184 fn get(&self) -> u32 {
185 self.load(Ordering::Relaxed)
186 }
187}
188
189#[cfg(target_has_atomic = "64")]
190impl Atomic<i64> for AtomicI64 {
191 fn inc(&self) -> i64 {
192 self.inc_by(1)
193 }
194
195 fn inc_by(&self, v: i64) -> i64 {
196 self.fetch_add(v, Ordering::Relaxed)
197 }
198
199 fn dec(&self) -> i64 {
200 self.dec_by(1)
201 }
202
203 fn dec_by(&self, v: i64) -> i64 {
204 self.fetch_sub(v, Ordering::Relaxed)
205 }
206
207 fn set(&self, v: i64) -> i64 {
208 self.swap(v, Ordering::Relaxed)
209 }
210
211 fn get(&self) -> i64 {
212 self.load(Ordering::Relaxed)
213 }
214}
215
216#[cfg(target_has_atomic = "64")]
217impl Atomic<u64> for AtomicU64 {
218 fn inc(&self) -> u64 {
219 self.inc_by(1)
220 }
221
222 fn inc_by(&self, v: u64) -> u64 {
223 self.fetch_add(v, Ordering::Relaxed)
224 }
225
226 fn dec(&self) -> u64 {
227 self.dec_by(1)
228 }
229
230 fn dec_by(&self, v: u64) -> u64 {
231 self.fetch_sub(v, Ordering::Relaxed)
232 }
233
234 fn set(&self, v: u64) -> u64 {
235 self.swap(v, Ordering::Relaxed)
236 }
237
238 fn get(&self) -> u64 {
239 self.load(Ordering::Relaxed)
240 }
241}
242
243#[cfg(target_has_atomic = "64")]
244impl Atomic<f64> for AtomicU64 {
245 fn inc(&self) -> f64 {
246 self.inc_by(1.0)
247 }
248
249 fn inc_by(&self, v: f64) -> f64 {
250 let mut old_u64 = self.load(Ordering::Relaxed);
251 let mut old_f64;
252 loop {
253 old_f64 = f64::from_bits(old_u64);
254 let new = f64::to_bits(old_f64 + v);
255 match self.compare_exchange_weak(old_u64, new, Ordering::Relaxed, Ordering::Relaxed) {
256 Ok(_) => break,
257 Err(x) => old_u64 = x,
258 }
259 }
260
261 old_f64
262 }
263
264 fn dec(&self) -> f64 {
265 self.dec_by(1.0)
266 }
267
268 fn dec_by(&self, v: f64) -> f64 {
269 let mut old_u64 = self.load(Ordering::Relaxed);
270 let mut old_f64;
271 loop {
272 old_f64 = f64::from_bits(old_u64);
273 let new = f64::to_bits(old_f64 - v);
274 match self.compare_exchange_weak(old_u64, new, Ordering::Relaxed, Ordering::Relaxed) {
275 Ok(_) => break,
276 Err(x) => old_u64 = x,
277 }
278 }
279
280 old_f64
281 }
282
283 fn set(&self, v: f64) -> f64 {
284 f64::from_bits(self.swap(f64::to_bits(v), Ordering::Relaxed))
285 }
286
287 fn get(&self) -> f64 {
288 f64::from_bits(self.load(Ordering::Relaxed))
289 }
290}
291
292impl Atomic<f32> for AtomicU32 {
293 fn inc(&self) -> f32 {
294 self.inc_by(1.0)
295 }
296
297 fn inc_by(&self, v: f32) -> f32 {
298 let mut old_u32 = self.load(Ordering::Relaxed);
299 let mut old_f32;
300 loop {
301 old_f32 = f32::from_bits(old_u32);
302 let new = f32::to_bits(old_f32 + v);
303 match self.compare_exchange_weak(old_u32, new, Ordering::Relaxed, Ordering::Relaxed) {
304 Ok(_) => break,
305 Err(x) => old_u32 = x,
306 }
307 }
308
309 old_f32
310 }
311
312 fn dec(&self) -> f32 {
313 self.dec_by(1.0)
314 }
315
316 fn dec_by(&self, v: f32) -> f32 {
317 let mut old_u32 = self.load(Ordering::Relaxed);
318 let mut old_f32;
319 loop {
320 old_f32 = f32::from_bits(old_u32);
321 let new = f32::to_bits(old_f32 - v);
322 match self.compare_exchange_weak(old_u32, new, Ordering::Relaxed, Ordering::Relaxed) {
323 Ok(_) => break,
324 Err(x) => old_u32 = x,
325 }
326 }
327
328 old_f32
329 }
330
331 fn set(&self, v: f32) -> f32 {
332 f32::from_bits(self.swap(f32::to_bits(v), Ordering::Relaxed))
333 }
334
335 fn get(&self) -> f32 {
336 f32::from_bits(self.load(Ordering::Relaxed))
337 }
338}
339
340impl<N, A> TypedMetric for Gauge<N, A> {
341 const TYPE: MetricType = MetricType::Gauge;
342}
343
344impl<N, A> EncodeMetric for Gauge<N, A>
345where
346 N: EncodeGaugeValue,
347 A: Atomic<N>,
348{
349 fn encode(&self, mut encoder: MetricEncoder) -> Result<(), std::fmt::Error> {
350 encoder.encode_gauge(&self.get())
351 }
352 fn metric_type(&self) -> MetricType {
353 Self::TYPE
354 }
355}
356
357#[derive(Debug, Default)]
361pub struct ConstGauge<N = i64> {
362 value: N,
363}
364
365impl<N> ConstGauge<N> {
366 pub fn new(value: N) -> Self {
368 Self { value }
369 }
370}
371
372impl<N> TypedMetric for ConstGauge<N> {
373 const TYPE: MetricType = MetricType::Gauge;
374}
375
376impl<N> EncodeMetric for ConstGauge<N>
377where
378 N: EncodeGaugeValue,
379{
380 fn encode(&self, mut encoder: MetricEncoder) -> Result<(), std::fmt::Error> {
381 encoder.encode_gauge(&self.value)
382 }
383
384 fn metric_type(&self) -> MetricType {
385 Self::TYPE
386 }
387}
388
389#[cfg(test)]
390mod 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}