From de2723402f9f7604e1d4a7419ae11c3f14e9803d Mon Sep 17 00:00:00 2001 From: Qinxuan Chen Date: Thu, 7 Mar 2024 17:45:38 +0800 Subject: [PATCH] feat(metrics): support `Gauge` type (#191) Signed-off-by: koushiro --- CHANGELOG.md | 9 +++++++ Cargo.toml | 2 +- src/encoding.rs | 14 ++++++++-- src/encoding/protobuf.rs | 4 +++ src/encoding/text.rs | 13 +++++++-- src/metrics/gauge.rs | 58 +++++++++++++++++++++++++++++----------- 6 files changed, 79 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c83e85b..7b1533d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.22.2] + +### Added + +- Added `Gauge` implementation. + See [PR 191]. + +[PR 191]: https://github.com/prometheus/client_rust/pull/191 + ## [0.22.1] ### Added diff --git a/Cargo.toml b/Cargo.toml index ce4d0ce3..7e919c71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "prometheus-client" -version = "0.22.1" +version = "0.22.2" authors = ["Max Inden "] edition = "2021" description = "Open Metrics client library allowing users to natively instrument applications." diff --git a/src/encoding.rs b/src/encoding.rs index 24d0d729..23c60328 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -544,6 +544,12 @@ pub trait EncodeGaugeValue { fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error>; } +impl EncodeGaugeValue for u32 { + fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> { + encoder.encode_u32(*self) + } +} + impl EncodeGaugeValue for i64 { fn encode(&self, encoder: &mut GaugeValueEncoder) -> Result<(), std::fmt::Error> { encoder.encode_i64(*self) @@ -568,13 +574,17 @@ enum GaugeValueEncoderInner<'a> { } impl<'a> GaugeValueEncoder<'a> { - fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> { - for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_f64(v)) + fn encode_u32(&mut self, v: u32) -> Result<(), std::fmt::Error> { + for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_u32(v)) } fn encode_i64(&mut self, v: i64) -> Result<(), std::fmt::Error> { for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_i64(v)) } + + fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> { + for_both_mut!(self, GaugeValueEncoderInner, e, e.encode_f64(v)) + } } impl<'a> From> for GaugeValueEncoder<'a> { diff --git a/src/encoding/protobuf.rs b/src/encoding/protobuf.rs index 53b30c3a..eef2731a 100644 --- a/src/encoding/protobuf.rs +++ b/src/encoding/protobuf.rs @@ -323,6 +323,10 @@ pub(crate) struct GaugeValueEncoder<'a> { } impl<'a> GaugeValueEncoder<'a> { + pub fn encode_u32(&mut self, v: u32) -> Result<(), std::fmt::Error> { + self.encode_i64(v as i64) + } + pub fn encode_i64(&mut self, v: i64) -> Result<(), std::fmt::Error> { *self.value = openmetrics_data_model::gauge_value::Value::IntValue(v); Ok(()) diff --git a/src/encoding/text.rs b/src/encoding/text.rs index adf42415..4acf1d51 100644 --- a/src/encoding/text.rs +++ b/src/encoding/text.rs @@ -423,9 +423,9 @@ impl<'a> std::fmt::Debug for GaugeValueEncoder<'a> { } impl<'a> GaugeValueEncoder<'a> { - pub fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> { + pub fn encode_u32(&mut self, v: u32) -> Result<(), std::fmt::Error> { self.writer.write_str(" ")?; - self.writer.write_str(dtoa::Buffer::new().format(v))?; + self.writer.write_str(itoa::Buffer::new().format(v))?; Ok(()) } @@ -434,6 +434,12 @@ impl<'a> GaugeValueEncoder<'a> { self.writer.write_str(itoa::Buffer::new().format(v))?; Ok(()) } + + pub fn encode_f64(&mut self, v: f64) -> Result<(), std::fmt::Error> { + self.writer.write_str(" ")?; + self.writer.write_str(dtoa::Buffer::new().format(v))?; + Ok(()) + } } pub(crate) struct ExemplarValueEncoder<'a> { @@ -565,6 +571,7 @@ mod tests { use crate::metrics::{counter::Counter, exemplar::CounterWithExemplar}; use pyo3::{prelude::*, types::PyModule}; use std::borrow::Cow; + use std::sync::atomic::AtomicU32; #[test] fn encode_counter() { @@ -632,6 +639,8 @@ mod tests { let mut registry = Registry::default(); let gauge: Gauge = Gauge::default(); registry.register("my_gauge", "My gauge", gauge); + let gauge = Gauge::::default(); + registry.register("u32_gauge", "Gauge::", gauge); let mut encoded = String::new(); diff --git a/src/metrics/gauge.rs b/src/metrics/gauge.rs index 98671280..7b268427 100644 --- a/src/metrics/gauge.rs +++ b/src/metrics/gauge.rs @@ -6,7 +6,7 @@ use crate::encoding::{EncodeGaugeValue, EncodeMetric, MetricEncoder}; use super::{MetricType, TypedMetric}; use std::marker::PhantomData; -use std::sync::atomic::{AtomicI32, Ordering}; +use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; #[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] use std::sync::atomic::{AtomicI64, AtomicU64}; use std::sync::Arc; @@ -134,55 +134,81 @@ pub trait Atomic { fn get(&self) -> N; } -#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] -impl Atomic for AtomicI64 { - fn inc(&self) -> i64 { +impl Atomic for AtomicI32 { + fn inc(&self) -> i32 { self.inc_by(1) } - fn inc_by(&self, v: i64) -> i64 { + fn inc_by(&self, v: i32) -> i32 { self.fetch_add(v, Ordering::Relaxed) } - fn dec(&self) -> i64 { + fn dec(&self) -> i32 { self.dec_by(1) } - fn dec_by(&self, v: i64) -> i64 { + fn dec_by(&self, v: i32) -> i32 { self.fetch_sub(v, Ordering::Relaxed) } - fn set(&self, v: i64) -> i64 { + fn set(&self, v: i32) -> i32 { self.swap(v, Ordering::Relaxed) } - fn get(&self) -> i64 { + fn get(&self) -> i32 { self.load(Ordering::Relaxed) } } -impl Atomic for AtomicI32 { - fn inc(&self) -> i32 { +impl Atomic for AtomicU32 { + fn inc(&self) -> u32 { self.inc_by(1) } - fn inc_by(&self, v: i32) -> i32 { + fn inc_by(&self, v: u32) -> u32 { self.fetch_add(v, Ordering::Relaxed) } - fn dec(&self) -> i32 { + fn dec(&self) -> u32 { self.dec_by(1) } - fn dec_by(&self, v: i32) -> i32 { + fn dec_by(&self, v: u32) -> u32 { self.fetch_sub(v, Ordering::Relaxed) } - fn set(&self, v: i32) -> i32 { + fn set(&self, v: u32) -> u32 { self.swap(v, Ordering::Relaxed) } - fn get(&self) -> i32 { + fn get(&self) -> u32 { + self.load(Ordering::Relaxed) + } +} + +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] +impl Atomic for AtomicI64 { + fn inc(&self) -> i64 { + self.inc_by(1) + } + + fn inc_by(&self, v: i64) -> i64 { + self.fetch_add(v, Ordering::Relaxed) + } + + fn dec(&self) -> i64 { + self.dec_by(1) + } + + fn dec_by(&self, v: i64) -> i64 { + self.fetch_sub(v, Ordering::Relaxed) + } + + fn set(&self, v: i64) -> i64 { + self.swap(v, Ordering::Relaxed) + } + + fn get(&self) -> i64 { self.load(Ordering::Relaxed) } }