From 6aafa61c5ba07422d7b8caa2482f6183e6f687cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Dec 2021 13:50:26 +0100 Subject: [PATCH 01/76] build(deps): update dtoa requirement from 0.4 to 1.0 (#27) * build(deps): update dtoa requirement from 0.4 to 1.0 Updates the requirements on [dtoa](https://github.com/dtolnay/dtoa) to permit the latest version. - [Release notes](https://github.com/dtolnay/dtoa/releases) - [Commits](https://github.com/dtolnay/dtoa/compare/0.4.0...1.0.1) --- updated-dependencies: - dependency-name: dtoa dependency-type: direct:production ... Signed-off-by: dependabot[bot] * src/encoding/text: Adjust to breaking changes in dtoa Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Max Inden Signed-off-by: ackintosh --- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- src/encoding/text.rs | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e59e1e49..77b475ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Update to `itoa` `v1`. See [PR 28]. +- Update to `dtoa` `v1`. See [PR 27]. [PR 28]: https://github.com/mxinden/rust-open-metrics-client/pull/28 +[PR 27]: https://github.com/mxinden/rust-open-metrics-client/pull/27 ## [0.13.0] - 2021-11-21 diff --git a/Cargo.toml b/Cargo.toml index cbd1b68d..807712f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ documentation = "https://docs.rs/open-metrics-client" members = ["derive-text-encode"] [dependencies] -dtoa = "0.4" +dtoa = "1.0" itoa = "1.0" owning_ref = "0.4" open-metrics-client-derive-text-encode = { version = "0.1.1", path = "derive-text-encode" } diff --git a/src/encoding/text.rs b/src/encoding/text.rs index 9f3cec2c..549be3f4 100644 --- a/src/encoding/text.rs +++ b/src/encoding/text.rs @@ -97,8 +97,8 @@ pub trait Encode { } impl Encode for f64 { - fn encode(&self, mut writer: &mut dyn Write) -> Result<(), std::io::Error> { - dtoa::write(&mut writer, *self)?; + fn encode(&self, writer: &mut dyn Write) -> Result<(), std::io::Error> { + writer.write_all(dtoa::Buffer::new().format(*self).as_bytes())?; Ok(()) } } From 638d84e42f9c216a423ee4eeff4b7210ba39f758 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 29 Dec 2021 18:05:18 +0100 Subject: [PATCH 02/76] src/metrics/gauge: Implement Gauge::dec and Gauge::dec_by (#30) Signed-off-by: ackintosh --- CHANGELOG.md | 7 +++++- Cargo.toml | 2 +- src/metrics/gauge.rs | 57 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77b475ff..27e59f06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,15 +4,20 @@ 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.13.1] - unreleased +## [0.14.0] - unreleased ### Changed - Update to `itoa` `v1`. See [PR 28]. - Update to `dtoa` `v1`. See [PR 27]. +### Added + +- Implement `Gauge::dec` and `Gauge::dec_by`. See [PR 30]. + [PR 28]: https://github.com/mxinden/rust-open-metrics-client/pull/28 [PR 27]: https://github.com/mxinden/rust-open-metrics-client/pull/27 +[PR 30]: https://github.com/mxinden/rust-open-metrics-client/pull/30 ## [0.13.0] - 2021-11-21 diff --git a/Cargo.toml b/Cargo.toml index 807712f5..c3ea0be2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "open-metrics-client" -version = "0.13.1" +version = "0.14.0" authors = ["Max Inden "] edition = "2018" description = "Open Metrics client library allowing users to natively instrument applications." diff --git a/src/metrics/gauge.rs b/src/metrics/gauge.rs index 8c64bab6..bcbc11f7 100644 --- a/src/metrics/gauge.rs +++ b/src/metrics/gauge.rs @@ -70,6 +70,16 @@ impl> Gauge { self.value.inc_by(v) } + /// Decrease the [`Gauge`] by 1, returning the previous value. + pub fn dec(&self) -> N { + self.value.dec() + } + + /// Decrease the [`Gauge`] by `v`, returning the previous value. + pub fn dec_by(&self, v: N) -> N { + self.value.dec_by(v) + } + /// Sets the [`Gauge`] to `v`, returning the previous value. pub fn set(&self, v: N) -> N { self.value.set(v) @@ -94,6 +104,10 @@ pub trait Atomic { fn inc_by(&self, v: N) -> N; + fn dec(&self) -> N; + + fn dec_by(&self, v: N) -> N; + fn set(&self, v: N) -> N; fn get(&self) -> N; @@ -108,6 +122,14 @@ impl Atomic for AtomicU64 { self.fetch_add(v, Ordering::Relaxed) } + fn dec(&self) -> u64 { + self.dec_by(1) + } + + fn dec_by(&self, v: u64) -> u64 { + self.fetch_sub(v, Ordering::Relaxed) + } + fn set(&self, v: u64) -> u64 { self.swap(v, Ordering::Relaxed) } @@ -126,6 +148,14 @@ impl Atomic for AtomicU32 { self.fetch_add(v, Ordering::Relaxed) } + fn dec(&self) -> u32 { + self.dec_by(1) + } + + fn dec_by(&self, v: u32) -> u32 { + self.fetch_sub(v, Ordering::Relaxed) + } + fn set(&self, v: u32) -> u32 { self.swap(v, Ordering::Relaxed) } @@ -155,6 +185,25 @@ impl Atomic for AtomicU64 { old_f64 } + fn dec(&self) -> f64 { + self.dec_by(1.0) + } + + fn dec_by(&self, v: f64) -> f64 { + let mut old_u64 = self.load(Ordering::Relaxed); + let mut old_f64; + loop { + old_f64 = f64::from_bits(old_u64); + let new = f64::to_bits(old_f64 - v); + match self.compare_exchange_weak(old_u64, new, Ordering::Relaxed, Ordering::Relaxed) { + Ok(_) => break, + Err(x) => old_u64 = x, + } + } + + old_f64 + } + fn set(&self, v: f64) -> f64 { f64::from_bits(self.swap(f64::to_bits(v), Ordering::Relaxed)) } @@ -173,11 +222,15 @@ mod tests { use super::*; #[test] - fn inc_and_get() { + fn inc_dec_and_get() { let gauge: Gauge = Gauge::default(); assert_eq!(0, gauge.inc()); assert_eq!(1, gauge.get()); - assert_eq!(1, gauge.set(10)); + + assert_eq!(1, gauge.dec()); + assert_eq!(0, gauge.get()); + + assert_eq!(0, gauge.set(10)); assert_eq!(10, gauge.get()); } } From 132b7f4ab0a3827fe795a74b520098cd2bb2f104 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 29 Dec 2021 18:06:14 +0100 Subject: [PATCH 03/76] CHANGELOG: Prepare v0.14.0 Signed-off-by: ackintosh --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27e59f06..d5eb235a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ 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.14.0] - unreleased +## [0.14.0] - 2021-12-29 ### Changed From 1ae51af976e87c02610b3b1b05f65f642870fdff Mon Sep 17 00:00:00 2001 From: Max Inden Date: Sun, 16 Jan 2022 21:28:29 +0100 Subject: [PATCH 04/76] *: Rename to prometheus-client (#32) - Move repository from https://github.com/mxinden/rust-open-metrics-client to https://github.com/prometheus/client_rust. - Rename crate from `open-metrics-client` to `prometheus-client`. - Rename import paths from `open_metrics_client` to `prometheus_client`. See https://groups.google.com/g/prometheus-developers/c/E67ByGmVQKM for details. Signed-off-by: Max Inden Signed-off-by: ackintosh --- CHANGELOG.md | 22 ++++++++++----------- Cargo.toml | 10 +++++----- README.md | 10 +++++----- benches/encoding/text.rs | 10 +++++----- benches/family.rs | 4 ++-- derive-text-encode/Cargo.toml | 12 ++++++------ derive-text-encode/src/lib.rs | 4 ++-- derive-text-encode/tests/lib.rs | 8 ++++---- examples/tide.rs | 8 ++++---- src/encoding/text.rs | 8 ++++---- src/lib.rs | 12 ++++++------ src/metrics/counter.rs | 4 ++-- src/metrics/exemplar.rs | 6 +++--- src/metrics/family.rs | 34 ++++++++++++++++----------------- src/metrics/gauge.rs | 4 ++-- src/metrics/histogram.rs | 2 +- src/metrics/info.rs | 2 +- src/registry.rs | 20 +++++++++---------- 18 files changed, 90 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5eb235a..980694a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Implement `Gauge::dec` and `Gauge::dec_by`. See [PR 30]. -[PR 28]: https://github.com/mxinden/rust-open-metrics-client/pull/28 -[PR 27]: https://github.com/mxinden/rust-open-metrics-client/pull/27 -[PR 30]: https://github.com/mxinden/rust-open-metrics-client/pull/30 +[PR 28]: https://github.com/prometheus/client_rust/pull/28 +[PR 27]: https://github.com/prometheus/client_rust/pull/27 +[PR 30]: https://github.com/prometheus/client_rust/pull/30 ## [0.13.0] - 2021-11-21 @@ -28,8 +28,8 @@ including a breaking change. See [PR 24] for details._ - Allow family to use constructors that do not coerce to function pointers. See [PR 21]. -[PR 21]: https://github.com/mxinden/rust-open-metrics-client/pull/21 -[PR 24]: https://github.com/mxinden/rust-open-metrics-client/pull/24 +[PR 21]: https://github.com/prometheus/client_rust/pull/21 +[PR 24]: https://github.com/prometheus/client_rust/pull/24 ## [0.12.0] - 2021-08-07 @@ -42,7 +42,7 @@ including a breaking change. See [PR 24] for details._ - Rename `Registry::sub_registry` to `Registry::sub_registry_with_prefix`. See [PR 20]. -[PR 20]: https://github.com/mxinden/rust-open-metrics-client/pull/20 +[PR 20]: https://github.com/prometheus/client_rust/pull/20 ## [0.11.2] - 2021-06-09 ### Fixed @@ -56,24 +56,24 @@ including a breaking change. See [PR 24] for details._ ### Added - Add support for OpenMetrics Info metrics (see [PR 18]). -[PR 18]: https://github.com/mxinden/rust-open-metrics-client/pull/18 +[PR 18]: https://github.com/prometheus/client_rust/pull/18 ## [0.10.1] - 2021-05-31 ### Added - Implement `Encode` for `u32`. ### Fixed -- Update to open-metrics-client-derive-text-encode v0.1.1 which handles keyword +- Update to prometheus-client-derive-text-encode v0.1.1 which handles keyword identifiers aka raw identifiers - https://github.com/mxinden/rust-open-metrics-client/pull/16 + https://github.com/prometheus/client_rust/pull/16 ## [0.10.0] - 2021-04-29 ### Added - Added `metrics::histogram::linear_buckets`. - https://github.com/mxinden/rust-open-metrics-client/issues/13 + https://github.com/prometheus/client_rust/issues/13 ### Changed - Renamed `metrics::histogram::exponential_series` to `metrics::histogram::exponential_buckets`. - https://github.com/mxinden/rust-open-metrics-client/issues/13 + https://github.com/prometheus/client_rust/issues/13 diff --git a/Cargo.toml b/Cargo.toml index c3ea0be2..8c9a6c53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,14 @@ [package] -name = "open-metrics-client" +name = "prometheus-client" version = "0.14.0" authors = ["Max Inden "] edition = "2018" description = "Open Metrics client library allowing users to natively instrument applications." license = "Apache-2.0 OR MIT" keywords = ["openmetrics", "prometheus", "metrics", "instrumentation", "monitoring"] -repository = "https://github.com/mxinden/rust-open-metrics-client" -homepage = "https://github.com/mxinden/rust-open-metrics-client" -documentation = "https://docs.rs/open-metrics-client" +repository = "https://github.com/prometheus/client_rust" +homepage = "https://github.com/prometheus/client_rust" +documentation = "https://docs.rs/prometheus-client" [workspace] members = ["derive-text-encode"] @@ -17,7 +17,7 @@ members = ["derive-text-encode"] dtoa = "1.0" itoa = "1.0" owning_ref = "0.4" -open-metrics-client-derive-text-encode = { version = "0.1.1", path = "derive-text-encode" } +prometheus-client-derive-text-encode = { version = "0.1.1", path = "derive-text-encode" } [dev-dependencies] async-std = { version = "1", features = ["attributes"] } diff --git a/README.md b/README.md index e7133570..fb599048 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -# Open Metrics Client Library +# Prometheus Rust client library -[![Test Status](https://github.com/mxinden/rust-open-metrics-client/actions/workflows/rust.yml/badge.svg?event=push)](https://github.com/mxinden/rust-open-metrics-client/actions) -[![Crate](https://img.shields.io/crates/v/open-metrics-client.svg)](https://crates.io/crates/open-metrics-client) -[![API](https://docs.rs/open-metrics-client/badge.svg)](https://docs.rs/open-metrics-client) +[![Test Status](https://github.com/prometheus/client_rust/actions/workflows/rust.yml/badge.svg?event=push)](https://github.com/prometheus/client_rust/actions) +[![Crate](https://img.shields.io/crates/v/prometheus-client.svg)](https://crates.io/crates/prometheus-client) +[![API](https://docs.rs/prometheus-client/badge.svg)](https://docs.rs/prometheus-client) [Rust](https://github.com/rust-lang/) client library implementation of the [Open Metrics specification](https://github.com/OpenObservability/OpenMetrics). Allows developers to instrument applications and thus enables operators to monitor said applications with monitoring systems like [Prometheus](https://prometheus.io/). -**Documentation**: https://docs.rs/open-metrics-client/ +**Documentation**: https://docs.rs/prometheus-client/ ## Goals diff --git a/benches/encoding/text.rs b/benches/encoding/text.rs index b739dfa1..9c3b450d 100644 --- a/benches/encoding/text.rs +++ b/benches/encoding/text.rs @@ -1,11 +1,11 @@ // Benchmark inspired by https://github.com/tikv/rust-prometheus/blob/ab1ca7285d3463504381a5025ae1951e020d6796/benches/text_encoder.rs use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use open_metrics_client::encoding::text::{encode, Encode, EncodeMetric}; -use open_metrics_client::metrics::counter::Counter; -use open_metrics_client::metrics::family::Family; -use open_metrics_client::metrics::histogram::{exponential_buckets, Histogram}; -use open_metrics_client::registry::Registry; +use prometheus_client::encoding::text::{encode, Encode, EncodeMetric}; +use prometheus_client::metrics::counter::Counter; +use prometheus_client::metrics::family::Family; +use prometheus_client::metrics::histogram::{exponential_buckets, Histogram}; +use prometheus_client::registry::Registry; use std::io::Write; use std::sync::atomic::AtomicU64; diff --git a/benches/family.rs b/benches/family.rs index 448d57c9..4fc50c6c 100644 --- a/benches/family.rs +++ b/benches/family.rs @@ -1,6 +1,6 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use open_metrics_client::metrics::counter::Counter; -use open_metrics_client::metrics::family::Family; +use prometheus_client::metrics::counter::Counter; +use prometheus_client::metrics::family::Family; pub fn family(c: &mut Criterion) { c.bench_function("counter family with Vec<(String, String)> label set", |b| { diff --git a/derive-text-encode/Cargo.toml b/derive-text-encode/Cargo.toml index c63211db..11e6b766 100644 --- a/derive-text-encode/Cargo.toml +++ b/derive-text-encode/Cargo.toml @@ -1,13 +1,13 @@ [package] -name = "open-metrics-client-derive-text-encode" +name = "prometheus-client-derive-text-encode" version = "0.1.1" authors = ["Max Inden "] edition = "2018" -description = "Auxiliary crate to derive text Encode trait from open-metrics-client." +description = "Auxiliary crate to derive text Encode trait from prometheus-client." license = "Apache-2.0 OR MIT" -repository = "https://github.com/mxinden/rust-open-metrics-client" -homepage = "https://github.com/mxinden/rust-open-metrics-client" -documentation = "https://docs.rs/open-metrics-client-derive-text-encode" +repository = "https://github.com/prometheus/client_rust" +homepage = "https://github.com/prometheus/client_rust" +documentation = "https://docs.rs/prometheus-client-derive-text-encode" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -17,7 +17,7 @@ quote = "1" syn = "1" [dev-dependencies] -open-metrics-client = { path = "../" } +prometheus-client = { path = "../" } [lib] proc-macro = true \ No newline at end of file diff --git a/derive-text-encode/src/lib.rs b/derive-text-encode/src/lib.rs index 8cc4e2a1..186aae43 100644 --- a/derive-text-encode/src/lib.rs +++ b/derive-text-encode/src/lib.rs @@ -31,7 +31,7 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { quote! { #maybe_comma writer.write_all(concat!(#ident_string, "=\"").as_bytes())?; - open_metrics_client::encoding::text::Encode::encode(&self.#ident, writer)?; + prometheus_client::encoding::text::Encode::encode(&self.#ident, writer)?; writer.write_all(b"\"")?; } }) @@ -62,7 +62,7 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { }; let gen = quote! { - impl open_metrics_client::encoding::text::Encode for #name { + impl prometheus_client::encoding::text::Encode for #name { fn encode(&self, writer: &mut dyn std::io::Write) -> std::result::Result<(), std::io::Error> { #body diff --git a/derive-text-encode/tests/lib.rs b/derive-text-encode/tests/lib.rs index d57c089b..00bc7617 100644 --- a/derive-text-encode/tests/lib.rs +++ b/derive-text-encode/tests/lib.rs @@ -1,7 +1,7 @@ -use open_metrics_client::encoding::text::{encode, Encode}; -use open_metrics_client::metrics::counter::Counter; -use open_metrics_client::metrics::family::Family; -use open_metrics_client::registry::Registry; +use prometheus_client::encoding::text::{encode, Encode}; +use prometheus_client::metrics::counter::Counter; +use prometheus_client::metrics::family::Family; +use prometheus_client::registry::Registry; #[test] fn basic_flow() { diff --git a/examples/tide.rs b/examples/tide.rs index 99b492f8..6b10f5ac 100644 --- a/examples/tide.rs +++ b/examples/tide.rs @@ -1,7 +1,7 @@ -use open_metrics_client::encoding::text::{encode, Encode}; -use open_metrics_client::metrics::counter::Counter; -use open_metrics_client::metrics::family::Family; -use open_metrics_client::registry::Registry; +use prometheus_client::encoding::text::{encode, Encode}; +use prometheus_client::metrics::counter::Counter; +use prometheus_client::metrics::family::Family; +use prometheus_client::registry::Registry; use std::sync::{Arc, Mutex}; diff --git a/src/encoding/text.rs b/src/encoding/text.rs index 549be3f4..9b18ad98 100644 --- a/src/encoding/text.rs +++ b/src/encoding/text.rs @@ -1,9 +1,9 @@ //! Open Metrics text format implementation. //! //! ``` -//! # use open_metrics_client::encoding::text::encode; -//! # use open_metrics_client::metrics::counter::Counter; -//! # use open_metrics_client::registry::Registry; +//! # use prometheus_client::encoding::text::encode; +//! # use prometheus_client::metrics::counter::Counter; +//! # use prometheus_client::registry::Registry; //! # //! # // Create registry and counter and register the latter with the former. //! # let mut registry = Registry::default(); @@ -38,7 +38,7 @@ use std::collections::HashMap; use std::io::Write; use std::ops::Deref; -pub use open_metrics_client_derive_text_encode::*; +pub use prometheus_client_derive_text_encode::*; pub fn encode(writer: &mut W, registry: &Registry) -> Result<(), std::io::Error> where diff --git a/src/lib.rs b/src/lib.rs index d39b566e..c492b0c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,11 +11,11 @@ //! # Examples //! //! ``` -//! # use open_metrics_client::encoding::text::Encode; -//! # use open_metrics_client::encoding::text::encode; -//! # use open_metrics_client::metrics::counter::{Atomic, Counter}; -//! # use open_metrics_client::metrics::family::Family; -//! # use open_metrics_client::registry::Registry; +//! # use prometheus_client::encoding::text::Encode; +//! # use prometheus_client::encoding::text::encode; +//! # use prometheus_client::metrics::counter::{Atomic, Counter}; +//! # use prometheus_client::metrics::family::Family; +//! # use prometheus_client::registry::Registry; //! # use std::io::Write; //! # //! // Create a metric registry. @@ -74,7 +74,7 @@ //! ``` //! See [examples] directory for more. //! -//! [examples]: https://github.com/mxinden/rust-open-metrics-client/tree/master/examples +//! [examples]: https://github.com/prometheus/client_rust/tree/master/examples pub mod encoding; pub mod metrics; diff --git a/src/metrics/counter.rs b/src/metrics/counter.rs index 27a8ce1f..fac0c309 100644 --- a/src/metrics/counter.rs +++ b/src/metrics/counter.rs @@ -21,7 +21,7 @@ use std::sync::Arc; /// ## Using [`AtomicU64`] as storage and [`u64`] on the interface /// /// ``` -/// # use open_metrics_client::metrics::counter::Counter; +/// # use prometheus_client::metrics::counter::Counter; /// let counter: Counter = Counter::default(); /// counter.inc(); /// let _value: u64 = counter.get(); @@ -30,7 +30,7 @@ use std::sync::Arc; /// ## Using [`AtomicU64`] as storage and [`f64`] on the interface /// /// ``` -/// # use open_metrics_client::metrics::counter::Counter; +/// # use prometheus_client::metrics::counter::Counter; /// # use std::sync::atomic::AtomicU64; /// let counter = Counter::::default(); /// counter.inc(); diff --git a/src/metrics/exemplar.rs b/src/metrics/exemplar.rs index 5a642137..90bb9fde 100644 --- a/src/metrics/exemplar.rs +++ b/src/metrics/exemplar.rs @@ -21,7 +21,7 @@ pub struct Exemplar { /// events and track references to data outside of the metric set. /// /// ``` -/// # use open_metrics_client::metrics::exemplar::CounterWithExemplar; +/// # use prometheus_client::metrics::exemplar::CounterWithExemplar; /// let counter_with_exemplar = CounterWithExemplar::>::default(); /// counter_with_exemplar.inc_by(1, Some(vec![("user_id".to_string(), "42".to_string())])); /// let _value: (u64, _) = counter_with_exemplar.get(); @@ -104,8 +104,8 @@ type RwLockGuardedCounterWithExemplar<'a, S, N, A> = /// and track references to data outside of the metric set. /// /// ``` -/// # use open_metrics_client::metrics::exemplar::HistogramWithExemplars; -/// # use open_metrics_client::metrics::histogram::exponential_buckets; +/// # use prometheus_client::metrics::exemplar::HistogramWithExemplars; +/// # use prometheus_client::metrics::histogram::exponential_buckets; /// let histogram = HistogramWithExemplars::new(exponential_buckets(1.0, 2.0, 10)); /// histogram.observe(4.2, Some(vec![("user_id".to_string(), "42".to_string())])); /// ``` diff --git a/src/metrics/family.rs b/src/metrics/family.rs index 36311e25..7d5d0e59 100644 --- a/src/metrics/family.rs +++ b/src/metrics/family.rs @@ -24,10 +24,10 @@ use std::sync::{Arc, RwLock, RwLockReadGuard}; /// ### [`Family`] with `Vec<(String, String)>` for convenience /// /// ``` -/// # use open_metrics_client::encoding::text::encode; -/// # use open_metrics_client::metrics::counter::{Atomic, Counter}; -/// # use open_metrics_client::metrics::family::Family; -/// # use open_metrics_client::registry::{Descriptor, Registry}; +/// # use prometheus_client::encoding::text::encode; +/// # use prometheus_client::metrics::counter::{Atomic, Counter}; +/// # use prometheus_client::metrics::family::Family; +/// # use prometheus_client::registry::{Descriptor, Registry}; /// # /// # let mut registry = Registry::default(); /// let family = Family::, Counter>::default(); @@ -57,11 +57,11 @@ use std::sync::{Arc, RwLock, RwLockReadGuard}; /// [`Encode`](crate::encoding::text::Encode) implementation. /// /// ``` -/// # use open_metrics_client::encoding::text::Encode; -/// # use open_metrics_client::encoding::text::encode; -/// # use open_metrics_client::metrics::counter::{Atomic, Counter}; -/// # use open_metrics_client::metrics::family::Family; -/// # use open_metrics_client::registry::{Descriptor, Registry}; +/// # use prometheus_client::encoding::text::Encode; +/// # use prometheus_client::encoding::text::encode; +/// # use prometheus_client::metrics::counter::{Atomic, Counter}; +/// # use prometheus_client::metrics::family::Family; +/// # use prometheus_client::registry::{Descriptor, Registry}; /// # use std::io::Write; /// # /// # let mut registry = Registry::default(); @@ -118,8 +118,8 @@ pub struct Family M> { /// capture variables. /// /// ``` -/// # use open_metrics_client::metrics::family::{Family, MetricConstructor}; -/// # use open_metrics_client::metrics::histogram::Histogram; +/// # use prometheus_client::metrics::family::{Family, MetricConstructor}; +/// # use prometheus_client::metrics::histogram::Histogram; /// struct CustomBuilder { /// buckets: Vec, /// } @@ -142,8 +142,8 @@ pub trait MetricConstructor { /// posible to directly provide a closure even if it captures variables. /// /// ``` -/// # use open_metrics_client::metrics::family::{Family}; -/// # use open_metrics_client::metrics::histogram::Histogram; +/// # use prometheus_client::metrics::family::{Family}; +/// # use prometheus_client::metrics::histogram::Histogram; /// let custom_buckets = vec![0.0, 10.0, 100.0]; /// let metric = Family::<(), Histogram, _>::new_with_constructor(|| { /// Histogram::new(custom_buckets.clone().into_iter()) @@ -181,8 +181,8 @@ impl Family { /// involved constructors see [`MetricConstructor`]. /// /// ``` - /// # use open_metrics_client::metrics::family::Family; - /// # use open_metrics_client::metrics::histogram::{exponential_buckets, Histogram}; + /// # use prometheus_client::metrics::family::Family; + /// # use prometheus_client::metrics::histogram::{exponential_buckets, Histogram}; /// Family::, Histogram>::new_with_constructor(|| { /// Histogram::new(exponential_buckets(1.0, 2.0, 10)) /// }); @@ -200,8 +200,8 @@ impl> Family, Counter>::default(); /// diff --git a/src/metrics/gauge.rs b/src/metrics/gauge.rs index bcbc11f7..b36fbeb0 100644 --- a/src/metrics/gauge.rs +++ b/src/metrics/gauge.rs @@ -21,7 +21,7 @@ use std::sync::Arc; /// ## Using [`AtomicU64`] as storage and [`u64`] on the interface /// /// ``` -/// # use open_metrics_client::metrics::gauge::Gauge; +/// # use prometheus_client::metrics::gauge::Gauge; /// let gauge: Gauge = Gauge::default(); /// gauge.set(42u64); /// let _value: u64 = gauge.get(); @@ -30,7 +30,7 @@ use std::sync::Arc; /// ## Using [`AtomicU64`] as storage and [`f64`] on the interface /// /// ``` -/// # use open_metrics_client::metrics::gauge::Gauge; +/// # use prometheus_client::metrics::gauge::Gauge; /// # use std::sync::atomic::AtomicU64; /// let gauge = Gauge::::default(); /// gauge.set(42.0); diff --git a/src/metrics/histogram.rs b/src/metrics/histogram.rs index 7fb91d50..177b49aa 100644 --- a/src/metrics/histogram.rs +++ b/src/metrics/histogram.rs @@ -10,7 +10,7 @@ use std::sync::{Arc, Mutex, MutexGuard}; /// Open Metrics [`Histogram`] to measure distributions of discrete events. /// /// ``` -/// # use open_metrics_client::metrics::histogram::{Histogram, exponential_buckets}; +/// # use prometheus_client::metrics::histogram::{Histogram, exponential_buckets}; /// let histogram = Histogram::new(exponential_buckets(1.0, 2.0, 10)); /// histogram.observe(4.2); /// ``` diff --git a/src/metrics/info.rs b/src/metrics/info.rs index 2eec8422..ffe52910 100644 --- a/src/metrics/info.rs +++ b/src/metrics/info.rs @@ -8,7 +8,7 @@ use crate::metrics::{MetricType, TypedMetric}; /// change during process lifetime". /// /// ``` -/// # use open_metrics_client::metrics::info::Info; +/// # use prometheus_client::metrics::info::Info; /// /// let _info = Info::new(vec![("os", "GNU/linux")]); /// ``` diff --git a/src/registry.rs b/src/registry.rs index bea07e39..9e28e580 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -20,10 +20,10 @@ use std::ops::Add; /// users might want to use their custom types. /// /// ``` -/// # use open_metrics_client::encoding::text::{encode, EncodeMetric}; -/// # use open_metrics_client::metrics::counter::{Atomic as _, Counter}; -/// # use open_metrics_client::metrics::gauge::{Atomic as _, Gauge}; -/// # use open_metrics_client::registry::Registry; +/// # use prometheus_client::encoding::text::{encode, EncodeMetric}; +/// # use prometheus_client::metrics::counter::{Atomic as _, Counter}; +/// # use prometheus_client::metrics::gauge::{Atomic as _, Gauge}; +/// # use prometheus_client::registry::Registry; /// # /// // Create a metric registry. /// // @@ -92,8 +92,8 @@ impl Registry { /// metric is known. /// /// ``` - /// # use open_metrics_client::metrics::counter::{Atomic as _, Counter}; - /// # use open_metrics_client::registry::{Registry, Unit}; + /// # use prometheus_client::metrics::counter::{Atomic as _, Counter}; + /// # use prometheus_client::registry::{Registry, Unit}; /// # /// let mut registry: Registry = Registry::default(); /// let counter = Counter::default(); @@ -113,8 +113,8 @@ impl Registry { /// unit to the name manually. /// /// ``` - /// # use open_metrics_client::metrics::counter::{Atomic as _, Counter}; - /// # use open_metrics_client::registry::{Registry, Unit}; + /// # use prometheus_client::metrics::counter::{Atomic as _, Counter}; + /// # use prometheus_client::registry::{Registry, Unit}; /// # /// let mut registry: Registry = Registry::default(); /// let counter = Counter::default(); @@ -172,8 +172,8 @@ impl Registry { /// subsystem registers. /// /// ``` - /// # use open_metrics_client::metrics::counter::{Atomic as _, Counter}; - /// # use open_metrics_client::registry::{Registry, Unit}; + /// # use prometheus_client::metrics::counter::{Atomic as _, Counter}; + /// # use prometheus_client::registry::{Registry, Unit}; /// # /// let mut registry: Registry = Registry::default(); /// From 4885fbebfc8f5ffe0fbb67752e08c2f3310327b8 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Sun, 16 Jan 2022 21:34:47 +0100 Subject: [PATCH 05/76] *: Prepare v0.15.0 Signed-off-by: ackintosh --- CHANGELOG.md | 6 ++++++ Cargo.toml | 4 ++-- derive-text-encode/Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 980694a6..c9fdce5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ 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.15.0] - 2022-01-16 + +### Changed + +- Release as `prometheus-client` and `prometheus-client-derive-text-encode`. + ## [0.14.0] - 2021-12-29 ### Changed diff --git a/Cargo.toml b/Cargo.toml index 8c9a6c53..ef6e6b91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "prometheus-client" -version = "0.14.0" +version = "0.15.0" authors = ["Max Inden "] edition = "2018" description = "Open Metrics client library allowing users to natively instrument applications." @@ -17,7 +17,7 @@ members = ["derive-text-encode"] dtoa = "1.0" itoa = "1.0" owning_ref = "0.4" -prometheus-client-derive-text-encode = { version = "0.1.1", path = "derive-text-encode" } +prometheus-client-derive-text-encode = { version = "0.2.0", path = "derive-text-encode" } [dev-dependencies] async-std = { version = "1", features = ["attributes"] } diff --git a/derive-text-encode/Cargo.toml b/derive-text-encode/Cargo.toml index 11e6b766..8bb06f1d 100644 --- a/derive-text-encode/Cargo.toml +++ b/derive-text-encode/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "prometheus-client-derive-text-encode" -version = "0.1.1" +version = "0.2.0" authors = ["Max Inden "] edition = "2018" description = "Auxiliary crate to derive text Encode trait from prometheus-client." From f6c468961313d6c0ecc4e31119d88b6f8e4cae4e Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Mon, 17 Jan 2022 15:46:35 +0100 Subject: [PATCH 06/76] *: Update common Prometheus files (#33) Signed-off-by: prombot Signed-off-by: ackintosh --- CODE_OF_CONDUCT.md | 3 +++ SECURITY.md | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 SECURITY.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..9a1aff41 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +## Prometheus Community Code of Conduct + +Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..67741f01 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,6 @@ +# Reporting a security issue + +The Prometheus security policy, including how to report vulnerabilities, can be +found here: + +https://prometheus.io/docs/operating/security/ From 55f673be3f3a61dd64ed31764ad1ba1cce03d2a3 Mon Sep 17 00:00:00 2001 From: Nick Pillitteri <56quarters@users.noreply.github.com> Date: Wed, 19 Jan 2022 15:13:11 -0500 Subject: [PATCH 07/76] src/lib: Make imports visible in example code (#35) Fixes #34 Signed-off-by: Nick Pillitteri Signed-off-by: ackintosh --- src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c492b0c5..add69623 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,13 +11,13 @@ //! # Examples //! //! ``` -//! # use prometheus_client::encoding::text::Encode; -//! # use prometheus_client::encoding::text::encode; -//! # use prometheus_client::metrics::counter::{Atomic, Counter}; -//! # use prometheus_client::metrics::family::Family; -//! # use prometheus_client::registry::Registry; -//! # use std::io::Write; -//! # +//! use prometheus_client::encoding::text::Encode; +//! use prometheus_client::encoding::text::encode; +//! use prometheus_client::metrics::counter::{Atomic, Counter}; +//! use prometheus_client::metrics::family::Family; +//! use prometheus_client::registry::Registry; +//! use std::io::Write; +//! //! // Create a metric registry. //! // //! // Note the angle brackets to make sure to use the default (dynamic From fed186652cdbe226bc540bd728c103a474539a4e Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 21 Jan 2022 14:12:46 +0100 Subject: [PATCH 08/76] .github/workflows: Add cross compilation step (#39) Signed-off-by: Max Inden Signed-off-by: ackintosh --- .github/workflows/rust.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 25ed51d7..65bd8a68 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -136,3 +136,24 @@ jobs: with: command: doc args: --verbose --workspace --no-deps --document-private-items + + cross-compile: + name: Cross compile + runs-on: ubuntu-latest + strategy: + matrix: + target: + - armv7-unknown-linux-gnueabihf + - powerpc64-unknown-linux-gnu + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: ${{ matrix.target }} + override: true + - uses: actions-rs/cargo@v1 + with: + use-cross: true + command: build + args: --release --target=${{ matrix.target }} From c80672d9b5900f9abdf2f5901a0680c4b78803a1 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 2 Feb 2022 21:50:46 +0100 Subject: [PATCH 09/76] src/encoding/text.rs: Expose Encoder methods (#41) By exposing the various `Encoder` builder methods, downstream users can implement their custom metrics using `EncodeMetric`. Showcase how to implement custom metric with example. Signed-off-by: Max Inden Signed-off-by: ackintosh --- CHANGELOG.md | 8 ++++++ Cargo.toml | 5 ++-- examples/custom-metric.rs | 52 +++++++++++++++++++++++++++++++++++++++ src/encoding/text.rs | 22 +++++++++++++---- 4 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 examples/custom-metric.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index c9fdce5c..3a09146d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ 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.15.1] - [unreleased] + +### Added + +- Expose `Encoder` methods. See [PR 41]. + +[PR 41]: https://github.com/prometheus/client_rust/pull/41 + ## [0.15.0] - 2022-01-16 ### Changed diff --git a/Cargo.toml b/Cargo.toml index ef6e6b91..8d244c71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "prometheus-client" -version = "0.15.0" +version = "0.15.1" authors = ["Max Inden "] edition = "2018" description = "Open Metrics client library allowing users to natively instrument applications." @@ -24,8 +24,9 @@ async-std = { version = "1", features = ["attributes"] } criterion = "0.3" http-types = "2" pyo3 = "0.15" -tide = "0.16" quickcheck = "1" +rand = "0.8.4" +tide = "0.16" [[bench]] name = "family" diff --git a/examples/custom-metric.rs b/examples/custom-metric.rs new file mode 100644 index 00000000..7fcda080 --- /dev/null +++ b/examples/custom-metric.rs @@ -0,0 +1,52 @@ +use prometheus_client::encoding::text::{encode, EncodeMetric, Encoder}; +use prometheus_client::metrics::MetricType; +use prometheus_client::registry::Registry; + +/// Showcasing encoding of custom metrics. +/// +/// Related to the concept of "Custom Collectors" in other implementations. +/// +/// [`MyCustomMetric`] generates and encodes a random number on each scrape. +struct MyCustomMetric {} + +impl EncodeMetric for MyCustomMetric { + fn encode(&self, mut encoder: Encoder) -> Result<(), std::io::Error> { + // This method is called on each Prometheus server scrape. Allowing you + // to execute whatever logic is needed to generate and encode your + // custom metric. + // + // While the `Encoder`'s builder pattern should guide you well and makes + // many mistakes impossible at the type level, do keep in mind that + // "with great power comes great responsibility". E.g. every CPU cycle + // spend in this method delays the response send to the Prometheus + // server. + + encoder + .no_suffix()? + .no_bucket()? + .encode_value(rand::random::())? + .no_exemplar()?; + + Ok(()) + } + + fn metric_type(&self) -> prometheus_client::metrics::MetricType { + MetricType::Unknown + } +} + +fn main() { + let mut registry = Registry::default(); + + let metric = MyCustomMetric {}; + registry.register( + "my_custom_metric", + "Custom metric returning a random number on each scrape", + metric, + ); + + let mut encoded = Vec::new(); + encode(&mut encoded, ®istry).unwrap(); + + println!("Scrape output:\n{:?}", String::from_utf8(encoded).unwrap()); +} diff --git a/src/encoding/text.rs b/src/encoding/text.rs index 9b18ad98..26bac582 100644 --- a/src/encoding/text.rs +++ b/src/encoding/text.rs @@ -217,6 +217,8 @@ impl Encode for () { } } +/// Helper type for [`EncodeMetric`], see [`EncodeMetric::encode`]. +/// // `Encoder` does not take a trait parameter for `writer` and `labels` because // `EncodeMetric` which uses `Encoder` needs to be usable as a trait object in // order to be able to register different metric types with a `Registry`. Trait @@ -232,6 +234,7 @@ pub struct Encoder<'a, 'b> { } impl<'a, 'b> Encoder<'a, 'b> { + /// Encode a metric suffix, e.g. in the case of [`Counter`] the suffic `_total`. pub fn encode_suffix(&mut self, suffix: &'static str) -> Result { self.write_name_and_unit()?; @@ -241,6 +244,7 @@ impl<'a, 'b> Encoder<'a, 'b> { self.encode_labels() } + /// Signal that the metric has no suffix. pub fn no_suffix(&mut self) -> Result { self.write_name_and_unit()?; @@ -285,6 +289,7 @@ impl<'a, 'b> Encoder<'a, 'b> { }) } + /// Encode a set of labels. Used by wrapper metric types like [`Family`]. pub fn with_label_set<'c, 'd>(&'c mut self, label_set: &'d dyn Encode) -> Encoder<'c, 'd> { debug_assert!(self.labels.is_none()); @@ -305,7 +310,8 @@ pub struct BucketEncoder<'a> { } impl<'a> BucketEncoder<'a> { - fn encode_bucket(&mut self, upper_bound: f64) -> Result { + /// Encode a bucket. Used for the [`Histogram`] metric type. + pub fn encode_bucket(&mut self, upper_bound: f64) -> Result { if self.opened_curly_brackets { self.writer.write_all(b",")?; } else { @@ -325,7 +331,8 @@ impl<'a> BucketEncoder<'a> { }) } - fn no_bucket(&mut self) -> Result { + /// Signal that the metric type has no bucket. + pub fn no_bucket(&mut self) -> Result { if self.opened_curly_brackets { self.writer.write_all(b"}")?; } @@ -341,7 +348,9 @@ pub struct ValueEncoder<'a> { } impl<'a> ValueEncoder<'a> { - fn encode_value(&mut self, v: V) -> Result { + /// Encode the metric value. E.g. in the case of [`Counter`] the + /// monotonically increasing counter value. + pub fn encode_value(&mut self, v: V) -> Result { self.writer.write_all(b" ")?; v.encode(self.writer)?; Ok(ExemplarEncoder { @@ -356,7 +365,8 @@ pub struct ExemplarEncoder<'a> { } impl<'a> ExemplarEncoder<'a> { - fn encode_exemplar( + /// Encode an exemplar for the given metric. + pub fn encode_exemplar( &mut self, exemplar: &Exemplar, ) -> Result<(), std::io::Error> { @@ -368,12 +378,14 @@ impl<'a> ExemplarEncoder<'a> { Ok(()) } - fn no_exemplar(&mut self) -> Result<(), std::io::Error> { + /// Signal that the metric type has no exemplar. + pub fn no_exemplar(&mut self) -> Result<(), std::io::Error> { self.writer.write_all(b"\n")?; Ok(()) } } +/// Trait implemented by each metric type, e.g. [`Counter`], to implement its encoding. pub trait EncodeMetric { fn encode(&self, encoder: Encoder) -> Result<(), std::io::Error>; From ef88152ac6d3883bda17b9699c9ad5bdb05ff18c Mon Sep 17 00:00:00 2001 From: Chitoku Date: Fri, 4 Feb 2022 02:44:45 +0900 Subject: [PATCH 10/76] src/metrics/: Don't use AtomicU64 on unsupported platforms (#42) Use `AtomicU32` on platforms that don't support `AtomicU64`. Co-authored-by: Max Inden Signed-off-by: ackintosh --- .github/workflows/rust.yml | 2 ++ CHANGELOG.md | 5 +++++ src/metrics/counter.rs | 14 +++++++++++++- src/metrics/exemplar.rs | 9 +++++++++ src/metrics/gauge.rs | 13 ++++++++++++- 5 files changed, 41 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 65bd8a68..f38e40ed 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -144,6 +144,8 @@ jobs: matrix: target: - armv7-unknown-linux-gnueabihf + - mipsel-unknown-linux-gnu + - powerpc-unknown-linux-gnu - powerpc64-unknown-linux-gnu steps: - uses: actions/checkout@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a09146d..ef84e363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Expose `Encoder` methods. See [PR 41]. +### Changed + +- Use `AtomicU32` on platforms that don't support `AtomicU64`. See [PR 42]. + [PR 41]: https://github.com/prometheus/client_rust/pull/41 +[PR 42]: https://github.com/prometheus/client_rust/pull/42 ## [0.15.0] - 2022-01-16 diff --git a/src/metrics/counter.rs b/src/metrics/counter.rs index fac0c309..c8ad9461 100644 --- a/src/metrics/counter.rs +++ b/src/metrics/counter.rs @@ -4,7 +4,9 @@ use super::{MetricType, TypedMetric}; use std::marker::PhantomData; -use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] +use std::sync::atomic::AtomicU64; +use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; /// Open Metrics [`Counter`] to measure discrete events. @@ -36,11 +38,18 @@ use std::sync::Arc; /// counter.inc(); /// let _value: f64 = counter.get(); /// ``` +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] pub struct Counter { value: Arc, phantom: PhantomData, } +#[cfg(any(target_arch = "mips", target_arch = "powerpc"))] +pub struct Counter { + value: Arc, + phantom: PhantomData, +} + impl Clone for Counter { fn clone(&self) -> Self { Self { @@ -96,6 +105,7 @@ pub trait Atomic { fn get(&self) -> N; } +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] impl Atomic for AtomicU64 { fn inc(&self) -> u64 { self.inc_by(1) @@ -124,6 +134,7 @@ impl Atomic for AtomicU32 { } } +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] impl Atomic for AtomicU64 { fn inc(&self) -> f64 { self.inc_by(1.0) @@ -165,6 +176,7 @@ mod tests { assert_eq!(1, counter.get()); } + #[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] #[test] fn f64_stored_in_atomic_u64() { fn prop(fs: Vec) { diff --git a/src/metrics/exemplar.rs b/src/metrics/exemplar.rs index 90bb9fde..66a043bb 100644 --- a/src/metrics/exemplar.rs +++ b/src/metrics/exemplar.rs @@ -6,6 +6,9 @@ use super::counter::{self, Counter}; use super::histogram::Histogram; use owning_ref::OwningRef; use std::collections::HashMap; +#[cfg(any(target_arch = "mips", target_arch = "powerpc"))] +use std::sync::atomic::AtomicU32; +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] use std::sync::atomic::AtomicU64; use std::sync::{Arc, RwLock, RwLockReadGuard}; @@ -26,10 +29,16 @@ pub struct Exemplar { /// counter_with_exemplar.inc_by(1, Some(vec![("user_id".to_string(), "42".to_string())])); /// let _value: (u64, _) = counter_with_exemplar.get(); /// ``` +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] pub struct CounterWithExemplar { pub(crate) inner: Arc>>, } +#[cfg(any(target_arch = "mips", target_arch = "powerpc"))] +pub struct CounterWithExemplar { + pub(crate) inner: Arc>>, +} + impl Clone for CounterWithExemplar { fn clone(&self) -> Self { CounterWithExemplar { diff --git a/src/metrics/gauge.rs b/src/metrics/gauge.rs index b36fbeb0..504d5bd9 100644 --- a/src/metrics/gauge.rs +++ b/src/metrics/gauge.rs @@ -4,7 +4,9 @@ use super::{MetricType, TypedMetric}; use std::marker::PhantomData; -use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] +use std::sync::atomic::AtomicU64; +use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; /// Open Metrics [`Gauge`] to record current measurements. @@ -36,11 +38,18 @@ use std::sync::Arc; /// gauge.set(42.0); /// let _value: f64 = gauge.get(); /// ``` +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] pub struct Gauge { value: Arc, phantom: PhantomData, } +#[cfg(any(target_arch = "mips", target_arch = "powerpc"))] +pub struct Gauge { + value: Arc, + phantom: PhantomData, +} + impl Clone for Gauge { fn clone(&self) -> Self { Self { @@ -113,6 +122,7 @@ pub trait Atomic { fn get(&self) -> N; } +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] impl Atomic for AtomicU64 { fn inc(&self) -> u64 { self.inc_by(1) @@ -165,6 +175,7 @@ impl Atomic for AtomicU32 { } } +#[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] impl Atomic for AtomicU64 { fn inc(&self) -> f64 { self.inc_by(1.0) From 463dce9f3abd89e9f54cd83383a3c5c814ed999c Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 4 Feb 2022 14:56:23 +0100 Subject: [PATCH 11/76] CHANGELOG: Prepare v0.15.1 (#44) Signed-off-by: Max Inden Signed-off-by: ackintosh --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef84e363..b9984b1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ 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.15.1] - [unreleased] +## [0.15.1] - 2022-02-04 ### Added From 1c9d81c8e7504850c201d7a937e5c02a8f04b896 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Feb 2022 23:15:29 +0900 Subject: [PATCH 12/76] Rough implementation to encode Counter Compile error: error[E0277]: the trait bound `Box: proto::EncodeMetric` is not satisfied --> src/encoding/proto.rs:151:33 | 151 | println!("{:?}", encode(®istry)); | ------ ^^^^^^^^^ the trait `proto::EncodeMetric` is not implemented for `Box` | | | required by a bound introduced by this call Signed-off-by: ackintosh --- Cargo.toml | 5 + build.rs | 6 + src/encoding.rs | 1 + src/encoding/proto.rs | 156 +++++++++++++ .../proto/openmetrics_data_model.proto | 214 ++++++++++++++++++ 5 files changed, 382 insertions(+) create mode 100644 build.rs create mode 100644 src/encoding/proto.rs create mode 100644 src/encoding/proto/openmetrics_data_model.proto diff --git a/Cargo.toml b/Cargo.toml index 8d244c71..17778203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,8 @@ dtoa = "1.0" itoa = "1.0" owning_ref = "0.4" prometheus-client-derive-text-encode = { version = "0.2.0", path = "derive-text-encode" } +prost = "0.9.0" +prost-types = "0.9.0" [dev-dependencies] async-std = { version = "1", features = ["attributes"] } @@ -28,6 +30,9 @@ quickcheck = "1" rand = "0.8.4" tide = "0.16" +[build-dependencies] +prost-build = "0.9.0" + [[bench]] name = "family" harness = false diff --git a/build.rs b/build.rs new file mode 100644 index 00000000..44c54667 --- /dev/null +++ b/build.rs @@ -0,0 +1,6 @@ +use std::io::Result; + +fn main() -> Result<()> { + prost_build::compile_protos(&["src/encoding/proto/openmetrics_data_model.proto"], &["src/encoding/proto/"])?; + Ok(()) +} diff --git a/src/encoding.rs b/src/encoding.rs index 07149d48..084e5100 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -1,3 +1,4 @@ //! Exposition format implementations. +pub mod proto; pub mod text; diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs new file mode 100644 index 00000000..ee0a945d --- /dev/null +++ b/src/encoding/proto.rs @@ -0,0 +1,156 @@ +// Include the `openmetrics_data_model` module, which is generated from `proto/openmetrics_data_model.proto`. +pub mod openmetrics_data_model { + include!(concat!(env!("OUT_DIR"), "/openmetrics.rs")); +} + +use std::ops::Deref; +use crate::registry::{Registry, Unit}; +use crate::metrics::counter::Counter; +use crate::metrics::MetricType; + +pub fn encode(registry: &Registry) -> openmetrics_data_model::MetricSet +where + M: EncodeMetric, +{ + // MetricSet + let mut metric_set = openmetrics_data_model::MetricSet::default(); + + for (desc, metric) in registry.iter() { + // MetricFamily + let mut family = openmetrics_data_model::MetricFamily::default(); + // MetricFamily.name + family.name = desc.name().to_string(); + // MetricFamily.type + family.r#type = { + let metric_type: openmetrics_data_model::MetricType = metric.metric_type().into(); + metric_type as i32 + }; + // MetricFamily.unit + if let Some(unit) = desc.unit() { + family.unit = match unit { + Unit::Amperes => "amperes", + Unit::Bytes => "bytes", + Unit::Celsius => "celsius", + Unit::Grams => "grams", + Unit::Joules => "joules", + Unit::Meters => "meters", + Unit::Ratios => "ratios", + Unit::Seconds => "seconds", + Unit::Volts => "volts", + Unit::Other(other) => other.as_str(), + }.to_string(); + } + // MetricFamily.help + family.help = desc.help().to_string(); + // Metric + let mut m = openmetrics_data_model::Metric::default(); + // Metric.labels + for l in desc.labels() { + let mut label = openmetrics_data_model::Label::default(); + label.name = l.0.to_string(); + label.value = l.1.to_string(); + m.labels.push(label); + } + // Metric.metric_points + m.metric_points.push(metric.encode()); + + family.metrics.push(m); + metric_set.metric_families.push(family); + } + + metric_set +} + +impl From for openmetrics_data_model::MetricType { + fn from(m: MetricType) -> Self { + match m { + MetricType::Counter => openmetrics_data_model::MetricType::Counter, + MetricType::Gauge => openmetrics_data_model::MetricType::Gauge, + MetricType::Histogram => openmetrics_data_model::MetricType::Histogram, + MetricType::Info => openmetrics_data_model::MetricType::Info, + MetricType::Unknown => openmetrics_data_model::MetricType::Unknown, + } + } +} + +/// Trait implemented by each metric type, e.g. [`Counter`], to implement its encoding. +pub trait EncodeMetric { + fn encode(&self) -> openmetrics_data_model::MetricPoint; + + fn metric_type(&self) -> MetricType; +} + +impl EncodeMetric for Box { + fn encode(&self) -> openmetrics_data_model::MetricPoint { + self.deref().encode() + } + + fn metric_type(&self) -> MetricType { + self.deref().metric_type() + } +} + +pub trait SendEncodeMetric: EncodeMetric + Send {} + +impl SendEncodeMetric for T {} + +impl EncodeMetric for Box { + fn encode(&self) -> openmetrics_data_model::MetricPoint { + self.deref().encode() + } + + fn metric_type(&self) -> MetricType { + self.deref().metric_type() + } +} + +///////////////////////////////////////////////////////////////////////////////// +// Counter + +impl EncodeMetric for Counter { + fn encode(&self) -> openmetrics_data_model::MetricPoint { + let metric_point = openmetrics_data_model::MetricPoint::default(); + // TODO: value + metric_point + } + + fn metric_type(&self) -> MetricType { + MetricType::Counter + } +} + +#[cfg(test)] +mod tests { + use std::borrow::Cow; + use crate::metrics::counter::Counter; + use crate::metrics::family::Family; + use crate::registry::Unit; + use super::*; + + #[test] + fn test_encode() { + let mut registry = ::default(); + + let counter: Counter = Counter::default(); + registry.register_with_unit("my_counter", "My counter", Unit::Seconds, Box::new(counter.clone())); + counter.inc(); + + let family = Family::, Counter>::default(); + let sub_registry = registry.sub_registry_with_label((Cow::Borrowed("my_key"), Cow::Borrowed("my_value"))); + sub_registry.register("my_counter_family", "My counter family", Box::new(family.clone())); + family + .get_or_create(&vec![ + ("method".to_string(), "GET".to_string()), + ("status".to_string(), "200".to_string()), + ]) + .inc(); + family + .get_or_create(&vec![ + ("method".to_string(), "POST".to_string()), + ("status".to_string(), "503".to_string()), + ]) + .inc(); + + println!("{:?}", encode(®istry)); + } +} diff --git a/src/encoding/proto/openmetrics_data_model.proto b/src/encoding/proto/openmetrics_data_model.proto new file mode 100644 index 00000000..a95942d9 --- /dev/null +++ b/src/encoding/proto/openmetrics_data_model.proto @@ -0,0 +1,214 @@ +syntax = "proto3"; + +// The OpenMetrics protobuf schema which defines the protobuf wire format. +// Ensure to interpret "required" as semantically required for a valid message. +// All string fields MUST be UTF-8 encoded strings. +package openmetrics; + +import "google/protobuf/timestamp.proto"; + +// The top-level container type that is encoded and sent over the wire. +message MetricSet { + // Each MetricFamily has one or more MetricPoints for a single Metric. + repeated MetricFamily metric_families = 1; +} + +// One or more Metrics for a single MetricFamily, where each Metric +// has one or more MetricPoints. +message MetricFamily { + // Required. + string name = 1; + + // Optional. + MetricType type = 2; + + // Optional. + string unit = 3; + + // Optional. + string help = 4; + + // Optional. + repeated Metric metrics = 5; +} + +// The type of a Metric. +enum MetricType { + // Unknown must use unknown MetricPoint values. + UNKNOWN = 0; + // Gauge must use gauge MetricPoint values. + GAUGE = 1; + // Counter must use counter MetricPoint values. + COUNTER = 2; + // State set must use state set MetricPoint values. + STATE_SET = 3; + // Info must use info MetricPoint values. + INFO = 4; + // Histogram must use histogram value MetricPoint values. + HISTOGRAM = 5; + // Gauge histogram must use histogram value MetricPoint values. + GAUGE_HISTOGRAM = 6; + // Summary quantiles must use summary value MetricPoint values. + SUMMARY = 7; +} + +// A single metric with a unique set of labels within a metric family. +message Metric { + // Optional. + repeated Label labels = 1; + + // Optional. + repeated MetricPoint metric_points = 2; +} + +// A name-value pair. These are used in multiple places: identifying +// timeseries, value of INFO metrics, and exemplars in Histograms. +message Label { + // Required. + string name = 1; + + // Required. + string value = 2; +} + +// A MetricPoint in a Metric. +message MetricPoint { + // Required. + oneof value { + UnknownValue unknown_value = 1; + GaugeValue gauge_value = 2; + CounterValue counter_value = 3; + HistogramValue histogram_value = 4; + StateSetValue state_set_value = 5; + InfoValue info_value = 6; + SummaryValue summary_value = 7; + } + + // Optional. + google.protobuf.Timestamp timestamp = 8; +} + +// Value for UNKNOWN MetricPoint. +message UnknownValue { + // Required. + oneof value { + double double_value = 1; + int64 int_value = 2; + } +} + +// Value for GAUGE MetricPoint. +message GaugeValue { + // Required. + oneof value { + double double_value = 1; + int64 int_value = 2; + } +} + +// Value for COUNTER MetricPoint. +message CounterValue { + // Required. + oneof total { + double double_value = 1; + uint64 int_value = 2; + } + + // The time values began being collected for this counter. + // Optional. + google.protobuf.Timestamp created = 3; + + // Optional. + Exemplar exemplar = 4; +} + +// Value for HISTOGRAM or GAUGE_HISTOGRAM MetricPoint. +message HistogramValue { + // Optional. + oneof sum { + double double_value = 1; + int64 int_value = 2; + } + + // Optional. + uint64 count = 3; + + // The time values began being collected for this histogram. + // Optional. + google.protobuf.Timestamp created = 4; + + // Optional. + repeated Bucket buckets = 5; + + // Bucket is the number of values for a bucket in the histogram + // with an optional exemplar. + message Bucket { + // Required. + uint64 count = 1; + + // Optional. + double upper_bound = 2; + + // Optional. + Exemplar exemplar = 3; + } +} + +message Exemplar { + // Required. + double value = 1; + + // Optional. + google.protobuf.Timestamp timestamp = 2; + + // Labels are additional information about the exemplar value (e.g. trace id). + // Optional. + repeated Label label = 3; +} + +// Value for STATE_SET MetricPoint. +message StateSetValue { + // Optional. + repeated State states = 1; + + message State { + // Required. + bool enabled = 1; + + // Required. + string name = 2; + } +} + +// Value for INFO MetricPoint. +message InfoValue { + // Optional. + repeated Label info = 1; +} + +// Value for SUMMARY MetricPoint. +message SummaryValue { + // Optional. + oneof sum { + double double_value = 1; + int64 int_value = 2; + } + + // Optional. + uint64 count = 3; + + // The time sum and count values began being collected for this summary. + // Optional. + google.protobuf.Timestamp created = 4; + + // Optional. + repeated Quantile quantile = 5; + + message Quantile { + // Required. + double quantile = 1; + + // Required. + double value = 2; + } +} From 0537cdff5019ada707e5c28962025906d42123e5 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 28 Feb 2022 18:33:46 +0100 Subject: [PATCH 13/76] src/encoding/proto: Construct Registry with proto::EncodeMetric Signed-off-by: ackintosh --- src/encoding/proto.rs | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index ee0a945d..f1e79030 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -3,10 +3,11 @@ pub mod openmetrics_data_model { include!(concat!(env!("OUT_DIR"), "/openmetrics.rs")); } -use std::ops::Deref; -use crate::registry::{Registry, Unit}; use crate::metrics::counter::Counter; +use crate::metrics::family::Family; use crate::metrics::MetricType; +use crate::registry::{Registry, Unit}; +use std::ops::Deref; pub fn encode(registry: &Registry) -> openmetrics_data_model::MetricSet where @@ -38,7 +39,8 @@ where Unit::Seconds => "seconds", Unit::Volts => "volts", Unit::Other(other) => other.as_str(), - }.to_string(); + } + .to_string(); } // MetricFamily.help family.help = desc.help().to_string(); @@ -119,25 +121,45 @@ impl EncodeMetric for Counter { } } +impl EncodeMetric for Family { + fn encode(&self) -> openmetrics_data_model::MetricPoint { + todo!() + } + + fn metric_type(&self) -> MetricType { + todo!() + } +} + #[cfg(test)] mod tests { - use std::borrow::Cow; + use super::*; use crate::metrics::counter::Counter; use crate::metrics::family::Family; use crate::registry::Unit; - use super::*; + use std::borrow::Cow; #[test] fn test_encode() { - let mut registry = ::default(); + let mut registry: Registry> = Registry::default(); let counter: Counter = Counter::default(); - registry.register_with_unit("my_counter", "My counter", Unit::Seconds, Box::new(counter.clone())); + registry.register_with_unit( + "my_counter", + "My counter", + Unit::Seconds, + Box::new(counter.clone()), + ); counter.inc(); let family = Family::, Counter>::default(); - let sub_registry = registry.sub_registry_with_label((Cow::Borrowed("my_key"), Cow::Borrowed("my_value"))); - sub_registry.register("my_counter_family", "My counter family", Box::new(family.clone())); + let sub_registry = + registry.sub_registry_with_label((Cow::Borrowed("my_key"), Cow::Borrowed("my_value"))); + sub_registry.register( + "my_counter_family", + "My counter family", + Box::new(family.clone()), + ); family .get_or_create(&vec![ ("method".to_string(), "GET".to_string()), From 3dcbc451a699bd3a1f259125668f44d03c2a46bf Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Mon, 14 Mar 2022 23:30:09 +0900 Subject: [PATCH 14/76] src/encoding/proto: Implement encoding for labels Signed-off-by: ackintosh --- build.rs | 5 +- src/encoding/proto.rs | 127 ++++++++++++++++++++++++++++++++---------- 2 files changed, 103 insertions(+), 29 deletions(-) diff --git a/build.rs b/build.rs index 44c54667..36a14ae6 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,9 @@ use std::io::Result; fn main() -> Result<()> { - prost_build::compile_protos(&["src/encoding/proto/openmetrics_data_model.proto"], &["src/encoding/proto/"])?; + prost_build::compile_protos( + &["src/encoding/proto/openmetrics_data_model.proto"], + &["src/encoding/proto/"], + )?; Ok(()) } diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index f1e79030..685477a3 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -4,8 +4,8 @@ pub mod openmetrics_data_model { } use crate::metrics::counter::Counter; -use crate::metrics::family::Family; -use crate::metrics::MetricType; +use crate::metrics::family::{Family, MetricConstructor}; +use crate::metrics::{MetricType, TypedMetric}; use crate::registry::{Registry, Unit}; use std::ops::Deref; @@ -44,19 +44,9 @@ where } // MetricFamily.help family.help = desc.help().to_string(); - // Metric - let mut m = openmetrics_data_model::Metric::default(); - // Metric.labels - for l in desc.labels() { - let mut label = openmetrics_data_model::Label::default(); - label.name = l.0.to_string(); - label.value = l.1.to_string(); - m.labels.push(label); - } - // Metric.metric_points - m.metric_points.push(metric.encode()); - - family.metrics.push(m); + println!("family.help: {}", family.help); + // MetricFamily.Metric + family.metrics = metric.encode(desc.labels().encode()); metric_set.metric_families.push(family); } @@ -77,14 +67,20 @@ impl From for openmetrics_data_model::MetricType { /// Trait implemented by each metric type, e.g. [`Counter`], to implement its encoding. pub trait EncodeMetric { - fn encode(&self) -> openmetrics_data_model::MetricPoint; + fn encode( + &self, + labels: Vec, + ) -> Vec; fn metric_type(&self) -> MetricType; } impl EncodeMetric for Box { - fn encode(&self) -> openmetrics_data_model::MetricPoint { - self.deref().encode() + fn encode( + &self, + labels: Vec, + ) -> Vec { + self.deref().encode(labels) } fn metric_type(&self) -> MetricType { @@ -97,8 +93,11 @@ pub trait SendEncodeMetric: EncodeMetric + Send {} impl SendEncodeMetric for T {} impl EncodeMetric for Box { - fn encode(&self) -> openmetrics_data_model::MetricPoint { - self.deref().encode() + fn encode( + &self, + labels: Vec, + ) -> Vec { + self.deref().encode(labels) } fn metric_type(&self) -> MetricType { @@ -106,14 +105,66 @@ impl EncodeMetric for Box { } } +pub trait EncodeLabel { + fn encode(&self) -> Vec; +} + +impl EncodeLabel for (K, V) { + fn encode(&self) -> Vec { + let mut label = openmetrics_data_model::Label::default(); + label.name = self.0.to_string(); + label.value = self.1.to_string(); + vec![label] + } +} + +impl EncodeLabel for Vec { + fn encode(&self) -> Vec { + let mut label = vec![]; + for t in self { + label.append(&mut t.encode()); + } + label + } +} + +impl EncodeLabel for &[T] { + fn encode(&self) -> Vec { + let mut label = vec![]; + for t in self.iter() { + label.append(&mut t.encode()); + } + label + } +} + ///////////////////////////////////////////////////////////////////////////////// // Counter impl EncodeMetric for Counter { - fn encode(&self) -> openmetrics_data_model::MetricPoint { - let metric_point = openmetrics_data_model::MetricPoint::default(); - // TODO: value - metric_point + fn encode( + &self, + labels: Vec, + ) -> Vec { + let mut metric = openmetrics_data_model::Metric::default(); + metric.labels = labels; + + metric.metric_points = { + let mut metric_point = openmetrics_data_model::MetricPoint::default(); + metric_point.value = { + let mut counter_value = openmetrics_data_model::CounterValue::default(); + counter_value.total = Some(openmetrics_data_model::counter_value::Total::IntValue( + self.get(), + )); + Some(openmetrics_data_model::metric_point::Value::CounterValue( + counter_value, + )) + }; + + vec![metric_point] + }; + + vec![metric] } fn metric_type(&self) -> MetricType { @@ -121,13 +172,33 @@ impl EncodeMetric for Counter { } } -impl EncodeMetric for Family { - fn encode(&self) -> openmetrics_data_model::MetricPoint { - todo!() +///////////////////////////////////////////////////////////////////////////////// +// Family + +impl EncodeMetric for Family +where + S: Clone + std::hash::Hash + Eq + EncodeLabel, + M: EncodeMetric + TypedMetric, + C: MetricConstructor, +{ + fn encode( + &self, + labels: Vec, + ) -> Vec { + let mut metrics = vec![]; + + let guard = self.read(); + for (label_set, metric) in guard.iter() { + let mut label = label_set.encode(); + label.append(&mut labels.clone()); + metrics.extend(metric.encode(label)); + } + + metrics } fn metric_type(&self) -> MetricType { - todo!() + M::TYPE } } From 6fd0693393f18d6d61f961a4983c52eb4d714388 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Tue, 15 Mar 2022 01:41:20 +0900 Subject: [PATCH 15/76] src/encoding/proto: Implement encoding for CounterWithExemplar Signed-off-by: ackintosh --- src/encoding/proto.rs | 126 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 110 insertions(+), 16 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 685477a3..c81dd1aa 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -4,8 +4,9 @@ pub mod openmetrics_data_model { } use crate::metrics::counter::Counter; +use crate::metrics::exemplar::{CounterWithExemplar, Exemplar}; use crate::metrics::family::{Family, MetricConstructor}; -use crate::metrics::{MetricType, TypedMetric}; +use crate::metrics::{counter, MetricType, TypedMetric}; use crate::registry::{Registry, Unit}; use std::ops::Deref; @@ -138,32 +139,67 @@ impl EncodeLabel for &[T] { } } +pub trait EncodeCounterValue { + fn encode(&self) -> openmetrics_data_model::counter_value::Total; +} + +impl EncodeCounterValue for u64 { + fn encode(&self) -> openmetrics_data_model::counter_value::Total { + openmetrics_data_model::counter_value::Total::IntValue(*self) + } +} + +impl EncodeCounterValue for f64 { + fn encode(&self) -> openmetrics_data_model::counter_value::Total { + openmetrics_data_model::counter_value::Total::DoubleValue(*self) + } +} + ///////////////////////////////////////////////////////////////////////////////// // Counter -impl EncodeMetric for Counter { +impl EncodeMetric for Counter +where + N: EncodeCounterValue, + A: counter::Atomic, +{ fn encode( &self, labels: Vec, ) -> Vec { - let mut metric = openmetrics_data_model::Metric::default(); + let mut metric = encode_counter(self.get(), None); metric.labels = labels; - metric.metric_points = { - let mut metric_point = openmetrics_data_model::MetricPoint::default(); - metric_point.value = { - let mut counter_value = openmetrics_data_model::CounterValue::default(); - counter_value.total = Some(openmetrics_data_model::counter_value::Total::IntValue( - self.get(), - )); - Some(openmetrics_data_model::metric_point::Value::CounterValue( - counter_value, - )) - }; - - vec![metric_point] + vec![metric] + } + + fn metric_type(&self) -> MetricType { + MetricType::Counter + } +} + +impl EncodeMetric for CounterWithExemplar +where + S: EncodeLabel, + N: Clone + EncodeCounterValue, + A: counter::Atomic, + f64: From, +{ + fn encode( + &self, + labels: Vec, + ) -> Vec { + let (value, exemplar) = self.get(); + + let exemplar_proto = if let Some(e) = exemplar.as_ref() { + Some(encode_exemplar(e)) + } else { + None }; + let mut metric = encode_counter(value.clone(), exemplar_proto); + metric.labels = labels; + vec![metric] } @@ -172,6 +208,46 @@ impl EncodeMetric for Counter { } } +fn encode_counter( + value: N, + exemplar: Option, +) -> openmetrics_data_model::Metric +where + N: EncodeCounterValue, +{ + let mut metric = openmetrics_data_model::Metric::default(); + + metric.metric_points = { + let mut metric_point = openmetrics_data_model::MetricPoint::default(); + metric_point.value = { + let mut counter_value = openmetrics_data_model::CounterValue::default(); + counter_value.total = Some(value.encode()); + counter_value.exemplar = exemplar; + + Some(openmetrics_data_model::metric_point::Value::CounterValue( + counter_value, + )) + }; + + vec![metric_point] + }; + + metric +} + +fn encode_exemplar(exemplar: &Exemplar) -> openmetrics_data_model::Exemplar +where + N: Clone, + S: EncodeLabel, + f64: From, // required because Exemplar.value is defined as `double` in protobuf +{ + let mut exemplar_proto = openmetrics_data_model::Exemplar::default(); + exemplar_proto.value = exemplar.value.clone().into(); + exemplar_proto.label = exemplar.label_set.encode(); + + exemplar_proto +} + ///////////////////////////////////////////////////////////////////////////////// // Family @@ -206,6 +282,7 @@ where mod tests { use super::*; use crate::metrics::counter::Counter; + use crate::metrics::exemplar::CounterWithExemplar; use crate::metrics::family::Family; use crate::registry::Unit; use std::borrow::Cow; @@ -246,4 +323,21 @@ mod tests { println!("{:?}", encode(®istry)); } + + #[test] + fn encode_counter_with_exemplar() { + let mut registry = Registry::default(); + + let counter_with_exemplar: CounterWithExemplar<(String, f64), f64> = + CounterWithExemplar::default(); + registry.register_with_unit( + "my_counter_with_exemplar", + "My counter with exemplar", + Unit::Seconds, + counter_with_exemplar.clone(), + ); + + counter_with_exemplar.inc_by(1.0, Some(("user_id".to_string(), 42.0))); + println!("{:?}", encode(®istry)); + } } From 8d89d6e350e2b38a4ab9ac7484254180f180c34f Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Sat, 19 Mar 2022 22:39:08 +0900 Subject: [PATCH 16/76] Move comment Signed-off-by: ackintosh --- src/encoding/proto.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index c81dd1aa..23877ece 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -139,6 +139,9 @@ impl EncodeLabel for &[T] { } } +///////////////////////////////////////////////////////////////////////////////// +// Counter + pub trait EncodeCounterValue { fn encode(&self) -> openmetrics_data_model::counter_value::Total; } @@ -155,9 +158,6 @@ impl EncodeCounterValue for f64 { } } -///////////////////////////////////////////////////////////////////////////////// -// Counter - impl EncodeMetric for Counter where N: EncodeCounterValue, From 2077ed770802cdbc218a0d3e8e7f73aac267cac2 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Sat, 19 Mar 2022 23:09:04 +0900 Subject: [PATCH 17/76] src/encoding/proto: Implement encoding for Gauge Signed-off-by: ackintosh --- src/encoding/proto.rs | 94 ++++++++++++++++++++++++++++++++++++++++++- src/metrics/gauge.rs | 28 ++++++++++++- 2 files changed, 119 insertions(+), 3 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 23877ece..84f5fb3e 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -6,7 +6,8 @@ pub mod openmetrics_data_model { use crate::metrics::counter::Counter; use crate::metrics::exemplar::{CounterWithExemplar, Exemplar}; use crate::metrics::family::{Family, MetricConstructor}; -use crate::metrics::{counter, MetricType, TypedMetric}; +use crate::metrics::gauge::Gauge; +use crate::metrics::{counter, gauge, MetricType, TypedMetric}; use crate::registry::{Registry, Unit}; use std::ops::Deref; @@ -45,7 +46,6 @@ where } // MetricFamily.help family.help = desc.help().to_string(); - println!("family.help: {}", family.help); // MetricFamily.Metric family.metrics = metric.encode(desc.labels().encode()); metric_set.metric_families.push(family); @@ -248,6 +248,60 @@ where exemplar_proto } +///////////////////////////////////////////////////////////////////////////////// +// Gauge + +pub trait EncodeGaugeValue { + fn encode(&self) -> openmetrics_data_model::gauge_value::Value; +} + +// GaugeValue.int_value is defined as `int64` in protobuf +impl EncodeGaugeValue for i64 { + fn encode(&self) -> openmetrics_data_model::gauge_value::Value { + openmetrics_data_model::gauge_value::Value::IntValue(*self) + } +} + +impl EncodeGaugeValue for f64 { + fn encode(&self) -> openmetrics_data_model::gauge_value::Value { + openmetrics_data_model::gauge_value::Value::DoubleValue(*self) + } +} + +impl EncodeMetric for Gauge +where + N: EncodeGaugeValue, + A: gauge::Atomic, +{ + fn encode( + &self, + labels: Vec, + ) -> Vec { + let mut metric = openmetrics_data_model::Metric::default(); + + metric.metric_points = { + let mut metric_point = openmetrics_data_model::MetricPoint::default(); + metric_point.value = { + let mut gauge_value = openmetrics_data_model::GaugeValue::default(); + gauge_value.value = Some(self.get().encode()); + + Some(openmetrics_data_model::metric_point::Value::GaugeValue( + gauge_value, + )) + }; + + vec![metric_point] + }; + + metric.labels = labels; + vec![metric] + } + + fn metric_type(&self) -> MetricType { + MetricType::Gauge + } +} + ///////////////////////////////////////////////////////////////////////////////// // Family @@ -284,8 +338,10 @@ mod tests { use crate::metrics::counter::Counter; use crate::metrics::exemplar::CounterWithExemplar; use crate::metrics::family::Family; + use crate::metrics::gauge::Gauge; use crate::registry::Unit; use std::borrow::Cow; + use std::sync::atomic::AtomicI64; #[test] fn test_encode() { @@ -340,4 +396,38 @@ mod tests { counter_with_exemplar.inc_by(1.0, Some(("user_id".to_string(), 42.0))); println!("{:?}", encode(®istry)); } + + #[test] + fn encode_gauge() { + let mut registry = Registry::default(); + let gauge = Gauge::::default(); + registry.register("my_gauge", "My gauge", gauge.clone()); + gauge.inc(); + + let metric_set = encode(®istry); + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_gauge", family.name); + assert_eq!( + openmetrics_data_model::MetricType::Gauge as i32, + family.r#type + ); + assert_eq!("My gauge.", family.help); + + let metric = family.metrics.first().unwrap(); + let gauge_value = openmetrics_data_model::metric_point::Value::GaugeValue({ + let mut v = openmetrics_data_model::GaugeValue::default(); + v.value = Some(openmetrics_data_model::gauge_value::Value::IntValue(1)); + v + }); + assert_eq!( + &gauge_value, + metric + .metric_points + .first() + .unwrap() + .value + .as_ref() + .unwrap() + ); + } } diff --git a/src/metrics/gauge.rs b/src/metrics/gauge.rs index 504d5bd9..3845a846 100644 --- a/src/metrics/gauge.rs +++ b/src/metrics/gauge.rs @@ -6,7 +6,7 @@ use super::{MetricType, TypedMetric}; use std::marker::PhantomData; #[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] use std::sync::atomic::AtomicU64; -use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::atomic::{AtomicI64, AtomicU32, Ordering}; use std::sync::Arc; /// Open Metrics [`Gauge`] to record current measurements. @@ -224,6 +224,32 @@ impl Atomic for AtomicU64 { } } +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) + } +} + impl TypedMetric for Gauge { const TYPE: MetricType = MetricType::Gauge; } From 229a4b03692f6b568a4d87667a62a85ee234091f Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Sun, 20 Mar 2022 16:22:58 +0900 Subject: [PATCH 18/76] src/encoding/proto: Implement encoding for Histogram Signed-off-by: ackintosh --- src/encoding/proto.rs | 84 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 84f5fb3e..d3bd2f45 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -7,6 +7,7 @@ use crate::metrics::counter::Counter; use crate::metrics::exemplar::{CounterWithExemplar, Exemplar}; use crate::metrics::family::{Family, MetricConstructor}; use crate::metrics::gauge::Gauge; +use crate::metrics::histogram::Histogram; use crate::metrics::{counter, gauge, MetricType, TypedMetric}; use crate::registry::{Registry, Unit}; use std::ops::Deref; @@ -332,6 +333,51 @@ where } } +///////////////////////////////////////////////////////////////////////////////// +// Histogram + +impl EncodeMetric for Histogram { + fn encode( + &self, + labels: Vec, + ) -> Vec { + let mut metric = openmetrics_data_model::Metric::default(); + + metric.metric_points = { + let mut metric_point = openmetrics_data_model::MetricPoint::default(); + metric_point.value = { + let mut histogram_value = openmetrics_data_model::HistogramValue::default(); + let (sum, count, buckets) = self.get(); + histogram_value.sum = Some( + openmetrics_data_model::histogram_value::Sum::DoubleValue(sum), + ); + histogram_value.count = count; + + let mut cummulative = 0; + for (_i, (upper_bound, count)) in buckets.iter().enumerate() { + cummulative += count; + let mut bucket = openmetrics_data_model::histogram_value::Bucket::default(); + bucket.count = cummulative; + bucket.upper_bound = *upper_bound; + histogram_value.buckets.push(bucket); + } + Some(openmetrics_data_model::metric_point::Value::HistogramValue( + histogram_value, + )) + }; + + vec![metric_point] + }; + + metric.labels = labels; + vec![metric] + } + + fn metric_type(&self) -> MetricType { + MetricType::Histogram + } +} + #[cfg(test)] mod tests { use super::*; @@ -339,6 +385,7 @@ mod tests { use crate::metrics::exemplar::CounterWithExemplar; use crate::metrics::family::Family; use crate::metrics::gauge::Gauge; + use crate::metrics::histogram::{exponential_buckets, Histogram}; use crate::registry::Unit; use std::borrow::Cow; use std::sync::atomic::AtomicI64; @@ -430,4 +477,41 @@ mod tests { .unwrap() ); } + + #[test] + fn encode_histogram() { + let mut registry = Registry::default(); + let histogram = Histogram::new(exponential_buckets(1.0, 2.0, 10)); + registry.register("my_histogram", "My histogram", histogram.clone()); + histogram.observe(1.0); + + let metric_set = encode(®istry); + let family = metric_set.metric_families.first().unwrap(); + assert_eq!( + openmetrics_data_model::MetricType::Histogram as i32, + family.r#type + ); + + let metric = family.metrics.first().unwrap(); + let metric_point_value = metric + .metric_points + .first() + .unwrap() + .value + .as_ref() + .unwrap(); + match metric_point_value { + openmetrics_data_model::metric_point::Value::HistogramValue(value) => { + assert_eq!( + Some(openmetrics_data_model::histogram_value::Sum::DoubleValue( + 1.0 + )), + value.sum + ); + assert_eq!(1, value.count); + assert_eq!(11, value.buckets.len()); + } + _ => assert!(false, "wrong value type"), + } + } } From 243e98a1b717f88ba15d90a613b6709ea2970efc Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Sun, 20 Mar 2022 16:47:55 +0900 Subject: [PATCH 19/76] src/encoding/proto: Tweak function name according to encoding::text Signed-off-by: ackintosh --- src/encoding/proto.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index d3bd2f45..b386e73a 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -168,7 +168,7 @@ where &self, labels: Vec, ) -> Vec { - let mut metric = encode_counter(self.get(), None); + let mut metric = encode_counter_with_maybe_exemplar(self.get(), None); metric.labels = labels; vec![metric] @@ -198,7 +198,7 @@ where None }; - let mut metric = encode_counter(value.clone(), exemplar_proto); + let mut metric = encode_counter_with_maybe_exemplar(value.clone(), exemplar_proto); metric.labels = labels; vec![metric] @@ -209,7 +209,7 @@ where } } -fn encode_counter( +fn encode_counter_with_maybe_exemplar( value: N, exemplar: Option, ) -> openmetrics_data_model::Metric From 1ecf2b631992a0313bad8aadd14478082e029877 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Mon, 21 Mar 2022 00:02:07 +0900 Subject: [PATCH 20/76] src/encoding/proto: Implement encoding for HistogramWithExemplars Signed-off-by: ackintosh --- src/encoding/proto.rs | 139 +++++++++++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 28 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index b386e73a..15eab1ff 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -4,12 +4,13 @@ pub mod openmetrics_data_model { } use crate::metrics::counter::Counter; -use crate::metrics::exemplar::{CounterWithExemplar, Exemplar}; +use crate::metrics::exemplar::{CounterWithExemplar, Exemplar, HistogramWithExemplars}; use crate::metrics::family::{Family, MetricConstructor}; use crate::metrics::gauge::Gauge; use crate::metrics::histogram::Histogram; use crate::metrics::{counter, gauge, MetricType, TypedMetric}; use crate::registry::{Registry, Unit}; +use std::collections::HashMap; use std::ops::Deref; pub fn encode(registry: &Registry) -> openmetrics_data_model::MetricSet @@ -140,6 +141,12 @@ impl EncodeLabel for &[T] { } } +impl EncodeLabel for () { + fn encode(&self) -> Vec { + vec![] + } +} + ///////////////////////////////////////////////////////////////////////////////// // Counter @@ -341,34 +348,30 @@ impl EncodeMetric for Histogram { &self, labels: Vec, ) -> Vec { - let mut metric = openmetrics_data_model::Metric::default(); - - metric.metric_points = { - let mut metric_point = openmetrics_data_model::MetricPoint::default(); - metric_point.value = { - let mut histogram_value = openmetrics_data_model::HistogramValue::default(); - let (sum, count, buckets) = self.get(); - histogram_value.sum = Some( - openmetrics_data_model::histogram_value::Sum::DoubleValue(sum), - ); - histogram_value.count = count; - - let mut cummulative = 0; - for (_i, (upper_bound, count)) in buckets.iter().enumerate() { - cummulative += count; - let mut bucket = openmetrics_data_model::histogram_value::Bucket::default(); - bucket.count = cummulative; - bucket.upper_bound = *upper_bound; - histogram_value.buckets.push(bucket); - } - Some(openmetrics_data_model::metric_point::Value::HistogramValue( - histogram_value, - )) - }; + let (sum, count, buckets) = self.get(); + // TODO: Would be better to use never type instead of `()`. + let mut metric = encode_histogram_with_maybe_exemplars::<()>(sum, count, &buckets, None); + metric.labels = labels; + vec![metric] + } - vec![metric_point] - }; + fn metric_type(&self) -> MetricType { + MetricType::Histogram + } +} +impl EncodeMetric for HistogramWithExemplars +where + S: EncodeLabel, +{ + fn encode( + &self, + labels: Vec, + ) -> Vec { + let inner = self.inner(); + let (sum, count, buckets) = inner.histogram.get(); + let mut metric = + encode_histogram_with_maybe_exemplars(sum, count, &buckets, Some(&inner.exemplars)); metric.labels = labels; vec![metric] } @@ -378,11 +381,51 @@ impl EncodeMetric for Histogram { } } +fn encode_histogram_with_maybe_exemplars( + sum: f64, + count: u64, + buckets: &[(f64, u64)], + exemplars: Option<&HashMap>>, +) -> openmetrics_data_model::Metric { + let mut metric = openmetrics_data_model::Metric::default(); + + metric.metric_points = { + let mut metric_point = openmetrics_data_model::MetricPoint::default(); + metric_point.value = { + let mut histogram_value = openmetrics_data_model::HistogramValue::default(); + histogram_value.sum = Some(openmetrics_data_model::histogram_value::Sum::DoubleValue( + sum, + )); + histogram_value.count = count; + + let mut cummulative = 0; + for (i, (upper_bound, count)) in buckets.iter().enumerate() { + cummulative += count; + let mut bucket = openmetrics_data_model::histogram_value::Bucket::default(); + bucket.count = cummulative; + bucket.upper_bound = *upper_bound; + bucket.exemplar = exemplars + .map(|es| es.get(&i)) + .flatten() + .map(|exemplar| encode_exemplar(exemplar)); + histogram_value.buckets.push(bucket); + } + Some(openmetrics_data_model::metric_point::Value::HistogramValue( + histogram_value, + )) + }; + + vec![metric_point] + }; + + metric +} + #[cfg(test)] mod tests { use super::*; use crate::metrics::counter::Counter; - use crate::metrics::exemplar::CounterWithExemplar; + use crate::metrics::exemplar::{CounterWithExemplar, HistogramWithExemplars}; use crate::metrics::family::Family; use crate::metrics::gauge::Gauge; use crate::metrics::histogram::{exponential_buckets, Histogram}; @@ -514,4 +557,44 @@ mod tests { _ => assert!(false, "wrong value type"), } } + + #[test] + fn encode_histogram_with_exemplars() { + let mut registry = Registry::default(); + let histogram = HistogramWithExemplars::new(exponential_buckets(1.0, 2.0, 10)); + registry.register("my_histogram", "My histogram", histogram.clone()); + histogram.observe(1.0, Some(("user_id".to_string(), 42u64))); + + let metric_set = encode(®istry); + let metric = metric_set + .metric_families + .first() + .unwrap() + .metrics + .first() + .unwrap(); + let metric_point_value = metric + .metric_points + .first() + .unwrap() + .value + .as_ref() + .unwrap(); + + match metric_point_value { + openmetrics_data_model::metric_point::Value::HistogramValue(value) => { + let exemplar = value.buckets.first().unwrap().exemplar.as_ref().unwrap(); + assert_eq!(1.0, exemplar.value); + + let expected_label = { + let mut label = openmetrics_data_model::Label::default(); + label.name = "user_id".to_string(); + label.value = "42".to_string(); + label + }; + assert_eq!(vec![expected_label], exemplar.label); + } + _ => assert!(false, "wrong value type"), + } + } } From 2edf381a5d1ce930f1e4960c8b8e8230ff3575a9 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Mon, 21 Mar 2022 00:05:17 +0900 Subject: [PATCH 21/76] src/encoding/proto: Move function for readability Signed-off-by: ackintosh --- src/encoding/proto.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 15eab1ff..37db2d03 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -147,6 +147,19 @@ impl EncodeLabel for () { } } +fn encode_exemplar(exemplar: &Exemplar) -> openmetrics_data_model::Exemplar + where + N: Clone, + S: EncodeLabel, + f64: From, // required because Exemplar.value is defined as `double` in protobuf +{ + let mut exemplar_proto = openmetrics_data_model::Exemplar::default(); + exemplar_proto.value = exemplar.value.clone().into(); + exemplar_proto.label = exemplar.label_set.encode(); + + exemplar_proto +} + ///////////////////////////////////////////////////////////////////////////////// // Counter @@ -243,19 +256,6 @@ where metric } -fn encode_exemplar(exemplar: &Exemplar) -> openmetrics_data_model::Exemplar -where - N: Clone, - S: EncodeLabel, - f64: From, // required because Exemplar.value is defined as `double` in protobuf -{ - let mut exemplar_proto = openmetrics_data_model::Exemplar::default(); - exemplar_proto.value = exemplar.value.clone().into(); - exemplar_proto.label = exemplar.label_set.encode(); - - exemplar_proto -} - ///////////////////////////////////////////////////////////////////////////////// // Gauge From 58ef300c63a407a254019832fef9d73d2cbe478f Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Mon, 21 Mar 2022 08:51:26 +0900 Subject: [PATCH 22/76] src/encoding/proto: Implement encoding for Info Signed-off-by: ackintosh --- src/encoding/proto.rs | 81 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 37db2d03..218e7dcc 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -8,6 +8,7 @@ use crate::metrics::exemplar::{CounterWithExemplar, Exemplar, HistogramWithExemp use crate::metrics::family::{Family, MetricConstructor}; use crate::metrics::gauge::Gauge; use crate::metrics::histogram::Histogram; +use crate::metrics::info::Info; use crate::metrics::{counter, gauge, MetricType, TypedMetric}; use crate::registry::{Registry, Unit}; use std::collections::HashMap; @@ -148,10 +149,10 @@ impl EncodeLabel for () { } fn encode_exemplar(exemplar: &Exemplar) -> openmetrics_data_model::Exemplar - where - N: Clone, - S: EncodeLabel, - f64: From, // required because Exemplar.value is defined as `double` in protobuf +where + N: Clone, + S: EncodeLabel, + f64: From, // required because Exemplar.value is defined as `double` in protobuf { let mut exemplar_proto = openmetrics_data_model::Exemplar::default(); exemplar_proto.value = exemplar.value.clone().into(); @@ -421,6 +422,44 @@ fn encode_histogram_with_maybe_exemplars( metric } +///////////////////////////////////////////////////////////////////////////////// +// Info + +impl EncodeMetric for Info +where + S: EncodeLabel, +{ + fn encode( + &self, + labels: Vec, + ) -> Vec { + let mut metric = openmetrics_data_model::Metric::default(); + + metric.metric_points = { + let mut metric_point = openmetrics_data_model::MetricPoint::default(); + metric_point.value = { + let mut label = self.0.encode(); + label.append(&mut labels.clone()); + + let mut info_value = openmetrics_data_model::InfoValue::default(); + info_value.info = label; + + Some(openmetrics_data_model::metric_point::Value::InfoValue( + info_value, + )) + }; + + vec![metric_point] + }; + + vec![metric] + } + + fn metric_type(&self) -> MetricType { + MetricType::Info + } +} + #[cfg(test)] mod tests { use super::*; @@ -429,6 +468,7 @@ mod tests { use crate::metrics::family::Family; use crate::metrics::gauge::Gauge; use crate::metrics::histogram::{exponential_buckets, Histogram}; + use crate::metrics::info::Info; use crate::registry::Unit; use std::borrow::Cow; use std::sync::atomic::AtomicI64; @@ -597,4 +637,37 @@ mod tests { _ => assert!(false, "wrong value type"), } } + + #[test] + fn encode_info() { + let mut registry = Registry::default(); + let info = Info::new(vec![("os".to_string(), "GNU/linux".to_string())]); + registry.register("my_info_metric", "My info metric", info); + + let metric_set = encode(®istry); + let metric = metric_set + .metric_families + .first() + .unwrap() + .metrics + .first() + .unwrap(); + let metric_point_value = metric + .metric_points + .first() + .unwrap() + .value + .as_ref() + .unwrap(); + + match metric_point_value { + openmetrics_data_model::metric_point::Value::InfoValue(value) => { + assert_eq!(1, value.info.len()); + let info = value.info.first().unwrap(); + assert_eq!("os", info.name); + assert_eq!("GNU/linux", info.value); + } + _ => assert!(false, "wrong value type"), + } + } } From 24a56ab357e9055c2943139d356787a4a4e6e177 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Mar 2022 15:13:38 +0900 Subject: [PATCH 23/76] src/encoding/proto: Add tests for Counter Signed-off-by: ackintosh --- src/encoding/proto.rs | 63 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 218e7dcc..a8b367a5 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -510,6 +510,48 @@ mod tests { println!("{:?}", encode(®istry)); } + #[test] + fn encode_counter_int() { + let counter: Counter = Counter::default(); + let mut registry = Registry::default(); + registry.register("my_counter", "My counter", counter.clone()); + counter.inc(); + + let metric_point_value = extract_metric_point_value(encode(®istry)); + + match metric_point_value { + openmetrics_data_model::metric_point::Value::CounterValue(value) => { + let expected = openmetrics_data_model::counter_value::Total::IntValue(1); + assert_eq!(Some(expected), value.total); + assert_eq!(None, value.exemplar); + assert_eq!(None, value.created); + } + _ => assert!(false, "wrong value type"), + } + } + + #[test] + fn encode_counter_double() { + // Using `f64` + let counter: Counter = Counter::default(); + let mut registry = Registry::default(); + registry.register("my_counter", "My counter", counter.clone()); + counter.inc(); + + let metric_point_value = extract_metric_point_value(encode(®istry)); + + match metric_point_value { + openmetrics_data_model::metric_point::Value::CounterValue(value) => { + // The counter should be encoded as `DoubleValue` + let expected = openmetrics_data_model::counter_value::Total::DoubleValue(1.0); + assert_eq!(Some(expected), value.total); + assert_eq!(None, value.exemplar); + assert_eq!(None, value.created); + } + _ => assert!(false, "wrong value type"), + } + } + #[test] fn encode_counter_with_exemplar() { let mut registry = Registry::default(); @@ -670,4 +712,25 @@ mod tests { _ => assert!(false, "wrong value type"), } } + + fn extract_metric_point_value( + metric_set: openmetrics_data_model::MetricSet, + ) -> openmetrics_data_model::metric_point::Value { + let metric = metric_set + .metric_families + .first() + .unwrap() + .metrics + .first() + .unwrap(); + + metric + .metric_points + .first() + .unwrap() + .value + .as_ref() + .unwrap() + .clone() + } } From e2a73103e14ec7b8a3f0e552720d34708345c066 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Mar 2022 21:41:02 +0900 Subject: [PATCH 24/76] src/encoding/proto: Add assertions for MetricType Signed-off-by: ackintosh --- src/encoding/proto.rs | 49 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index a8b367a5..e11c4ee0 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -517,9 +517,14 @@ mod tests { registry.register("my_counter", "My counter", counter.clone()); counter.inc(); - let metric_point_value = extract_metric_point_value(encode(®istry)); + let metric_set = encode(®istry); - match metric_point_value { + assert_eq!( + openmetrics_data_model::MetricType::Counter as i32, + extract_metric_type(&metric_set) + ); + + match extract_metric_point_value(metric_set) { openmetrics_data_model::metric_point::Value::CounterValue(value) => { let expected = openmetrics_data_model::counter_value::Total::IntValue(1); assert_eq!(Some(expected), value.total); @@ -538,9 +543,14 @@ mod tests { registry.register("my_counter", "My counter", counter.clone()); counter.inc(); - let metric_point_value = extract_metric_point_value(encode(®istry)); + let metric_set = encode(®istry); - match metric_point_value { + assert_eq!( + openmetrics_data_model::MetricType::Counter as i32, + extract_metric_type(&metric_set) + ); + + match extract_metric_point_value(metric_set) { openmetrics_data_model::metric_point::Value::CounterValue(value) => { // The counter should be encoded as `DoubleValue` let expected = openmetrics_data_model::counter_value::Total::DoubleValue(1.0); @@ -566,7 +576,15 @@ mod tests { ); counter_with_exemplar.inc_by(1.0, Some(("user_id".to_string(), 42.0))); - println!("{:?}", encode(®istry)); + + let metric_set = encode(®istry); + + assert_eq!( + openmetrics_data_model::MetricType::Counter as i32, + extract_metric_type(&metric_set) + ); + + // TODO: test the exemplar } #[test] @@ -581,7 +599,7 @@ mod tests { assert_eq!("my_gauge", family.name); assert_eq!( openmetrics_data_model::MetricType::Gauge as i32, - family.r#type + extract_metric_type(&metric_set) ); assert_eq!("My gauge.", family.help); @@ -614,7 +632,7 @@ mod tests { let family = metric_set.metric_families.first().unwrap(); assert_eq!( openmetrics_data_model::MetricType::Histogram as i32, - family.r#type + extract_metric_type(&metric_set) ); let metric = family.metrics.first().unwrap(); @@ -648,6 +666,12 @@ mod tests { histogram.observe(1.0, Some(("user_id".to_string(), 42u64))); let metric_set = encode(®istry); + + assert_eq!( + openmetrics_data_model::MetricType::Histogram as i32, + extract_metric_type(&metric_set) + ); + let metric = metric_set .metric_families .first() @@ -687,6 +711,12 @@ mod tests { registry.register("my_info_metric", "My info metric", info); let metric_set = encode(®istry); + + assert_eq!( + openmetrics_data_model::MetricType::Info as i32, + extract_metric_type(&metric_set) + ); + let metric = metric_set .metric_families .first() @@ -713,6 +743,11 @@ mod tests { } } + fn extract_metric_type(metric_set: &openmetrics_data_model::MetricSet) -> i32 { + let family = metric_set.metric_families.first().unwrap(); + family.r#type + } + fn extract_metric_point_value( metric_set: openmetrics_data_model::MetricSet, ) -> openmetrics_data_model::metric_point::Value { From 46e8e63d2b1d6ba6d43a986698d66973d1e9d33c Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Mar 2022 21:54:16 +0900 Subject: [PATCH 25/76] src/encoding/proto: DRY-ed tests with `extract_metric_point_value` Signed-off-by: ackintosh --- src/encoding/proto.rs | 73 +++++++++---------------------------------- 1 file changed, 14 insertions(+), 59 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index e11c4ee0..ff9cc9e9 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -597,28 +597,20 @@ mod tests { let metric_set = encode(®istry); let family = metric_set.metric_families.first().unwrap(); assert_eq!("my_gauge", family.name); + assert_eq!("My gauge.", family.help); + assert_eq!( openmetrics_data_model::MetricType::Gauge as i32, extract_metric_type(&metric_set) ); - assert_eq!("My gauge.", family.help); - let metric = family.metrics.first().unwrap(); - let gauge_value = openmetrics_data_model::metric_point::Value::GaugeValue({ - let mut v = openmetrics_data_model::GaugeValue::default(); - v.value = Some(openmetrics_data_model::gauge_value::Value::IntValue(1)); - v - }); - assert_eq!( - &gauge_value, - metric - .metric_points - .first() - .unwrap() - .value - .as_ref() - .unwrap() - ); + match extract_metric_point_value(metric_set) { + openmetrics_data_model::metric_point::Value::GaugeValue(value) => { + let expected = openmetrics_data_model::gauge_value::Value::IntValue(1); + assert_eq!(Some(expected), value.value); + } + _ => assert!(false, "wrong value type"), + } } #[test] @@ -629,21 +621,13 @@ mod tests { histogram.observe(1.0); let metric_set = encode(®istry); - let family = metric_set.metric_families.first().unwrap(); + assert_eq!( openmetrics_data_model::MetricType::Histogram as i32, extract_metric_type(&metric_set) ); - let metric = family.metrics.first().unwrap(); - let metric_point_value = metric - .metric_points - .first() - .unwrap() - .value - .as_ref() - .unwrap(); - match metric_point_value { + match extract_metric_point_value(metric_set) { openmetrics_data_model::metric_point::Value::HistogramValue(value) => { assert_eq!( Some(openmetrics_data_model::histogram_value::Sum::DoubleValue( @@ -672,22 +656,7 @@ mod tests { extract_metric_type(&metric_set) ); - let metric = metric_set - .metric_families - .first() - .unwrap() - .metrics - .first() - .unwrap(); - let metric_point_value = metric - .metric_points - .first() - .unwrap() - .value - .as_ref() - .unwrap(); - - match metric_point_value { + match extract_metric_point_value(metric_set) { openmetrics_data_model::metric_point::Value::HistogramValue(value) => { let exemplar = value.buckets.first().unwrap().exemplar.as_ref().unwrap(); assert_eq!(1.0, exemplar.value); @@ -717,24 +686,10 @@ mod tests { extract_metric_type(&metric_set) ); - let metric = metric_set - .metric_families - .first() - .unwrap() - .metrics - .first() - .unwrap(); - let metric_point_value = metric - .metric_points - .first() - .unwrap() - .value - .as_ref() - .unwrap(); - - match metric_point_value { + match extract_metric_point_value(metric_set) { openmetrics_data_model::metric_point::Value::InfoValue(value) => { assert_eq!(1, value.info.len()); + let info = value.info.first().unwrap(); assert_eq!("os", info.name); assert_eq!("GNU/linux", info.value); From 0855a0af53c653882c4ddb56b7682571f3c25e44 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Mar 2022 21:58:41 +0900 Subject: [PATCH 26/76] src/encoding/proto: Assert name and help Signed-off-by: ackintosh --- src/encoding/proto.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index ff9cc9e9..abb509c5 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -519,6 +519,10 @@ mod tests { let metric_set = encode(®istry); + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_counter", family.name); + assert_eq!("My counter.", family.help); + assert_eq!( openmetrics_data_model::MetricType::Counter as i32, extract_metric_type(&metric_set) @@ -545,6 +549,10 @@ mod tests { let metric_set = encode(®istry); + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_counter", family.name); + assert_eq!("My counter.", family.help); + assert_eq!( openmetrics_data_model::MetricType::Counter as i32, extract_metric_type(&metric_set) @@ -579,6 +587,10 @@ mod tests { let metric_set = encode(®istry); + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_counter_with_exemplar", family.name); + assert_eq!("My counter with exemplar.", family.help); + assert_eq!( openmetrics_data_model::MetricType::Counter as i32, extract_metric_type(&metric_set) @@ -622,6 +634,10 @@ mod tests { let metric_set = encode(®istry); + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_histogram", family.name); + assert_eq!("My histogram.", family.help); + assert_eq!( openmetrics_data_model::MetricType::Histogram as i32, extract_metric_type(&metric_set) @@ -651,6 +667,10 @@ mod tests { let metric_set = encode(®istry); + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_histogram", family.name); + assert_eq!("My histogram.", family.help); + assert_eq!( openmetrics_data_model::MetricType::Histogram as i32, extract_metric_type(&metric_set) @@ -681,6 +701,10 @@ mod tests { let metric_set = encode(®istry); + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_info_metric", family.name); + assert_eq!("My info metric.", family.help); + assert_eq!( openmetrics_data_model::MetricType::Info as i32, extract_metric_type(&metric_set) From f318b65c81fbfafe64a3bd151dc5df92b35966c5 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Mar 2022 22:07:10 +0900 Subject: [PATCH 27/76] src/encoding/proto: Refactor: use associated constants Signed-off-by: ackintosh --- src/encoding/proto.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index abb509c5..0b6d9ba5 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -196,7 +196,7 @@ where } fn metric_type(&self) -> MetricType { - MetricType::Counter + Self::TYPE } } @@ -226,7 +226,7 @@ where } fn metric_type(&self) -> MetricType { - MetricType::Counter + Counter::::TYPE } } @@ -307,7 +307,7 @@ where } fn metric_type(&self) -> MetricType { - MetricType::Gauge + Self::TYPE } } @@ -357,7 +357,7 @@ impl EncodeMetric for Histogram { } fn metric_type(&self) -> MetricType { - MetricType::Histogram + Self::TYPE } } @@ -378,7 +378,7 @@ where } fn metric_type(&self) -> MetricType { - MetricType::Histogram + Histogram::TYPE } } @@ -456,7 +456,7 @@ where } fn metric_type(&self) -> MetricType { - MetricType::Info + Self::TYPE } } From 223b2562dc05738873a9777342bfbb4de1c34feb Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Mar 2022 22:13:22 +0900 Subject: [PATCH 28/76] src/encoding/proto: Add assertions for counter.exemplar Signed-off-by: ackintosh --- src/encoding/proto.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 0b6d9ba5..9d0991f2 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -596,7 +596,25 @@ mod tests { extract_metric_type(&metric_set) ); - // TODO: test the exemplar + match extract_metric_point_value(metric_set) { + openmetrics_data_model::metric_point::Value::CounterValue(value) => { + // The counter should be encoded as `DoubleValue` + let expected = openmetrics_data_model::counter_value::Total::DoubleValue(1.0); + assert_eq!(Some(expected), value.total); + + let exemplar = value.exemplar.as_ref().unwrap(); + assert_eq!(1.0, exemplar.value); + + let expected_label = { + let mut label = openmetrics_data_model::Label::default(); + label.name = "user_id".to_string(); + label.value = "42".to_string(); + label + }; + assert_eq!(vec![expected_label], exemplar.label); + } + _ => assert!(false, "wrong value type"), + } } #[test] From 56da14d1df06ff20e5f08425f024f392e4e6cf44 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Mar 2022 22:19:43 +0900 Subject: [PATCH 29/76] src/encoding/proto: Add assertion for Unit Signed-off-by: ackintosh --- src/encoding/proto.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 9d0991f2..7836b6ac 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -570,16 +570,29 @@ mod tests { } } + #[test] + fn encode_counter_with_unit() { + let mut registry = Registry::default(); + let counter: Counter = Counter::default(); + registry.register_with_unit("my_counter", "My counter", Unit::Seconds, counter.clone()); + + let metric_set = encode(®istry); + + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_counter", family.name); + assert_eq!("My counter.", family.help); + assert_eq!("seconds", family.unit); + } + #[test] fn encode_counter_with_exemplar() { let mut registry = Registry::default(); let counter_with_exemplar: CounterWithExemplar<(String, f64), f64> = CounterWithExemplar::default(); - registry.register_with_unit( + registry.register( "my_counter_with_exemplar", "My counter with exemplar", - Unit::Seconds, counter_with_exemplar.clone(), ); From c92e42aee3508cb7a43b757ff37fb1c22ab15771 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Mar 2022 22:48:49 +0900 Subject: [PATCH 30/76] src/encoding/proto: Refactoring: extract a method `Unit::as_str()` Signed-off-by: ackintosh --- src/encoding/proto.rs | 16 ++-------------- src/encoding/text.rs | 15 +-------------- src/registry.rs | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 7836b6ac..0c81e174 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -10,7 +10,7 @@ use crate::metrics::gauge::Gauge; use crate::metrics::histogram::Histogram; use crate::metrics::info::Info; use crate::metrics::{counter, gauge, MetricType, TypedMetric}; -use crate::registry::{Registry, Unit}; +use crate::registry::Registry; use std::collections::HashMap; use std::ops::Deref; @@ -33,19 +33,7 @@ where }; // MetricFamily.unit if let Some(unit) = desc.unit() { - family.unit = match unit { - Unit::Amperes => "amperes", - Unit::Bytes => "bytes", - Unit::Celsius => "celsius", - Unit::Grams => "grams", - Unit::Joules => "joules", - Unit::Meters => "meters", - Unit::Ratios => "ratios", - Unit::Seconds => "seconds", - Unit::Volts => "volts", - Unit::Other(other) => other.as_str(), - } - .to_string(); + family.unit = unit.as_str().to_string(); } // MetricFamily.help family.help = desc.help().to_string(); diff --git a/src/encoding/text.rs b/src/encoding/text.rs index 26bac582..d98bb3e5 100644 --- a/src/encoding/text.rs +++ b/src/encoding/text.rs @@ -193,20 +193,7 @@ impl Encode for MetricType { impl Encode for Unit { fn encode(&self, writer: &mut dyn Write) -> Result<(), std::io::Error> { - let u = match self { - Unit::Amperes => "amperes", - Unit::Bytes => "bytes", - Unit::Celsius => "celsius", - Unit::Grams => "grams", - Unit::Joules => "joules", - Unit::Meters => "meters", - Unit::Ratios => "ratios", - Unit::Seconds => "seconds", - Unit::Volts => "volts", - Unit::Other(other) => other.as_str(), - }; - - writer.write_all(u.as_bytes())?; + writer.write_all(self.as_str().as_bytes())?; Ok(()) } } diff --git a/src/registry.rs b/src/registry.rs index 9e28e580..287c9675 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -347,6 +347,23 @@ pub enum Unit { Other(String), } +impl Unit { + pub fn as_str(&self) -> &str { + match self { + Unit::Amperes => "amperes", + Unit::Bytes => "bytes", + Unit::Celsius => "celsius", + Unit::Grams => "grams", + Unit::Joules => "joules", + Unit::Meters => "meters", + Unit::Ratios => "ratios", + Unit::Seconds => "seconds", + Unit::Volts => "volts", + Unit::Other(other) => other.as_str(), + } + } +} + #[cfg(test)] mod tests { use super::*; From 2d8e80daf1fa89abf18fe666dc68a24e97ca075f Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Thu, 24 Mar 2022 22:52:05 +0900 Subject: [PATCH 31/76] src/encoding/proto: Remove superfluous comments Signed-off-by: ackintosh --- src/encoding/proto.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 0c81e174..953b83ad 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -18,27 +18,21 @@ pub fn encode(registry: &Registry) -> openmetrics_data_model::MetricSet where M: EncodeMetric, { - // MetricSet let mut metric_set = openmetrics_data_model::MetricSet::default(); for (desc, metric) in registry.iter() { - // MetricFamily let mut family = openmetrics_data_model::MetricFamily::default(); - // MetricFamily.name family.name = desc.name().to_string(); - // MetricFamily.type family.r#type = { let metric_type: openmetrics_data_model::MetricType = metric.metric_type().into(); metric_type as i32 }; - // MetricFamily.unit if let Some(unit) = desc.unit() { family.unit = unit.as_str().to_string(); } - // MetricFamily.help family.help = desc.help().to_string(); - // MetricFamily.Metric family.metrics = metric.encode(desc.labels().encode()); + metric_set.metric_families.push(family); } From b3dec216b58361f3d0fb270b13510f67ea320478 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Fri, 25 Mar 2022 08:54:42 +0900 Subject: [PATCH 32/76] src/encoding/proto: Add tests for Family Signed-off-by: ackintosh --- src/encoding/proto.rs | 89 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 953b83ad..40e61c84 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -638,6 +638,95 @@ mod tests { } } + #[test] + fn encode_counter_family() { + let mut registry = Registry::default(); + let family = Family::, Counter>::default(); + registry.register("my_counter_family", "My counter family", family.clone()); + + family + .get_or_create(&vec![ + ("method".to_string(), "GET".to_string()), + ("status".to_string(), "200".to_string()), + ]) + .inc(); + + let metric_set = encode(®istry); + + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_counter_family", family.name); + assert_eq!("My counter family.", family.help); + + assert_eq!( + openmetrics_data_model::MetricType::Counter as i32, + extract_metric_type(&metric_set) + ); + + let metric = family.metrics.first().unwrap(); + assert_eq!(2, metric.labels.len()); + assert_eq!("method", metric.labels[0].name); + assert_eq!("GET", metric.labels[0].value); + assert_eq!("status", metric.labels[1].name); + assert_eq!("200", metric.labels[1].value); + + match extract_metric_point_value(metric_set) { + openmetrics_data_model::metric_point::Value::CounterValue(value) => { + let expected = openmetrics_data_model::counter_value::Total::IntValue(1); + assert_eq!(Some(expected), value.total); + assert_eq!(None, value.exemplar); + assert_eq!(None, value.created); + } + _ => assert!(false, "wrong value type"), + } + } + + #[test] + fn encode_counter_family_with_prefix_with_label() { + let mut registry = Registry::default(); + let sub_registry = registry.sub_registry_with_prefix("my_prefix"); + let sub_sub_registry = sub_registry + .sub_registry_with_label((Cow::Borrowed("my_key"), Cow::Borrowed("my_value"))); + let family = Family::, Counter>::default(); + sub_sub_registry.register("my_counter_family", "My counter family", family.clone()); + + family + .get_or_create(&vec![ + ("method".to_string(), "GET".to_string()), + ("status".to_string(), "200".to_string()), + ]) + .inc(); + + let metric_set = encode(®istry); + + let family = metric_set.metric_families.first().unwrap(); + assert_eq!("my_prefix_my_counter_family", family.name); + assert_eq!("My counter family.", family.help); + + assert_eq!( + openmetrics_data_model::MetricType::Counter as i32, + extract_metric_type(&metric_set) + ); + + let metric = family.metrics.first().unwrap(); + assert_eq!(3, metric.labels.len()); + assert_eq!("method", metric.labels[0].name); + assert_eq!("GET", metric.labels[0].value); + assert_eq!("status", metric.labels[1].name); + assert_eq!("200", metric.labels[1].value); + assert_eq!("my_key", metric.labels[2].name); + assert_eq!("my_value", metric.labels[2].value); + + match extract_metric_point_value(metric_set) { + openmetrics_data_model::metric_point::Value::CounterValue(value) => { + let expected = openmetrics_data_model::counter_value::Total::IntValue(1); + assert_eq!(Some(expected), value.total); + assert_eq!(None, value.exemplar); + assert_eq!(None, value.created); + } + _ => assert!(false, "wrong value type"), + } + } + #[test] fn encode_histogram() { let mut registry = Registry::default(); From d82860d9023ea9e93ca6832d63ffd57498d9f06c Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Fri, 25 Mar 2022 09:27:11 +0900 Subject: [PATCH 33/76] src/encoding/proto: Remove redundant test Signed-off-by: ackintosh --- src/encoding/proto.rs | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 40e61c84..267a6011 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -455,43 +455,6 @@ mod tests { use std::borrow::Cow; use std::sync::atomic::AtomicI64; - #[test] - fn test_encode() { - let mut registry: Registry> = Registry::default(); - - let counter: Counter = Counter::default(); - registry.register_with_unit( - "my_counter", - "My counter", - Unit::Seconds, - Box::new(counter.clone()), - ); - counter.inc(); - - let family = Family::, Counter>::default(); - let sub_registry = - registry.sub_registry_with_label((Cow::Borrowed("my_key"), Cow::Borrowed("my_value"))); - sub_registry.register( - "my_counter_family", - "My counter family", - Box::new(family.clone()), - ); - family - .get_or_create(&vec![ - ("method".to_string(), "GET".to_string()), - ("status".to_string(), "200".to_string()), - ]) - .inc(); - family - .get_or_create(&vec![ - ("method".to_string(), "POST".to_string()), - ("status".to_string(), "503".to_string()), - ]) - .inc(); - - println!("{:?}", encode(®istry)); - } - #[test] fn encode_counter_int() { let counter: Counter = Counter::default(); From 7873e28a5dc45b084711b04843183bfc082cec31 Mon Sep 17 00:00:00 2001 From: "akihito.nakano" Date: Sat, 26 Mar 2022 11:16:48 +0900 Subject: [PATCH 34/76] src/encoding/proto: Add doc Signed-off-by: ackintosh --- src/encoding/proto.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 267a6011..c30f2809 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -1,3 +1,27 @@ +//! Open Metrics protobuf implementation. +//! +//! ``` +//! # use prometheus_client::encoding::proto::encode; +//! # use prometheus_client::metrics::counter::Counter; +//! # use prometheus_client::registry::Registry; +//! # +//! # // Create registry and counter and register the latter with the former. +//! # let mut registry = Registry::default(); +//! # let counter: Counter = Counter::default(); +//! # registry.register( +//! # "my_counter", +//! # "This is my counter", +//! # counter.clone(), +//! # ); +//! # counter.inc(); +//! // Returns `MetricSet`, the top-level container type. Please refer to [openmetrics_data_model.proto](https://github.com/OpenObservability/OpenMetrics/blob/main/proto/openmetrics_data_model.proto) for details. +//! let metric_set = encode(®istry); +//! +//! let family = metric_set.metric_families.first().unwrap(); +//! assert_eq!("my_counter", family.name); +//! assert_eq!("My counter.", family.help); +//! ``` + // Include the `openmetrics_data_model` module, which is generated from `proto/openmetrics_data_model.proto`. pub mod openmetrics_data_model { include!(concat!(env!("OUT_DIR"), "/openmetrics.rs")); From 286e5b4b77d8803228593b420fc96615d21f6e3e Mon Sep 17 00:00:00 2001 From: Max Inden Date: Wed, 2 Mar 2022 12:13:18 +0100 Subject: [PATCH 35/76] src/encoding: Remove unnecessary flatten (#50) Signed-off-by: Max Inden Signed-off-by: ackintosh --- src/encoding/text.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/encoding/text.rs b/src/encoding/text.rs index d98bb3e5..9f30f123 100644 --- a/src/encoding/text.rs +++ b/src/encoding/text.rs @@ -558,7 +558,7 @@ fn encode_histogram_with_maybe_exemplars( let mut value_encoder = bucket_encoder.encode_bucket(*upper_bound)?; let mut exemplar_encoder = value_encoder.encode_value(cummulative)?; - match exemplars.map(|es| es.get(&i)).flatten() { + match exemplars.and_then(|es| es.get(&i)) { Some(exemplar) => exemplar_encoder.encode_exemplar(exemplar)?, None => exemplar_encoder.no_exemplar()?, } From 6354f929cca373da234f5dd2f14b0ecc6898b1e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Mar 2022 12:19:54 +0100 Subject: [PATCH 36/76] build(deps): update pyo3 requirement from 0.15 to 0.16 (#48) Updates the requirements on [pyo3](https://github.com/pyo3/pyo3) to permit the latest version. - [Release notes](https://github.com/pyo3/pyo3/releases) - [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md) - [Commits](https://github.com/pyo3/pyo3/compare/v0.15.0...v0.16.0) --- updated-dependencies: - dependency-name: pyo3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Signed-off-by: ackintosh --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 17778203..b540bb3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ prost-types = "0.9.0" async-std = { version = "1", features = ["attributes"] } criterion = "0.3" http-types = "2" -pyo3 = "0.15" +pyo3 = "0.16" quickcheck = "1" rand = "0.8.4" tide = "0.16" From 3dd63fb3d32d577a82a14aaac808d284b75059df Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 25 Mar 2022 16:59:15 +0100 Subject: [PATCH 37/76] examples/tide: Remove unnecessary Mutex (#55) There is no need for mutable access to the `Registry` once all metrics have been registered. Encoding the registered metrics does not require a mutable reference. With that in mind, an `Arc` is good enough. There is no need for a `Mutex`. Signed-off-by: Max Inden Signed-off-by: ackintosh --- examples/tide.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/tide.rs b/examples/tide.rs index 6b10f5ac..dfb68125 100644 --- a/examples/tide.rs +++ b/examples/tide.rs @@ -3,7 +3,7 @@ use prometheus_client::metrics::counter::Counter; use prometheus_client::metrics::family::Family; use prometheus_client::registry::Registry; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use tide::{Middleware, Next, Request, Result}; @@ -23,7 +23,7 @@ async fn main() -> std::result::Result<(), std::io::Error> { http_requests_total, }; let mut app = tide::with_state(State { - registry: Arc::new(Mutex::new(registry)), + registry: Arc::new(registry), }); app.with(middleware); @@ -31,7 +31,7 @@ async fn main() -> std::result::Result<(), std::io::Error> { app.at("/metrics") .get(|req: tide::Request| async move { let mut encoded = Vec::new(); - encode(&mut encoded, &req.state().registry.lock().unwrap()).unwrap(); + encode(&mut encoded, &req.state().registry).unwrap(); let response = tide::Response::builder(200) .body(encoded) .content_type("application/openmetrics-text; version=1.0.0; charset=utf-8") @@ -57,7 +57,7 @@ enum Method { #[derive(Clone)] struct State { - registry: Arc>>>, + registry: Arc>>, } #[derive(Default)] From 5c5c5081ea7a94e29a8cc97106a9aae9acc6d419 Mon Sep 17 00:00:00 2001 From: Ben Sully Date: Wed, 6 Apr 2022 17:51:29 +0200 Subject: [PATCH 38/76] src/registry.rs: Require metrics to be Sync by default (#58) This will allow the default `Registry` to be used in multi-threaded environments (e.g. web servers) where a ref to the registry needs to be shared between threads. Closes #57. Signed-off-by: Ben Sully Signed-off-by: Max Inden Co-authored-by: Max Inden Signed-off-by: ackintosh --- CHANGELOG.md | 8 ++++++++ Cargo.toml | 2 +- src/encoding/text.rs | 6 +++--- src/registry.rs | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9984b1c..1852d6dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ 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.16.0] - unreleased + +### Changed + +- Require `Registry` default generic type `SendEncodeMetric` to be `Sync`. See [PR 58]. + +[PR 58]: https://github.com/prometheus/client_rust/pull/58 + ## [0.15.1] - 2022-02-04 ### Added diff --git a/Cargo.toml b/Cargo.toml index b540bb3e..ec709949 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "prometheus-client" -version = "0.15.1" +version = "0.16.0" authors = ["Max Inden "] edition = "2018" description = "Open Metrics client library allowing users to natively instrument applications." diff --git a/src/encoding/text.rs b/src/encoding/text.rs index 9f30f123..86e9d89b 100644 --- a/src/encoding/text.rs +++ b/src/encoding/text.rs @@ -391,11 +391,11 @@ impl EncodeMetric for Box { } } -pub trait SendEncodeMetric: EncodeMetric + Send {} +pub trait SendSyncEncodeMetric: EncodeMetric + Send + Sync {} -impl SendEncodeMetric for T {} +impl SendSyncEncodeMetric for T {} -impl EncodeMetric for Box { +impl EncodeMetric for Box { fn encode(&self, encoder: Encoder) -> Result<(), std::io::Error> { self.deref().encode(encoder) } diff --git a/src/registry.rs b/src/registry.rs index 287c9675..fb5b51dd 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -58,7 +58,7 @@ use std::ops::Add; /// # "# EOF\n"; /// # assert_eq!(expected, String::from_utf8(buffer).unwrap()); /// ``` -pub struct Registry> { +pub struct Registry> { prefix: Option, labels: Vec<(Cow<'static, str>, Cow<'static, str>)>, metrics: Vec<(Descriptor, M)>, From fea47257a2ce56199c2b61aa272f61fcaf479f60 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 3 May 2022 22:08:26 +0200 Subject: [PATCH 39/76] CHANGELOG.md: Prepare v0.16.0 (#59) Signed-off-by: Max Inden Signed-off-by: ackintosh --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1852d6dd..05bdffc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ 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.16.0] - unreleased +## [0.16.0] ### Changed From 626e6959b6d2fe12058a0dbac6d9e085062eba66 Mon Sep 17 00:00:00 2001 From: PrometheusBot Date: Sun, 8 May 2022 12:08:49 +0200 Subject: [PATCH 40/76] *: Update common Prometheus files (#60) Signed-off-by: prombot Signed-off-by: ackintosh --- CODE_OF_CONDUCT.md | 4 ++-- SECURITY.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 9a1aff41..d325872b 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ -## Prometheus Community Code of Conduct +# Prometheus Community Code of Conduct -Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). +Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). diff --git a/SECURITY.md b/SECURITY.md index 67741f01..fed02d85 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -3,4 +3,4 @@ The Prometheus security policy, including how to report vulnerabilities, can be found here: -https://prometheus.io/docs/operating/security/ + From aebc4bc23b6c10dd9e8a608af1492598a82211c1 Mon Sep 17 00:00:00 2001 From: Doehyun Baek Date: Mon, 23 May 2022 23:38:43 +0900 Subject: [PATCH 41/76] src/metrics/histogram.rs: Document no default buckets (#63) As suggested and discussed in https://github.com/prometheus/client_rust/issues/61, this commit adds a comment that describes unavailability of default values for buckets. Signed-off-by: Doehyun Baek Signed-off-by: ackintosh --- src/metrics/histogram.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/metrics/histogram.rs b/src/metrics/histogram.rs index 177b49aa..e17799cf 100644 --- a/src/metrics/histogram.rs +++ b/src/metrics/histogram.rs @@ -14,6 +14,20 @@ use std::sync::{Arc, Mutex, MutexGuard}; /// let histogram = Histogram::new(exponential_buckets(1.0, 2.0, 10)); /// histogram.observe(4.2); /// ``` +/// +/// [`Histogram`] does not implement [`Default`], given that the choice of +/// bucket values depends on the situation [`Histogram`] is used in. As an +/// example, to measure HTTP request latency, the values suggested in the +/// Golang implementation might work for you: +/// +/// ``` +/// # use prometheus_client::metrics::histogram::Histogram; +/// // Default values from go client(https://github.com/prometheus/client_golang/blob/5d584e2717ef525673736d72cd1d12e304f243d7/prometheus/histogram.go#L68) +/// let histogram = Histogram::new(IntoIterator::into_iter([ +/// 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, +/// ])); +/// histogram.observe(4.2); +/// ``` // TODO: Consider using atomics. See // https://github.com/tikv/rust-prometheus/pull/314. pub struct Histogram { From 0f0f70ea8283ba3df6ddc9c0ed4bdabb2a96e49c Mon Sep 17 00:00:00 2001 From: Doehyun Baek Date: Wed, 1 Jun 2022 19:24:22 +0900 Subject: [PATCH 42/76] */Cargo.toml: Update to 2021 edition (#65) As suggested in https://github.com/prometheus/client_rust/issues/64, this commit update edition key of manifest file into 2021. As documented in 2021 edition guide(https://doc.rust-lang.org/edition-guide/rust-2021/IntoIterator-for-arrays.html), array.into_iter() now returns owned value instead of references, This commit changes previous doc comments to utilize new behavior. Signed-off-by: Doehyun Baek --- CHANGELOG.md | 8 ++++++++ Cargo.toml | 6 +++--- derive-text-encode/Cargo.toml | 4 ++-- src/metrics/family.rs | 4 ++-- src/metrics/histogram.rs | 5 +++-- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05bdffc5..7c9bb82a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ 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.17.0] - unreleased + +### Changed + +- Updates to Rust 2021 Edition. See [PR 65]. + +[PR 65]: https://github.com/prometheus/client_rust/pull/65 + ## [0.16.0] ### Changed diff --git a/Cargo.toml b/Cargo.toml index ec709949..71b0af66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "prometheus-client" -version = "0.16.0" +version = "0.17.0" authors = ["Max Inden "] -edition = "2018" +edition = "2021" description = "Open Metrics client library allowing users to natively instrument applications." license = "Apache-2.0 OR MIT" keywords = ["openmetrics", "prometheus", "metrics", "instrumentation", "monitoring"] @@ -17,7 +17,7 @@ members = ["derive-text-encode"] dtoa = "1.0" itoa = "1.0" owning_ref = "0.4" -prometheus-client-derive-text-encode = { version = "0.2.0", path = "derive-text-encode" } +prometheus-client-derive-text-encode = { version = "0.3.0", path = "derive-text-encode" } prost = "0.9.0" prost-types = "0.9.0" diff --git a/derive-text-encode/Cargo.toml b/derive-text-encode/Cargo.toml index 8bb06f1d..f243c24e 100644 --- a/derive-text-encode/Cargo.toml +++ b/derive-text-encode/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "prometheus-client-derive-text-encode" -version = "0.2.0" +version = "0.3.0" authors = ["Max Inden "] -edition = "2018" +edition = "2021" description = "Auxiliary crate to derive text Encode trait from prometheus-client." license = "Apache-2.0 OR MIT" repository = "https://github.com/prometheus/client_rust" diff --git a/src/metrics/family.rs b/src/metrics/family.rs index 7d5d0e59..1610881b 100644 --- a/src/metrics/family.rs +++ b/src/metrics/family.rs @@ -144,9 +144,9 @@ pub trait MetricConstructor { /// ``` /// # use prometheus_client::metrics::family::{Family}; /// # use prometheus_client::metrics::histogram::Histogram; -/// let custom_buckets = vec![0.0, 10.0, 100.0]; +/// let custom_buckets = [0.0, 10.0, 100.0]; /// let metric = Family::<(), Histogram, _>::new_with_constructor(|| { -/// Histogram::new(custom_buckets.clone().into_iter()) +/// Histogram::new(custom_buckets.into_iter()) /// }); /// # metric.get_or_create(&()); /// ``` diff --git a/src/metrics/histogram.rs b/src/metrics/histogram.rs index e17799cf..3f2ae9ff 100644 --- a/src/metrics/histogram.rs +++ b/src/metrics/histogram.rs @@ -23,9 +23,10 @@ use std::sync::{Arc, Mutex, MutexGuard}; /// ``` /// # use prometheus_client::metrics::histogram::Histogram; /// // Default values from go client(https://github.com/prometheus/client_golang/blob/5d584e2717ef525673736d72cd1d12e304f243d7/prometheus/histogram.go#L68) -/// let histogram = Histogram::new(IntoIterator::into_iter([ +/// let custom_buckets = [ /// 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, -/// ])); +/// ]; +/// let histogram = Histogram::new(custom_buckets.into_iter()); /// histogram.observe(4.2); /// ``` // TODO: Consider using atomics. See From 496c8abc98b47b279ae5f87734280e8a487e0bf5 Mon Sep 17 00:00:00 2001 From: Thaler Benedek Date: Mon, 11 Jul 2022 03:41:19 +0200 Subject: [PATCH 43/76] src/registry.rs: Remove Add trait impls (#69) They conflict with builtin implementations, see https://github.com/rust-lang/rust/issues/77143 Signed-off-by: Benedek Thaler Signed-off-by: ackintosh --- CHANGELOG.md | 5 +++++ src/registry.rs | 27 ++++----------------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c9bb82a..1700c62d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updates to Rust 2021 Edition. See [PR 65]. +### Removed + +- Remove `Add` trait implementation for a private type which lead to compile time conflicts with existing `Add` implementations e.g. on `String`. See [PR 69]. + [PR 65]: https://github.com/prometheus/client_rust/pull/65 +[PR 69]: https://github.com/prometheus/client_rust/pull/69 ## [0.16.0] diff --git a/src/registry.rs b/src/registry.rs index fb5b51dd..3922dc67 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -3,7 +3,6 @@ //! See [`Registry`] for details. use std::borrow::Cow; -use std::ops::Add; /// A metric registry. /// @@ -149,7 +148,7 @@ impl Registry { name: self .prefix .as_ref() - .map(|p| (p.clone() + "_" + name.as_str()).into()) + .map(|p| (p.clone().0 + "_" + name.as_str())) .unwrap_or(name), help, unit, @@ -196,13 +195,9 @@ impl Registry { /// but namespacing with a label instead of a metric name prefix. pub fn sub_registry_with_prefix>(&mut self, prefix: P) -> &mut Self { let sub_registry = Registry { - prefix: Some( - self.prefix - .clone() - .map(|p| p + "_") - .unwrap_or_else(|| String::new().into()) - + prefix.as_ref(), - ), + prefix: Some(Prefix( + self.prefix.clone().map(|p| p.0 + "_").unwrap_or_default() + prefix.as_ref(), + )), labels: self.labels.clone(), ..Default::default() }; @@ -292,20 +287,6 @@ impl From for String { } } -impl Add<&str> for Prefix { - type Output = Self; - fn add(self, rhs: &str) -> Self::Output { - Prefix(self.0 + rhs) - } -} - -impl Add<&Prefix> for String { - type Output = Self; - fn add(self, rhs: &Prefix) -> Self::Output { - self + rhs.0.as_str() - } -} - pub struct Descriptor { name: String, help: String, From 42d153490ebf022447ee6596d35109e88025efe2 Mon Sep 17 00:00:00 2001 From: Victor Nordam Suadicani Date: Thu, 14 Jul 2022 09:37:09 +0200 Subject: [PATCH 44/76] src/registry.rs: Add with_prefix to Registry (#70) Signed-off-by: Victor Nordam Suadicani Signed-off-by: ackintosh --- CHANGELOG.md | 6 ++++-- src/registry.rs | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1700c62d..80383cfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,15 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.17.0] - unreleased ### Changed - - Updates to Rust 2021 Edition. See [PR 65]. -### Removed +### Added +- Added a `with_prefix` method to `Registry` to allow initializing a registry with a prefix. See [PR 70]. +### Removed - Remove `Add` trait implementation for a private type which lead to compile time conflicts with existing `Add` implementations e.g. on `String`. See [PR 69]. [PR 65]: https://github.com/prometheus/client_rust/pull/65 [PR 69]: https://github.com/prometheus/client_rust/pull/69 +[PR 70]: https://github.com/prometheus/client_rust/pull/70 ## [0.16.0] diff --git a/src/registry.rs b/src/registry.rs index 3922dc67..429a9aeb 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -76,6 +76,14 @@ impl Default for Registry { } impl Registry { + /// Creates a new default [`Registry`] with the given prefix. + pub fn with_prefix(prefix: impl Into) -> Self { + Self { + prefix: Some(Prefix(prefix.into())), + ..Default::default() + } + } + /// Register a metric with the [`Registry`]. /// /// Note: In the Open Metrics text exposition format some metric types have From 20a2b4f76ebc387ba4bf55af2848bf3e5f3c982b Mon Sep 17 00:00:00 2001 From: Victor Nordam Suadicani Date: Fri, 15 Jul 2022 09:23:20 +0200 Subject: [PATCH 45/76] src/*: Add Debug impls and fix clippy warnings (#71) Signed-off-by: Victor Nordam Suadicani Signed-off-by: ackintosh --- .github/workflows/rust.yml | 2 +- CHANGELOG.md | 2 ++ benches/encoding/text.rs | 5 ++--- benches/family.rs | 6 +++--- derive-text-encode/tests/lib.rs | 16 ++++++++-------- src/encoding/text.rs | 10 +++++++--- src/lib.rs | 1 + src/metrics.rs | 2 +- src/metrics/counter.rs | 2 ++ src/metrics/exemplar.rs | 6 ++++++ src/metrics/family.rs | 1 + src/metrics/gauge.rs | 2 ++ src/metrics/histogram.rs | 2 ++ src/metrics/info.rs | 1 + src/registry.rs | 8 ++++++-- 15 files changed, 45 insertions(+), 21 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f38e40ed..864faad5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -118,7 +118,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: clippy - args: -- -D warnings + args: --workspace --all-targets -- -D warnings check-rustdoc-links: name: Check rustdoc intra-doc links diff --git a/CHANGELOG.md b/CHANGELOG.md index 80383cfe..4cb400ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added a `with_prefix` method to `Registry` to allow initializing a registry with a prefix. See [PR 70]. +- Added `Debug` implementations on most public types that were missing them. See [PR 71]. ### Removed - Remove `Add` trait implementation for a private type which lead to compile time conflicts with existing `Add` implementations e.g. on `String`. See [PR 69]. @@ -18,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [PR 65]: https://github.com/prometheus/client_rust/pull/65 [PR 69]: https://github.com/prometheus/client_rust/pull/69 [PR 70]: https://github.com/prometheus/client_rust/pull/70 +[PR 71]: https://github.com/prometheus/client_rust/pull/71 ## [0.16.0] diff --git a/benches/encoding/text.rs b/benches/encoding/text.rs index 9c3b450d..78c2c4f3 100644 --- a/benches/encoding/text.rs +++ b/benches/encoding/text.rs @@ -7,7 +7,6 @@ use prometheus_client::metrics::family::Family; use prometheus_client::metrics::histogram::{exponential_buckets, Histogram}; use prometheus_client::registry::Registry; use std::io::Write; -use std::sync::atomic::AtomicU64; pub fn text(c: &mut Criterion) { c.bench_function("encode", |b| { @@ -23,7 +22,7 @@ pub fn text(c: &mut Criterion) { Get, #[allow(dead_code)] Put, - }; + } #[derive(Clone, Hash, PartialEq, Eq)] enum Status { @@ -32,7 +31,7 @@ pub fn text(c: &mut Criterion) { Four, #[allow(dead_code)] Five, - }; + } impl Encode for Status { fn encode(&self, writer: &mut dyn Write) -> Result<(), std::io::Error> { diff --git a/benches/family.rs b/benches/family.rs index 4fc50c6c..a409cc43 100644 --- a/benches/family.rs +++ b/benches/family.rs @@ -1,4 +1,4 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, Criterion}; use prometheus_client::metrics::counter::Counter; use prometheus_client::metrics::family::Family; @@ -28,7 +28,7 @@ pub fn family(c: &mut Criterion) { Get, #[allow(dead_code)] Put, - }; + } #[derive(Clone, Hash, PartialEq, Eq)] enum Status { @@ -37,7 +37,7 @@ pub fn family(c: &mut Criterion) { Four, #[allow(dead_code)] Five, - }; + } let family = Family::::default(); b.iter(|| { diff --git a/derive-text-encode/tests/lib.rs b/derive-text-encode/tests/lib.rs index 00bc7617..2e4cbbfc 100644 --- a/derive-text-encode/tests/lib.rs +++ b/derive-text-encode/tests/lib.rs @@ -10,14 +10,14 @@ fn basic_flow() { struct Labels { method: Method, path: String, - }; + } #[derive(Clone, Hash, PartialEq, Eq, Encode)] enum Method { - GET, + Get, #[allow(dead_code)] - PUT, - }; + Put, + } let family = Family::::default(); registry.register("my_counter", "This is my counter", family.clone()); @@ -25,7 +25,7 @@ fn basic_flow() { // Record a single HTTP GET request. family .get_or_create(&Labels { - method: Method::GET, + method: Method::Get, path: "/metrics".to_string(), }) .inc(); @@ -36,7 +36,7 @@ fn basic_flow() { let expected = "# HELP my_counter This is my counter.\n".to_owned() + "# TYPE my_counter counter\n" - + "my_counter_total{method=\"GET\",path=\"/metrics\"} 1\n" + + "my_counter_total{method=\"Get\",path=\"/metrics\"} 1\n" + "# EOF\n"; assert_eq!(expected, String::from_utf8(buffer).unwrap()); } @@ -52,13 +52,13 @@ fn remap_keyword_identifiers() { // Test makes sure `r#type` is replaced by `type` in the OpenMetrics // output. r#type: u64, - }; + } let labels = Labels { r#type: 42 }; let mut buffer = vec![]; - labels.encode(&mut buffer); + labels.encode(&mut buffer).unwrap(); assert_eq!( "type=\"42\"".to_string(), diff --git a/src/encoding/text.rs b/src/encoding/text.rs index 86e9d89b..edb03c1c 100644 --- a/src/encoding/text.rs +++ b/src/encoding/text.rs @@ -212,6 +212,7 @@ impl Encode for () { // objects can not use type parameters. // // TODO: Alternative solutions to the above are very much appreciated. +#[allow(missing_debug_implementations)] pub struct Encoder<'a, 'b> { writer: &'a mut dyn Write, name: &'a str, @@ -290,6 +291,7 @@ impl<'a, 'b> Encoder<'a, 'b> { } } +#[allow(missing_debug_implementations)] #[must_use] pub struct BucketEncoder<'a> { writer: &'a mut dyn Write, @@ -329,6 +331,7 @@ impl<'a> BucketEncoder<'a> { } } +#[allow(missing_debug_implementations)] #[must_use] pub struct ValueEncoder<'a> { writer: &'a mut dyn Write, @@ -346,6 +349,7 @@ impl<'a> ValueEncoder<'a> { } } +#[allow(missing_debug_implementations)] #[must_use] pub struct ExemplarEncoder<'a> { writer: &'a mut dyn Write, @@ -603,7 +607,7 @@ mod tests { fn encode_counter() { let counter: Counter = Counter::default(); let mut registry = Registry::default(); - registry.register("my_counter", "My counter", counter.clone()); + registry.register("my_counter", "My counter", counter); let mut encoded = Vec::new(); @@ -616,7 +620,7 @@ mod tests { fn encode_counter_with_unit() { let mut registry = Registry::default(); let counter: Counter = Counter::default(); - registry.register_with_unit("my_counter", "My counter", Unit::Seconds, counter.clone()); + registry.register_with_unit("my_counter", "My counter", Unit::Seconds, counter); let mut encoded = Vec::new(); encode(&mut encoded, ®istry).unwrap(); @@ -664,7 +668,7 @@ mod tests { fn encode_gauge() { let mut registry = Registry::default(); let gauge: Gauge = Gauge::default(); - registry.register("my_gauge", "My gauge", gauge.clone()); + registry.register("my_gauge", "My gauge", gauge); let mut encoded = Vec::new(); diff --git a/src/lib.rs b/src/lib.rs index add69623..b5edaac2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![forbid(unsafe_code)] #![deny(unused)] #![deny(dead_code)] +#![warn(missing_debug_implementations)] //! Client library implementation of the [Open Metrics //! specification](https://github.com/OpenObservability/OpenMetrics). Allows diff --git a/src/metrics.rs b/src/metrics.rs index 5a21654c..e09504e3 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -12,7 +12,7 @@ pub trait TypedMetric { const TYPE: MetricType = MetricType::Unknown; } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum MetricType { Counter, Gauge, diff --git a/src/metrics/counter.rs b/src/metrics/counter.rs index c8ad9461..689723d8 100644 --- a/src/metrics/counter.rs +++ b/src/metrics/counter.rs @@ -39,12 +39,14 @@ use std::sync::Arc; /// let _value: f64 = counter.get(); /// ``` #[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] +#[derive(Debug)] pub struct Counter { value: Arc, phantom: PhantomData, } #[cfg(any(target_arch = "mips", target_arch = "powerpc"))] +#[derive(Debug)] pub struct Counter { value: Arc, phantom: PhantomData, diff --git a/src/metrics/exemplar.rs b/src/metrics/exemplar.rs index 66a043bb..485712f6 100644 --- a/src/metrics/exemplar.rs +++ b/src/metrics/exemplar.rs @@ -12,6 +12,7 @@ use std::sync::atomic::AtomicU32; use std::sync::atomic::AtomicU64; use std::sync::{Arc, RwLock, RwLockReadGuard}; +#[derive(Debug)] pub struct Exemplar { pub(crate) label_set: S, pub(crate) value: V, @@ -30,11 +31,13 @@ pub struct Exemplar { /// let _value: (u64, _) = counter_with_exemplar.get(); /// ``` #[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] +#[derive(Debug)] pub struct CounterWithExemplar { pub(crate) inner: Arc>>, } #[cfg(any(target_arch = "mips", target_arch = "powerpc"))] +#[derive(Debug)] pub struct CounterWithExemplar { pub(crate) inner: Arc>>, } @@ -47,6 +50,7 @@ impl Clone for CounterWithExemplar { } } +#[derive(Debug)] pub struct CounterWithExemplarInner { pub(crate) exemplar: Option>, pub(crate) counter: Counter, @@ -118,6 +122,7 @@ type RwLockGuardedCounterWithExemplar<'a, S, N, A> = /// let histogram = HistogramWithExemplars::new(exponential_buckets(1.0, 2.0, 10)); /// histogram.observe(4.2, Some(vec![("user_id".to_string(), "42".to_string())])); /// ``` +#[derive(Debug)] pub struct HistogramWithExemplars { // TODO: Not ideal, as Histogram has a Mutex as well. pub(crate) inner: Arc>>, @@ -131,6 +136,7 @@ impl Clone for HistogramWithExemplars { } } +#[derive(Debug)] pub struct HistogramWithExemplarsInner { pub(crate) exemplars: HashMap>, pub(crate) histogram: Histogram, diff --git a/src/metrics/family.rs b/src/metrics/family.rs index 1610881b..be945075 100644 --- a/src/metrics/family.rs +++ b/src/metrics/family.rs @@ -97,6 +97,7 @@ use std::sync::{Arc, RwLock, RwLockReadGuard}; /// # assert_eq!(expected, String::from_utf8(buffer).unwrap()); /// ``` // TODO: Consider exposing hash algorithm. +#[derive(Debug)] pub struct Family M> { metrics: Arc>>, /// Function that when called constructs a new metric. diff --git a/src/metrics/gauge.rs b/src/metrics/gauge.rs index 3845a846..1e940411 100644 --- a/src/metrics/gauge.rs +++ b/src/metrics/gauge.rs @@ -39,12 +39,14 @@ use std::sync::Arc; /// let _value: f64 = gauge.get(); /// ``` #[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] +#[derive(Debug)] pub struct Gauge { value: Arc, phantom: PhantomData, } #[cfg(any(target_arch = "mips", target_arch = "powerpc"))] +#[derive(Debug)] pub struct Gauge { value: Arc, phantom: PhantomData, diff --git a/src/metrics/histogram.rs b/src/metrics/histogram.rs index 3f2ae9ff..c025c4e8 100644 --- a/src/metrics/histogram.rs +++ b/src/metrics/histogram.rs @@ -31,6 +31,7 @@ use std::sync::{Arc, Mutex, MutexGuard}; /// ``` // TODO: Consider using atomics. See // https://github.com/tikv/rust-prometheus/pull/314. +#[derive(Debug)] pub struct Histogram { inner: Arc>, } @@ -43,6 +44,7 @@ impl Clone for Histogram { } } +#[derive(Debug)] pub(crate) struct Inner { // TODO: Consider allowing integer observe values. sum: f64, diff --git a/src/metrics/info.rs b/src/metrics/info.rs index ffe52910..8457207f 100644 --- a/src/metrics/info.rs +++ b/src/metrics/info.rs @@ -12,6 +12,7 @@ use crate::metrics::{MetricType, TypedMetric}; /// /// let _info = Info::new(vec![("os", "GNU/linux")]); /// ``` +#[derive(Debug)] pub struct Info(pub(crate) S); impl Info { diff --git a/src/registry.rs b/src/registry.rs index 429a9aeb..e2122ca0 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -57,6 +57,7 @@ use std::borrow::Cow; /// # "# EOF\n"; /// # assert_eq!(expected, String::from_utf8(buffer).unwrap()); /// ``` +#[derive(Debug)] pub struct Registry> { prefix: Option, labels: Vec<(Cow<'static, str>, Cow<'static, str>)>, @@ -250,6 +251,7 @@ impl Registry { /// Iterator iterating both the metrics registered directly with the registry as /// well as all metrics registered with sub-registries. +#[derive(Debug)] pub struct RegistryIterator<'a, M> { metrics: std::slice::Iter<'a, (Descriptor, M)>, sub_registries: std::slice::Iter<'a, Registry>, @@ -280,7 +282,7 @@ impl<'a, M> Iterator for RegistryIterator<'a, M> { } } -#[derive(Clone)] +#[derive(Clone, Debug)] struct Prefix(String); impl From for Prefix { @@ -295,6 +297,7 @@ impl From for String { } } +#[derive(Debug)] pub struct Descriptor { name: String, help: String, @@ -323,6 +326,7 @@ impl Descriptor { /// Metric units recommended by Open Metrics. /// /// See [`Unit::Other`] to specify alternative units. +#[derive(Debug)] pub enum Unit { Amperes, Bytes, @@ -362,7 +366,7 @@ mod tests { fn register_and_iterate() { let mut registry: Registry = Registry::default(); let counter = Counter::default(); - registry.register("my_counter", "My counter", counter.clone()); + registry.register("my_counter", "My counter", counter); assert_eq!(1, registry.iter().count()) } From c04812824a923261b27d6aa9374a038c18a5a9ca Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 18 Jul 2022 13:37:41 +0200 Subject: [PATCH 46/76] CHANGELOG: Preapre v0.17.0 (#72) Signed-off-by: Max Inden Signed-off-by: ackintosh --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cb400ca..a1d18c3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ 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.17.0] - unreleased +## [0.17.0] ### Changed - Updates to Rust 2021 Edition. See [PR 65]. From 87143ebce9bbcf510fee32eeff332bff1218c492 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Wed, 27 Jul 2022 11:23:39 +0900 Subject: [PATCH 47/76] Introduce `protobuf` feature Signed-off-by: ackintosh --- Cargo.toml | 9 ++++++--- build.rs | 2 ++ src/encoding.rs | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 71b0af66..05bfd60e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,9 @@ repository = "https://github.com/prometheus/client_rust" homepage = "https://github.com/prometheus/client_rust" documentation = "https://docs.rs/prometheus-client" +[features] +protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build"] + [workspace] members = ["derive-text-encode"] @@ -18,8 +21,8 @@ dtoa = "1.0" itoa = "1.0" owning_ref = "0.4" prometheus-client-derive-text-encode = { version = "0.3.0", path = "derive-text-encode" } -prost = "0.9.0" -prost-types = "0.9.0" +prost = { version = "0.9.0", optional = true } +prost-types = { version = "0.9.0", optional = true } [dev-dependencies] async-std = { version = "1", features = ["attributes"] } @@ -31,7 +34,7 @@ rand = "0.8.4" tide = "0.16" [build-dependencies] -prost-build = "0.9.0" +prost-build = { version = "0.9.0", optional = true } [[bench]] name = "family" diff --git a/build.rs b/build.rs index 36a14ae6..d10b0197 100644 --- a/build.rs +++ b/build.rs @@ -1,9 +1,11 @@ use std::io::Result; fn main() -> Result<()> { + #[cfg(feature = "protobuf")] prost_build::compile_protos( &["src/encoding/proto/openmetrics_data_model.proto"], &["src/encoding/proto/"], )?; + Ok(()) } diff --git a/src/encoding.rs b/src/encoding.rs index 084e5100..d62cb3fc 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -1,4 +1,5 @@ //! Exposition format implementations. +#[cfg(feature = "protobuf")] pub mod proto; pub mod text; From fa909c277fe10e38795805219f6d8aa202830d59 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Wed, 27 Jul 2022 11:42:46 +0900 Subject: [PATCH 48/76] src/encoding/proto: Refactoring for loop Signed-off-by: ackintosh --- src/encoding/proto.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index c30f2809..4f4ab654 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -130,21 +130,13 @@ impl EncodeLabel for (K, V) { impl EncodeLabel for Vec { fn encode(&self) -> Vec { - let mut label = vec![]; - for t in self { - label.append(&mut t.encode()); - } - label + self.iter().map(|t| t.encode()).flatten().collect() } } impl EncodeLabel for &[T] { fn encode(&self) -> Vec { - let mut label = vec![]; - for t in self.iter() { - label.append(&mut t.encode()); - } - label + self.iter().map(|t| t.encode()).flatten().collect() } } From 46309f2beed73b6ee1783b6a39a4ff144a30e22a Mon Sep 17 00:00:00 2001 From: ackintosh Date: Mon, 8 Aug 2022 17:00:11 +0900 Subject: [PATCH 49/76] Implement proc macro `EncodeProtobuf` Signed-off-by: ackintosh --- Cargo.toml | 5 +- derive-proto-encode/Cargo.toml | 23 ++++++ derive-proto-encode/src/lib.rs | 132 +++++++++++++++++++++++++++++++ derive-proto-encode/tests/lib.rs | 103 ++++++++++++++++++++++++ src/encoding/proto.rs | 3 + 5 files changed, 264 insertions(+), 2 deletions(-) create mode 100644 derive-proto-encode/Cargo.toml create mode 100644 derive-proto-encode/src/lib.rs create mode 100644 derive-proto-encode/tests/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 05bfd60e..b536b8d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,15 +11,16 @@ homepage = "https://github.com/prometheus/client_rust" documentation = "https://docs.rs/prometheus-client" [features] -protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build"] +protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build", "dep:prometheus-client-derive-proto-encode"] [workspace] -members = ["derive-text-encode"] +members = ["derive-text-encode", "derive-proto-encode"] [dependencies] dtoa = "1.0" itoa = "1.0" owning_ref = "0.4" +prometheus-client-derive-proto-encode = { version = "0.1.0", path = "derive-proto-encode", optional = true } prometheus-client-derive-text-encode = { version = "0.3.0", path = "derive-text-encode" } prost = { version = "0.9.0", optional = true } prost-types = { version = "0.9.0", optional = true } diff --git a/derive-proto-encode/Cargo.toml b/derive-proto-encode/Cargo.toml new file mode 100644 index 00000000..2baf445c --- /dev/null +++ b/derive-proto-encode/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "prometheus-client-derive-proto-encode" +version = "0.1.0" +authors = ["Akihito Nakano "] +edition = "2021" +description = "Auxiliary crate to derive protobuf EncodeLabel trait from prometheus-client." +license = "Apache-2.0 OR MIT" +repository = "https://github.com/prometheus/client_rust" +homepage = "https://github.com/prometheus/client_rust" +documentation = "https://docs.rs/prometheus-client-derive-proto-encode" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +proc-macro2 = "1" +quote = "1" +syn = "1" + +[dev-dependencies] +prometheus-client = { path = "../", features = ["protobuf"] } + +[lib] +proc-macro = true diff --git a/derive-proto-encode/src/lib.rs b/derive-proto-encode/src/lib.rs new file mode 100644 index 00000000..61589652 --- /dev/null +++ b/derive-proto-encode/src/lib.rs @@ -0,0 +1,132 @@ +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use quote::quote; +use syn::DeriveInput; + +#[proc_macro_derive(EncodeProtobuf)] +pub fn derive_encode(input: TokenStream) -> TokenStream { + let ast: DeriveInput = syn::parse(input).unwrap(); + let name = &ast.ident; + + let body: TokenStream2 = match ast.data { + syn::Data::Struct(s) => match s.fields { + syn::Fields::Named(syn::FieldsNamed { named, .. }) => { + let push_labels: TokenStream2 = named + .into_iter() + .map(|f| { + let ident = f.ident.unwrap(); + let ident_string = KEYWORD_IDENTIFIERS + .iter() + .find(|pair| ident == pair.1) + .map(|pair| pair.0.to_string()) + .unwrap_or_else(|| ident.to_string()); + + quote! { + let mut label = prometheus_client::encoding::proto::Label::default(); + label.name = #ident_string.to_string(); + label.value = format!("{}", self.#ident); + labels.push(label); + } + }) + .collect(); + + quote! { + let mut labels = vec![]; + #push_labels + labels + } + } + syn::Fields::Unnamed(_) => { + panic!("Can not derive Encode for struct with unnamed fields.") + } + syn::Fields::Unit => panic!("Can not derive Encode for struct with unit field."), + }, + syn::Data::Enum(syn::DataEnum { variants, .. }) => { + let match_arms: TokenStream2 = variants + .into_iter() + .map(|v| { + let ident = v.ident; + quote! { + #name::#ident => { + let mut label = prometheus_client::encoding::proto::Label::default(); + label.name = stringify!(#name).to_string(); + label.value = stringify!(#ident).to_string(); + label + } + } + }) + .collect(); + + quote! { + let label = match self { + #match_arms + }; + + vec![label] + } + } + syn::Data::Union(_) => panic!("Can not derive Encode for union."), + }; + + let gen = quote! { + impl prometheus_client::encoding::proto::EncodeLabel for #name { + fn encode(&self) -> Vec { + #body + } + } + }; + gen.into() +} + +// Copied from https://github.com/djc/askama (MIT and APACHE licensed) and +// modified. +static KEYWORD_IDENTIFIERS: [(&str, &str); 48] = [ + ("as", "r#as"), + ("break", "r#break"), + ("const", "r#const"), + ("continue", "r#continue"), + ("crate", "r#crate"), + ("else", "r#else"), + ("enum", "r#enum"), + ("extern", "r#extern"), + ("false", "r#false"), + ("fn", "r#fn"), + ("for", "r#for"), + ("if", "r#if"), + ("impl", "r#impl"), + ("in", "r#in"), + ("let", "r#let"), + ("loop", "r#loop"), + ("match", "r#match"), + ("mod", "r#mod"), + ("move", "r#move"), + ("mut", "r#mut"), + ("pub", "r#pub"), + ("ref", "r#ref"), + ("return", "r#return"), + ("static", "r#static"), + ("struct", "r#struct"), + ("trait", "r#trait"), + ("true", "r#true"), + ("type", "r#type"), + ("unsafe", "r#unsafe"), + ("use", "r#use"), + ("where", "r#where"), + ("while", "r#while"), + ("async", "r#async"), + ("await", "r#await"), + ("dyn", "r#dyn"), + ("abstract", "r#abstract"), + ("become", "r#become"), + ("box", "r#box"), + ("do", "r#do"), + ("final", "r#final"), + ("macro", "r#macro"), + ("override", "r#override"), + ("priv", "r#priv"), + ("typeof", "r#typeof"), + ("unsized", "r#unsized"), + ("virtual", "r#virtual"), + ("yield", "r#yield"), + ("try", "r#try"), +]; diff --git a/derive-proto-encode/tests/lib.rs b/derive-proto-encode/tests/lib.rs new file mode 100644 index 00000000..f5fc97c4 --- /dev/null +++ b/derive-proto-encode/tests/lib.rs @@ -0,0 +1,103 @@ +use prometheus_client::encoding::proto::EncodeLabel; +use prometheus_client::encoding::proto::{encode, EncodeProtobuf}; +use prometheus_client::metrics::counter::Counter; +use prometheus_client::metrics::family::Family; +use prometheus_client::registry::Registry; +use std::fmt::{Display, Formatter}; + +#[test] +fn structs() { + #[derive(Clone, Hash, PartialEq, Eq, EncodeProtobuf)] + struct Labels { + method: Method, + path: String, + } + + #[derive(Clone, Hash, PartialEq, Eq)] + enum Method { + Get, + #[allow(dead_code)] + Put, + } + + impl Display for Method { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Method::Get => f.write_str("Get"), + Method::Put => f.write_str("Put"), + } + } + } + + let mut registry = Registry::default(); + let family = Family::::default(); + registry.register("my_counter", "This is my counter", family.clone()); + + // Record a single HTTP GET request. + family + .get_or_create(&Labels { + method: Method::Get, + path: "/metrics".to_string(), + }) + .inc(); + + // Encode all metrics in the registry in the OpenMetrics protobuf format. + let mut metric_set = encode(®istry); + let mut family: prometheus_client::encoding::proto::MetricFamily = + metric_set.metric_families.pop().unwrap(); + let metric: prometheus_client::encoding::proto::Metric = family.metrics.pop().unwrap(); + + let method = &metric.labels[0]; + assert_eq!("method", method.name); + assert_eq!("Get", method.value); + + let path = &metric.labels[1]; + assert_eq!("path", path.name); + assert_eq!("/metrics", path.value); +} + +#[test] +fn enums() { + #[derive(Clone, Hash, PartialEq, Eq, EncodeProtobuf)] + enum Method { + Get, + #[allow(dead_code)] + Put, + } + + let mut registry = Registry::default(); + let family = Family::::default(); + registry.register("my_counter", "This is my counter", family.clone()); + + // Record a single HTTP GET request. + family.get_or_create(&Method::Get).inc(); + + // Encode all metrics in the registry in the OpenMetrics protobuf format. + let mut metric_set = encode(®istry); + let mut family: prometheus_client::encoding::proto::MetricFamily = + metric_set.metric_families.pop().unwrap(); + let metric: prometheus_client::encoding::proto::Metric = family.metrics.pop().unwrap(); + + let label = &metric.labels[0]; + assert_eq!("Method", label.name); + assert_eq!("Get", label.value); +} + +#[test] +fn remap_keyword_identifiers() { + #[derive(EncodeProtobuf, Hash, Clone, Eq, PartialEq)] + struct Labels { + // `r#type` is problematic as `r#` is not a valid OpenMetrics label name + // but one needs to use keyword identifier syntax (aka. raw identifiers) + // as `type` is a keyword. + // + // Test makes sure `r#type` is replaced by `type` in the OpenMetrics + // output. + r#type: u64, + } + + let labels = Labels { r#type: 42 }.encode(); + + assert_eq!("type", labels[0].name); + assert_eq!("42", labels[0].value); +} diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 4f4ab654..1580aedc 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -38,6 +38,9 @@ use crate::registry::Registry; use std::collections::HashMap; use std::ops::Deref; +pub use openmetrics_data_model::*; +pub use prometheus_client_derive_proto_encode::*; + pub fn encode(registry: &Registry) -> openmetrics_data_model::MetricSet where M: EncodeMetric, From 63a127d7df40f25d0d380d8d54ecd40e9c07dae2 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Wed, 10 Aug 2022 16:39:02 +0900 Subject: [PATCH 50/76] Add impl EncodeGaugeValue for u64 Signed-off-by: ackintosh --- src/encoding/proto.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 1580aedc..ebd25675 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -272,6 +272,12 @@ impl EncodeGaugeValue for i64 { } } +impl EncodeGaugeValue for u64 { + fn encode(&self) -> openmetrics_data_model::gauge_value::Value { + openmetrics_data_model::gauge_value::Value::IntValue(*self as i64) + } +} + impl EncodeGaugeValue for f64 { fn encode(&self) -> openmetrics_data_model::gauge_value::Value { openmetrics_data_model::gauge_value::Value::DoubleValue(*self) From fa07f15edf3f63089449973fefa5f24604df992e Mon Sep 17 00:00:00 2001 From: ackintosh Date: Sun, 31 Jul 2022 11:51:24 +0900 Subject: [PATCH 51/76] Try Associated Type Build error below occurs: error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> src/encoding/proto.rs:199:6 | 199 | impl<'a, N, A> EncodeMetric for Counter | ^^ unconstrained lifetime parameter Signed-off-by: ackintosh --- src/encoding/proto.rs | 70 +++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index ebd25675..fe2e49bc 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -80,19 +80,23 @@ impl From for openmetrics_data_model::MetricType { /// Trait implemented by each metric type, e.g. [`Counter`], to implement its encoding. pub trait EncodeMetric { + type Iterator: Iterator; + fn encode( &self, labels: Vec, - ) -> Vec; + ) -> Self::Iterator; fn metric_type(&self) -> MetricType; } -impl EncodeMetric for Box { +impl<'a> EncodeMetric for Box>> { + type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + fn encode( &self, labels: Vec, - ) -> Vec { + ) -> Self::Iterator { self.deref().encode(labels) } @@ -105,11 +109,13 @@ pub trait SendEncodeMetric: EncodeMetric + Send {} impl SendEncodeMetric for T {} -impl EncodeMetric for Box { +impl<'a> EncodeMetric for Box>> { + type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + fn encode( &self, labels: Vec, - ) -> Vec { + ) -> Self::Iterator { self.deref().encode(labels) } @@ -186,14 +192,16 @@ where N: EncodeCounterValue, A: counter::Atomic, { + type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + fn encode( &self, labels: Vec, - ) -> Vec { + ) -> Self::Iterator { let mut metric = encode_counter_with_maybe_exemplar(self.get(), None); metric.labels = labels; - vec![metric] + vec![metric].iter() } fn metric_type(&self) -> MetricType { @@ -201,17 +209,19 @@ where } } -impl EncodeMetric for CounterWithExemplar +impl<'a, S, N, A> EncodeMetric for CounterWithExemplar where S: EncodeLabel, N: Clone + EncodeCounterValue, A: counter::Atomic, f64: From, { + type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + fn encode( &self, labels: Vec, - ) -> Vec { + ) -> Self::Iterator { let (value, exemplar) = self.get(); let exemplar_proto = if let Some(e) = exemplar.as_ref() { @@ -223,7 +233,7 @@ where let mut metric = encode_counter_with_maybe_exemplar(value.clone(), exemplar_proto); metric.labels = labels; - vec![metric] + vec![metric].iter() } fn metric_type(&self) -> MetricType { @@ -284,15 +294,17 @@ impl EncodeGaugeValue for f64 { } } -impl EncodeMetric for Gauge +impl<'a, N, A> EncodeMetric for Gauge where N: EncodeGaugeValue, A: gauge::Atomic, { + type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + fn encode( &self, labels: Vec, - ) -> Vec { + ) -> Self::Iterator { let mut metric = openmetrics_data_model::Metric::default(); metric.metric_points = { @@ -310,7 +322,7 @@ where }; metric.labels = labels; - vec![metric] + vec![metric].iter() } fn metric_type(&self) -> MetricType { @@ -321,16 +333,18 @@ where ///////////////////////////////////////////////////////////////////////////////// // Family -impl EncodeMetric for Family +impl<'a, S, M, C> EncodeMetric for Family where S: Clone + std::hash::Hash + Eq + EncodeLabel, M: EncodeMetric + TypedMetric, C: MetricConstructor, { + type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + fn encode( &self, labels: Vec, - ) -> Vec { + ) -> Self::Iterator { let mut metrics = vec![]; let guard = self.read(); @@ -340,7 +354,7 @@ where metrics.extend(metric.encode(label)); } - metrics + metrics.iter() } fn metric_type(&self) -> MetricType { @@ -351,16 +365,18 @@ where ///////////////////////////////////////////////////////////////////////////////// // Histogram -impl EncodeMetric for Histogram { +impl<'a> EncodeMetric for Histogram { + type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + fn encode( &self, labels: Vec, - ) -> Vec { + ) -> Self::Iterator { let (sum, count, buckets) = self.get(); // TODO: Would be better to use never type instead of `()`. let mut metric = encode_histogram_with_maybe_exemplars::<()>(sum, count, &buckets, None); metric.labels = labels; - vec![metric] + vec![metric].iter() } fn metric_type(&self) -> MetricType { @@ -368,20 +384,22 @@ impl EncodeMetric for Histogram { } } -impl EncodeMetric for HistogramWithExemplars +impl<'a, S> EncodeMetric for HistogramWithExemplars where S: EncodeLabel, { + type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + fn encode( &self, labels: Vec, - ) -> Vec { + ) -> Self::Iterator { let inner = self.inner(); let (sum, count, buckets) = inner.histogram.get(); let mut metric = encode_histogram_with_maybe_exemplars(sum, count, &buckets, Some(&inner.exemplars)); metric.labels = labels; - vec![metric] + vec![metric].iter() } fn metric_type(&self) -> MetricType { @@ -432,14 +450,16 @@ fn encode_histogram_with_maybe_exemplars( ///////////////////////////////////////////////////////////////////////////////// // Info -impl EncodeMetric for Info +impl<'a, S> EncodeMetric for Info where S: EncodeLabel, { + type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + fn encode( &self, labels: Vec, - ) -> Vec { + ) -> Self::Iterator { let mut metric = openmetrics_data_model::Metric::default(); metric.metric_points = { @@ -459,7 +479,7 @@ where vec![metric_point] }; - vec![metric] + vec![metric].iter() } fn metric_type(&self) -> MetricType { From 977ca7fd9aa7d6cdb379c034177f7c53968b4e41 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Wed, 3 Aug 2022 16:31:44 +0900 Subject: [PATCH 52/76] Fix life parameter issue Build error: error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> src/encoding/proto.rs:199:6 | 199 | impl<'a, N, A> EncodeMetric for Counter | ^^ unconstrained lifetime parameter Signed-off-by: ackintosh --- src/encoding/proto.rs | 105 ++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 66 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index fe2e49bc..898e65ed 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -37,6 +37,7 @@ use crate::metrics::{counter, gauge, MetricType, TypedMetric}; use crate::registry::Registry; use std::collections::HashMap; use std::ops::Deref; +use std::vec::IntoIter; pub use openmetrics_data_model::*; pub use prometheus_client_derive_proto_encode::*; @@ -58,7 +59,7 @@ where family.unit = unit.as_str().to_string(); } family.help = desc.help().to_string(); - family.metrics = metric.encode(desc.labels().encode()); + family.metrics = metric.encode(desc.labels().encode()).collect::>(); metric_set.metric_families.push(family); } @@ -82,21 +83,15 @@ impl From for openmetrics_data_model::MetricType { pub trait EncodeMetric { type Iterator: Iterator; - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator; + fn encode(&self, labels: Vec) -> Self::Iterator; fn metric_type(&self) -> MetricType; } -impl<'a> EncodeMetric for Box>> { - type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; - - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator { +impl EncodeMetric for Box>> { + type Iterator = IntoIter; + + fn encode(&self, labels: Vec) -> Self::Iterator { self.deref().encode(labels) } @@ -109,13 +104,12 @@ pub trait SendEncodeMetric: EncodeMetric + Send {} impl SendEncodeMetric for T {} -impl<'a> EncodeMetric for Box>> { - type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; +impl EncodeMetric + for Box>> +{ + type Iterator = IntoIter; - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator { + fn encode(&self, labels: Vec) -> Self::Iterator { self.deref().encode(labels) } @@ -192,16 +186,13 @@ where N: EncodeCounterValue, A: counter::Atomic, { - type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + type Iterator = IntoIter; - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator { + fn encode(&self, labels: Vec) -> Self::Iterator { let mut metric = encode_counter_with_maybe_exemplar(self.get(), None); metric.labels = labels; - vec![metric].iter() + vec![metric].into_iter() } fn metric_type(&self) -> MetricType { @@ -209,19 +200,16 @@ where } } -impl<'a, S, N, A> EncodeMetric for CounterWithExemplar +impl EncodeMetric for CounterWithExemplar where S: EncodeLabel, N: Clone + EncodeCounterValue, A: counter::Atomic, f64: From, { - type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + type Iterator = IntoIter; - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator { + fn encode(&self, labels: Vec) -> Self::Iterator { let (value, exemplar) = self.get(); let exemplar_proto = if let Some(e) = exemplar.as_ref() { @@ -233,7 +221,7 @@ where let mut metric = encode_counter_with_maybe_exemplar(value.clone(), exemplar_proto); metric.labels = labels; - vec![metric].iter() + vec![metric].into_iter() } fn metric_type(&self) -> MetricType { @@ -294,17 +282,14 @@ impl EncodeGaugeValue for f64 { } } -impl<'a, N, A> EncodeMetric for Gauge +impl EncodeMetric for Gauge where N: EncodeGaugeValue, A: gauge::Atomic, { - type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + type Iterator = IntoIter; - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator { + fn encode(&self, labels: Vec) -> Self::Iterator { let mut metric = openmetrics_data_model::Metric::default(); metric.metric_points = { @@ -322,7 +307,7 @@ where }; metric.labels = labels; - vec![metric].iter() + vec![metric].into_iter() } fn metric_type(&self) -> MetricType { @@ -333,18 +318,15 @@ where ///////////////////////////////////////////////////////////////////////////////// // Family -impl<'a, S, M, C> EncodeMetric for Family +impl EncodeMetric for Family where S: Clone + std::hash::Hash + Eq + EncodeLabel, M: EncodeMetric + TypedMetric, C: MetricConstructor, { - type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + type Iterator = IntoIter; - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator { + fn encode(&self, labels: Vec) -> Self::Iterator { let mut metrics = vec![]; let guard = self.read(); @@ -354,7 +336,7 @@ where metrics.extend(metric.encode(label)); } - metrics.iter() + metrics.into_iter() } fn metric_type(&self) -> MetricType { @@ -365,18 +347,15 @@ where ///////////////////////////////////////////////////////////////////////////////// // Histogram -impl<'a> EncodeMetric for Histogram { - type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; +impl EncodeMetric for Histogram { + type Iterator = IntoIter; - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator { + fn encode(&self, labels: Vec) -> Self::Iterator { let (sum, count, buckets) = self.get(); // TODO: Would be better to use never type instead of `()`. let mut metric = encode_histogram_with_maybe_exemplars::<()>(sum, count, &buckets, None); metric.labels = labels; - vec![metric].iter() + vec![metric].into_iter() } fn metric_type(&self) -> MetricType { @@ -384,22 +363,19 @@ impl<'a> EncodeMetric for Histogram { } } -impl<'a, S> EncodeMetric for HistogramWithExemplars +impl EncodeMetric for HistogramWithExemplars where S: EncodeLabel, { - type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + type Iterator = IntoIter; - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator { + fn encode(&self, labels: Vec) -> Self::Iterator { let inner = self.inner(); let (sum, count, buckets) = inner.histogram.get(); let mut metric = encode_histogram_with_maybe_exemplars(sum, count, &buckets, Some(&inner.exemplars)); metric.labels = labels; - vec![metric].iter() + vec![metric].into_iter() } fn metric_type(&self) -> MetricType { @@ -450,16 +426,13 @@ fn encode_histogram_with_maybe_exemplars( ///////////////////////////////////////////////////////////////////////////////// // Info -impl<'a, S> EncodeMetric for Info +impl EncodeMetric for Info where S: EncodeLabel, { - type Iterator = std::slice::Iter<'a, openmetrics_data_model::Metric>; + type Iterator = IntoIter; - fn encode( - &self, - labels: Vec, - ) -> Self::Iterator { + fn encode(&self, labels: Vec) -> Self::Iterator { let mut metric = openmetrics_data_model::Metric::default(); metric.metric_points = { @@ -479,7 +452,7 @@ where vec![metric_point] }; - vec![metric].iter() + vec![metric].into_iter() } fn metric_type(&self) -> MetricType { From 05dab820ecbfa4a8c8d4089c908d747747319a06 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Wed, 3 Aug 2022 16:49:35 +0900 Subject: [PATCH 53/76] Make EncodeLabel::encode return iterator Signed-off-by: ackintosh --- src/encoding/proto.rs | 46 +++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 898e65ed..01304948 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -59,7 +59,9 @@ where family.unit = unit.as_str().to_string(); } family.help = desc.help().to_string(); - family.metrics = metric.encode(desc.labels().encode()).collect::>(); + family.metrics = metric + .encode(desc.labels().encode().collect::>()) + .collect::>(); metric_set.metric_families.push(family); } @@ -119,33 +121,51 @@ impl EncodeMetric } pub trait EncodeLabel { - fn encode(&self) -> Vec; + type Iterator: Iterator; + + fn encode(&self) -> Self::Iterator; } impl EncodeLabel for (K, V) { - fn encode(&self) -> Vec { + type Iterator = IntoIter; + + fn encode(&self) -> Self::Iterator { let mut label = openmetrics_data_model::Label::default(); label.name = self.0.to_string(); label.value = self.1.to_string(); - vec![label] + vec![label].into_iter() } } impl EncodeLabel for Vec { - fn encode(&self) -> Vec { - self.iter().map(|t| t.encode()).flatten().collect() + type Iterator = IntoIter; + + fn encode(&self) -> Self::Iterator { + self.iter() + .map(|t| t.encode()) + .flatten() + .collect::>() + .into_iter() } } impl EncodeLabel for &[T] { - fn encode(&self) -> Vec { - self.iter().map(|t| t.encode()).flatten().collect() + type Iterator = IntoIter; + + fn encode(&self) -> Self::Iterator { + self.iter() + .map(|t| t.encode()) + .flatten() + .collect::>() + .into_iter() } } impl EncodeLabel for () { - fn encode(&self) -> Vec { - vec![] + type Iterator = IntoIter; + + fn encode(&self) -> Self::Iterator { + vec![].into_iter() } } @@ -157,7 +177,7 @@ where { let mut exemplar_proto = openmetrics_data_model::Exemplar::default(); exemplar_proto.value = exemplar.value.clone().into(); - exemplar_proto.label = exemplar.label_set.encode(); + exemplar_proto.label = exemplar.label_set.encode().collect::>(); exemplar_proto } @@ -331,7 +351,7 @@ where let guard = self.read(); for (label_set, metric) in guard.iter() { - let mut label = label_set.encode(); + let mut label = label_set.encode().collect::>(); label.append(&mut labels.clone()); metrics.extend(metric.encode(label)); } @@ -438,7 +458,7 @@ where metric.metric_points = { let mut metric_point = openmetrics_data_model::MetricPoint::default(); metric_point.value = { - let mut label = self.0.encode(); + let mut label = self.0.encode().collect::>(); label.append(&mut labels.clone()); let mut info_value = openmetrics_data_model::InfoValue::default(); From b3d49cebad9e57a68c5338afd5d1451f915570f0 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Mon, 8 Aug 2022 20:07:23 +0900 Subject: [PATCH 54/76] src/encoding/proto: Refactor EncodeLabel and EncodeMetric Signed-off-by: ackintosh --- src/encoding/proto.rs | 154 ++++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 75 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 01304948..24880c81 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -90,8 +90,10 @@ pub trait EncodeMetric { fn metric_type(&self) -> MetricType; } -impl EncodeMetric for Box>> { - type Iterator = IntoIter; +impl EncodeMetric + for Box>>> +{ + type Iterator = Box>; fn encode(&self, labels: Vec) -> Self::Iterator { self.deref().encode(labels) @@ -107,9 +109,11 @@ pub trait SendEncodeMetric: EncodeMetric + Send {} impl SendEncodeMetric for T {} impl EncodeMetric - for Box>> + for Box< + dyn SendEncodeMetric>>, + > { - type Iterator = IntoIter; + type Iterator = Box>; fn encode(&self, labels: Vec) -> Self::Iterator { self.deref().encode(labels) @@ -120,59 +124,49 @@ impl EncodeMetric } } +// TODO: Rename to EncodeLabels? pub trait EncodeLabel { type Iterator: Iterator; - fn encode(&self) -> Self::Iterator; + fn encode(self) -> Self::Iterator; } -impl EncodeLabel for (K, V) { - type Iterator = IntoIter; - - fn encode(&self) -> Self::Iterator { +impl Into for &(K, V) { + fn into(self) -> openmetrics_data_model::Label { let mut label = openmetrics_data_model::Label::default(); label.name = self.0.to_string(); label.value = self.1.to_string(); - vec![label].into_iter() - } -} - -impl EncodeLabel for Vec { - type Iterator = IntoIter; - - fn encode(&self) -> Self::Iterator { - self.iter() - .map(|t| t.encode()) - .flatten() - .collect::>() - .into_iter() + label } } -impl EncodeLabel for &[T] { - type Iterator = IntoIter; +// TODO: Is this needed? We already have `&'a [T]` below. +impl<'a, T> EncodeLabel for &'a Vec +where + for<'b> &'b T: Into, +{ + type Iterator = Box + 'a>; - fn encode(&self) -> Self::Iterator { - self.iter() - .map(|t| t.encode()) - .flatten() - .collect::>() - .into_iter() + fn encode(self) -> Self::Iterator { + Box::new(self.iter().map(|t| t.into())) } } -impl EncodeLabel for () { - type Iterator = IntoIter; +impl<'a, T> EncodeLabel for &'a [T] +where + for<'b> &'b T: Into, +{ + type Iterator = Box + 'a>; - fn encode(&self) -> Self::Iterator { - vec![].into_iter() + fn encode(self) -> Self::Iterator { + Box::new(self.iter().map(|t| t.into())) } } fn encode_exemplar(exemplar: &Exemplar) -> openmetrics_data_model::Exemplar where N: Clone, - S: EncodeLabel, + for<'a> &'a S: EncodeLabel, f64: From, // required because Exemplar.value is defined as `double` in protobuf { let mut exemplar_proto = openmetrics_data_model::Exemplar::default(); @@ -206,13 +200,13 @@ where N: EncodeCounterValue, A: counter::Atomic, { - type Iterator = IntoIter; + type Iterator = std::iter::Once; fn encode(&self, labels: Vec) -> Self::Iterator { let mut metric = encode_counter_with_maybe_exemplar(self.get(), None); metric.labels = labels; - vec![metric].into_iter() + std::iter::once(metric) } fn metric_type(&self) -> MetricType { @@ -220,14 +214,14 @@ where } } -impl EncodeMetric for CounterWithExemplar +impl<'a, S, N, A> EncodeMetric for CounterWithExemplar where - S: EncodeLabel, + for<'b> &'b S: EncodeLabel, N: Clone + EncodeCounterValue, A: counter::Atomic, f64: From, { - type Iterator = IntoIter; + type Iterator = std::iter::Once; fn encode(&self, labels: Vec) -> Self::Iterator { let (value, exemplar) = self.get(); @@ -241,7 +235,7 @@ where let mut metric = encode_counter_with_maybe_exemplar(value.clone(), exemplar_proto); metric.labels = labels; - vec![metric].into_iter() + std::iter::once(metric) } fn metric_type(&self) -> MetricType { @@ -302,12 +296,12 @@ impl EncodeGaugeValue for f64 { } } -impl EncodeMetric for Gauge +impl<'a, N, A> EncodeMetric for Gauge where N: EncodeGaugeValue, A: gauge::Atomic, { - type Iterator = IntoIter; + type Iterator = std::iter::Once; fn encode(&self, labels: Vec) -> Self::Iterator { let mut metric = openmetrics_data_model::Metric::default(); @@ -327,7 +321,7 @@ where }; metric.labels = labels; - vec![metric].into_iter() + std::iter::once(metric) } fn metric_type(&self) -> MetricType { @@ -338,25 +332,30 @@ where ///////////////////////////////////////////////////////////////////////////////// // Family -impl EncodeMetric for Family +impl<'c, S, M, C> EncodeMetric for Family where - S: Clone + std::hash::Hash + Eq + EncodeLabel, + S: Clone + std::hash::Hash + Eq, + for<'b> &'b S: EncodeLabel, M: EncodeMetric + TypedMetric, C: MetricConstructor, { type Iterator = IntoIter; fn encode(&self, labels: Vec) -> Self::Iterator { - let mut metrics = vec![]; - - let guard = self.read(); - for (label_set, metric) in guard.iter() { - let mut label = label_set.encode().collect::>(); - label.append(&mut labels.clone()); - metrics.extend(metric.encode(label)); - } - - metrics.into_iter() + self.read() + .iter() + .map(|(label_set, metric)| { + let mut labels = labels.clone(); + labels.extend(label_set.encode()); + metric.encode(labels) + }) + .flatten() + // TODO: Ideally we would not have to collect into a vector here, + // though we have to as we borrow from the `MutexGuard`. Once + // https://github.com/prometheus/client_rust/pull/78/ merged, we + // might be able to leverage `MutexGuard::map`. + .collect::>() + .into_iter() } fn metric_type(&self) -> MetricType { @@ -368,14 +367,17 @@ where // Histogram impl EncodeMetric for Histogram { - type Iterator = IntoIter; + type Iterator = std::iter::Once; fn encode(&self, labels: Vec) -> Self::Iterator { let (sum, count, buckets) = self.get(); // TODO: Would be better to use never type instead of `()`. - let mut metric = encode_histogram_with_maybe_exemplars::<()>(sum, count, &buckets, None); + // TODO: Revert (String, String)? + let mut metric = encode_histogram_with_maybe_exemplars::>( + sum, count, &buckets, None, + ); metric.labels = labels; - vec![metric].into_iter() + std::iter::once(metric) } fn metric_type(&self) -> MetricType { @@ -385,9 +387,9 @@ impl EncodeMetric for Histogram { impl EncodeMetric for HistogramWithExemplars where - S: EncodeLabel, + for<'b> &'b S: EncodeLabel, { - type Iterator = IntoIter; + type Iterator = std::iter::Once; fn encode(&self, labels: Vec) -> Self::Iterator { let inner = self.inner(); @@ -395,7 +397,7 @@ where let mut metric = encode_histogram_with_maybe_exemplars(sum, count, &buckets, Some(&inner.exemplars)); metric.labels = labels; - vec![metric].into_iter() + std::iter::once(metric) } fn metric_type(&self) -> MetricType { @@ -403,12 +405,15 @@ where } } -fn encode_histogram_with_maybe_exemplars( +fn encode_histogram_with_maybe_exemplars<'a, S>( sum: f64, count: u64, buckets: &[(f64, u64)], - exemplars: Option<&HashMap>>, -) -> openmetrics_data_model::Metric { + exemplars: Option<&'a HashMap>>, +) -> openmetrics_data_model::Metric +where + for<'b> &'b S: EncodeLabel, +{ let mut metric = openmetrics_data_model::Metric::default(); metric.metric_points = { @@ -448,21 +453,20 @@ fn encode_histogram_with_maybe_exemplars( impl EncodeMetric for Info where - S: EncodeLabel, + for<'b> &'b S: EncodeLabel, { - type Iterator = IntoIter; + type Iterator = std::iter::Once; - fn encode(&self, labels: Vec) -> Self::Iterator { + fn encode(&self, mut labels: Vec) -> Self::Iterator { let mut metric = openmetrics_data_model::Metric::default(); metric.metric_points = { let mut metric_point = openmetrics_data_model::MetricPoint::default(); metric_point.value = { - let mut label = self.0.encode().collect::>(); - label.append(&mut labels.clone()); + labels.extend(self.0.encode()); let mut info_value = openmetrics_data_model::InfoValue::default(); - info_value.info = label; + info_value.info = labels; Some(openmetrics_data_model::metric_point::Value::InfoValue( info_value, @@ -472,7 +476,7 @@ where vec![metric_point] }; - vec![metric].into_iter() + std::iter::once(metric) } fn metric_type(&self) -> MetricType { @@ -571,7 +575,7 @@ mod tests { fn encode_counter_with_exemplar() { let mut registry = Registry::default(); - let counter_with_exemplar: CounterWithExemplar<(String, f64), f64> = + let counter_with_exemplar: CounterWithExemplar, f64> = CounterWithExemplar::default(); registry.register( "my_counter_with_exemplar", @@ -579,7 +583,7 @@ mod tests { counter_with_exemplar.clone(), ); - counter_with_exemplar.inc_by(1.0, Some(("user_id".to_string(), 42.0))); + counter_with_exemplar.inc_by(1.0, Some(vec![("user_id".to_string(), 42.0)])); let metric_set = encode(®istry); @@ -766,7 +770,7 @@ mod tests { let mut registry = Registry::default(); let histogram = HistogramWithExemplars::new(exponential_buckets(1.0, 2.0, 10)); registry.register("my_histogram", "My histogram", histogram.clone()); - histogram.observe(1.0, Some(("user_id".to_string(), 42u64))); + histogram.observe(1.0, Some(vec![("user_id".to_string(), 42u64)])); let metric_set = encode(®istry); From d55296ddeaa6e561301a19175ee518fcc7ac8ab5 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Fri, 12 Aug 2022 10:02:24 +0900 Subject: [PATCH 55/76] Fix assertions because of changes of the order of result Signed-off-by: ackintosh --- src/encoding/proto.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 24880c81..28d421a2 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -714,12 +714,12 @@ mod tests { let metric = family.metrics.first().unwrap(); assert_eq!(3, metric.labels.len()); - assert_eq!("method", metric.labels[0].name); - assert_eq!("GET", metric.labels[0].value); - assert_eq!("status", metric.labels[1].name); - assert_eq!("200", metric.labels[1].value); - assert_eq!("my_key", metric.labels[2].name); - assert_eq!("my_value", metric.labels[2].value); + assert_eq!("my_key", metric.labels[0].name); + assert_eq!("my_value", metric.labels[0].value); + assert_eq!("method", metric.labels[1].name); + assert_eq!("GET", metric.labels[1].value); + assert_eq!("status", metric.labels[2].name); + assert_eq!("200", metric.labels[2].value); match extract_metric_point_value(metric_set) { openmetrics_data_model::metric_point::Value::CounterValue(value) => { From ff7ada0b30ee459ef6ee893f0fb8842a6e1d4e6c Mon Sep 17 00:00:00 2001 From: ackintosh Date: Fri, 12 Aug 2022 10:03:01 +0900 Subject: [PATCH 56/76] Remove unnecessary lifetime parameter Signed-off-by: ackintosh --- src/encoding/proto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 28d421a2..d01f8536 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -332,7 +332,7 @@ where ///////////////////////////////////////////////////////////////////////////////// // Family -impl<'c, S, M, C> EncodeMetric for Family +impl EncodeMetric for Family where S: Clone + std::hash::Hash + Eq, for<'b> &'b S: EncodeLabel, From 42f00e3eb2be44e2f89d31722a6f1a9855fb8c7c Mon Sep 17 00:00:00 2001 From: ackintosh Date: Fri, 12 Aug 2022 10:04:18 +0900 Subject: [PATCH 57/76] Rename EncodeLabel -> EncodeLabels Signed-off-by: ackintosh --- src/encoding/proto.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index d01f8536..2a19d4df 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -124,8 +124,7 @@ impl EncodeMetric } } -// TODO: Rename to EncodeLabels? -pub trait EncodeLabel { +pub trait EncodeLabels { type Iterator: Iterator; fn encode(self) -> Self::Iterator; @@ -141,7 +140,7 @@ impl Into for &(K, V) { } // TODO: Is this needed? We already have `&'a [T]` below. -impl<'a, T> EncodeLabel for &'a Vec +impl<'a, T> EncodeLabels for &'a Vec where for<'b> &'b T: Into, { @@ -152,7 +151,7 @@ where } } -impl<'a, T> EncodeLabel for &'a [T] +impl<'a, T> EncodeLabels for &'a [T] where for<'b> &'b T: Into, { @@ -166,7 +165,7 @@ where fn encode_exemplar(exemplar: &Exemplar) -> openmetrics_data_model::Exemplar where N: Clone, - for<'a> &'a S: EncodeLabel, + for<'a> &'a S: EncodeLabels, f64: From, // required because Exemplar.value is defined as `double` in protobuf { let mut exemplar_proto = openmetrics_data_model::Exemplar::default(); @@ -216,7 +215,7 @@ where impl<'a, S, N, A> EncodeMetric for CounterWithExemplar where - for<'b> &'b S: EncodeLabel, + for<'b> &'b S: EncodeLabels, N: Clone + EncodeCounterValue, A: counter::Atomic, f64: From, @@ -335,7 +334,7 @@ where impl EncodeMetric for Family where S: Clone + std::hash::Hash + Eq, - for<'b> &'b S: EncodeLabel, + for<'b> &'b S: EncodeLabels, M: EncodeMetric + TypedMetric, C: MetricConstructor, { @@ -387,7 +386,7 @@ impl EncodeMetric for Histogram { impl EncodeMetric for HistogramWithExemplars where - for<'b> &'b S: EncodeLabel, + for<'b> &'b S: EncodeLabels, { type Iterator = std::iter::Once; @@ -412,7 +411,7 @@ fn encode_histogram_with_maybe_exemplars<'a, S>( exemplars: Option<&'a HashMap>>, ) -> openmetrics_data_model::Metric where - for<'b> &'b S: EncodeLabel, + for<'b> &'b S: EncodeLabels, { let mut metric = openmetrics_data_model::Metric::default(); @@ -453,7 +452,7 @@ where impl EncodeMetric for Info where - for<'b> &'b S: EncodeLabel, + for<'b> &'b S: EncodeLabels, { type Iterator = std::iter::Once; From 6d4f6f69eb2dcf79c4af022f608cfe19839a0e70 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Fri, 12 Aug 2022 10:38:57 +0900 Subject: [PATCH 58/76] Using `Void` to indicate the impossible case Signed-off-by: ackintosh --- Cargo.toml | 1 + src/encoding/proto.rs | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b536b8d0..58489e82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ prometheus-client-derive-proto-encode = { version = "0.1.0", path = "derive-prot prometheus-client-derive-text-encode = { version = "0.3.0", path = "derive-text-encode" } prost = { version = "0.9.0", optional = true } prost-types = { version = "0.9.0", optional = true } +void = "1.0" [dev-dependencies] async-std = { version = "1", features = ["attributes"] } diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 2a19d4df..b1be09e4 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -38,6 +38,7 @@ use crate::registry::Registry; use std::collections::HashMap; use std::ops::Deref; use std::vec::IntoIter; +use void::Void; pub use openmetrics_data_model::*; pub use prometheus_client_derive_proto_encode::*; @@ -162,6 +163,14 @@ where } } +impl<'a> EncodeLabels for &'a Void { + type Iterator = Box>; + + fn encode(self) -> Self::Iterator { + unreachable!() + } +} + fn encode_exemplar(exemplar: &Exemplar) -> openmetrics_data_model::Exemplar where N: Clone, @@ -370,11 +379,8 @@ impl EncodeMetric for Histogram { fn encode(&self, labels: Vec) -> Self::Iterator { let (sum, count, buckets) = self.get(); - // TODO: Would be better to use never type instead of `()`. - // TODO: Revert (String, String)? - let mut metric = encode_histogram_with_maybe_exemplars::>( - sum, count, &buckets, None, - ); + // TODO: Would be better to use never type instead of `Void`. + let mut metric = encode_histogram_with_maybe_exemplars::(sum, count, &buckets, None); metric.labels = labels; std::iter::once(metric) } From 1c965d4f0df35100e2f666005c8d0ea3a42c91c2 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Fri, 12 Aug 2022 11:17:28 +0900 Subject: [PATCH 59/76] Changed proc macro accordingly since `encode` returns iterator Signed-off-by: ackintosh --- derive-proto-encode/src/lib.rs | 10 ++++++---- derive-proto-encode/tests/lib.rs | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/derive-proto-encode/src/lib.rs b/derive-proto-encode/src/lib.rs index 61589652..09b30e73 100644 --- a/derive-proto-encode/src/lib.rs +++ b/derive-proto-encode/src/lib.rs @@ -33,7 +33,7 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { quote! { let mut labels = vec![]; #push_labels - labels + Box::new(labels.into_iter()) } } syn::Fields::Unnamed(_) => { @@ -62,15 +62,17 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { #match_arms }; - vec![label] + Box::new(vec![label].into_iter()) } } syn::Data::Union(_) => panic!("Can not derive Encode for union."), }; let gen = quote! { - impl prometheus_client::encoding::proto::EncodeLabel for #name { - fn encode(&self) -> Vec { + impl<'a> prometheus_client::encoding::proto::EncodeLabels for &'a #name { + type Iterator = Box + 'a>; + + fn encode(self) -> Self::Iterator { #body } } diff --git a/derive-proto-encode/tests/lib.rs b/derive-proto-encode/tests/lib.rs index f5fc97c4..5c0e1ad2 100644 --- a/derive-proto-encode/tests/lib.rs +++ b/derive-proto-encode/tests/lib.rs @@ -1,4 +1,4 @@ -use prometheus_client::encoding::proto::EncodeLabel; +use prometheus_client::encoding::proto::EncodeLabels; use prometheus_client::encoding::proto::{encode, EncodeProtobuf}; use prometheus_client::metrics::counter::Counter; use prometheus_client::metrics::family::Family; @@ -96,7 +96,7 @@ fn remap_keyword_identifiers() { r#type: u64, } - let labels = Labels { r#type: 42 }.encode(); + let labels = Labels { r#type: 42 }.encode().collect::>(); assert_eq!("type", labels[0].name); assert_eq!("42", labels[0].value); From 9e83678f5056f4c31cadd294739c29802ed49ea5 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Sat, 13 Aug 2022 08:37:50 +0900 Subject: [PATCH 60/76] Rename the proc macro since the name was a bit redundant Signed-off-by: ackintosh --- derive-proto-encode/src/lib.rs | 2 +- derive-proto-encode/tests/lib.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/derive-proto-encode/src/lib.rs b/derive-proto-encode/src/lib.rs index 09b30e73..0ad0ad98 100644 --- a/derive-proto-encode/src/lib.rs +++ b/derive-proto-encode/src/lib.rs @@ -3,7 +3,7 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; use syn::DeriveInput; -#[proc_macro_derive(EncodeProtobuf)] +#[proc_macro_derive(Encode)] pub fn derive_encode(input: TokenStream) -> TokenStream { let ast: DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; diff --git a/derive-proto-encode/tests/lib.rs b/derive-proto-encode/tests/lib.rs index 5c0e1ad2..de18b4ab 100644 --- a/derive-proto-encode/tests/lib.rs +++ b/derive-proto-encode/tests/lib.rs @@ -1,5 +1,5 @@ use prometheus_client::encoding::proto::EncodeLabels; -use prometheus_client::encoding::proto::{encode, EncodeProtobuf}; +use prometheus_client::encoding::proto::{encode, Encode}; use prometheus_client::metrics::counter::Counter; use prometheus_client::metrics::family::Family; use prometheus_client::registry::Registry; @@ -7,7 +7,7 @@ use std::fmt::{Display, Formatter}; #[test] fn structs() { - #[derive(Clone, Hash, PartialEq, Eq, EncodeProtobuf)] + #[derive(Clone, Hash, PartialEq, Eq, Encode)] struct Labels { method: Method, path: String, @@ -58,7 +58,7 @@ fn structs() { #[test] fn enums() { - #[derive(Clone, Hash, PartialEq, Eq, EncodeProtobuf)] + #[derive(Clone, Hash, PartialEq, Eq, Encode)] enum Method { Get, #[allow(dead_code)] @@ -85,7 +85,7 @@ fn enums() { #[test] fn remap_keyword_identifiers() { - #[derive(EncodeProtobuf, Hash, Clone, Eq, PartialEq)] + #[derive(Encode, Hash, Clone, Eq, PartialEq)] struct Labels { // `r#type` is problematic as `r#` is not a valid OpenMetrics label name // but one needs to use keyword identifier syntax (aka. raw identifiers) From cbd97ab00b872fbbd6545c4043d8c90656dd6a5e Mon Sep 17 00:00:00 2001 From: Vasiliy Taranov Date: Mon, 1 Aug 2022 10:09:23 +0300 Subject: [PATCH 61/76] examples/: Add actix-web binary (#76) Signed-off-by: ackintosh --- CHANGELOG.md | 2 ++ Cargo.toml | 1 + examples/actix-web.rs | 74 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 examples/actix-web.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index a1d18c3f..d881544c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added a `with_prefix` method to `Registry` to allow initializing a registry with a prefix. See [PR 70]. - Added `Debug` implementations on most public types that were missing them. See [PR 71]. +- Added example for actix-web framework. See [PR 76]. ### Removed - Remove `Add` trait implementation for a private type which lead to compile time conflicts with existing `Add` implementations e.g. on `String`. See [PR 69]. @@ -20,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [PR 69]: https://github.com/prometheus/client_rust/pull/69 [PR 70]: https://github.com/prometheus/client_rust/pull/70 [PR 71]: https://github.com/prometheus/client_rust/pull/71 +[PR 76]: https://github.com/prometheus/client_rust/pull/76 ## [0.16.0] diff --git a/Cargo.toml b/Cargo.toml index 58489e82..b4880e7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ pyo3 = "0.16" quickcheck = "1" rand = "0.8.4" tide = "0.16" +actix-web = "4" [build-dependencies] prost-build = { version = "0.9.0", optional = true } diff --git a/examples/actix-web.rs b/examples/actix-web.rs new file mode 100644 index 00000000..20fae762 --- /dev/null +++ b/examples/actix-web.rs @@ -0,0 +1,74 @@ +use std::sync::Mutex; + +use actix_web::{web, App, HttpResponse, HttpServer, Responder, Result}; +use prometheus_client::encoding::text::{encode, Encode}; +use prometheus_client::metrics::counter::Counter; +use prometheus_client::metrics::family::Family; +use prometheus_client::registry::Registry; + +#[derive(Clone, Hash, PartialEq, Eq, Encode)] +pub enum Method { + Get, + Post, +} + +#[derive(Clone, Hash, PartialEq, Eq, Encode)] +pub struct MethodLabels { + pub method: Method, +} + +pub struct Metrics { + requests: Family, +} + +impl Metrics { + pub fn inc_requests(&self, method: Method) { + self.requests.get_or_create(&MethodLabels { method }).inc(); + } +} + +pub struct AppState { + pub registry: Registry, +} + +pub async fn metrics_handler(state: web::Data>) -> Result { + let state = state.lock().unwrap(); + let mut buf = Vec::new(); + encode(&mut buf, &state.registry)?; + let body = std::str::from_utf8(buf.as_slice()).unwrap().to_string(); + Ok(HttpResponse::Ok() + .content_type("application/openmetrics-text; version=1.0.0; charset=utf-8") + .body(body)) +} + +pub async fn some_handler(metrics: web::Data) -> impl Responder { + metrics.inc_requests(Method::Get); + "okay".to_string() +} + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + let metrics = web::Data::new(Metrics { + requests: Family::default(), + }); + let mut state = AppState { + registry: Registry::default(), + }; + state.registry.register( + "requests", + "Count of requests", + Box::new(metrics.requests.clone()), + ); + let state = web::Data::new(Mutex::new(state)); + + HttpServer::new(move || { + App::new() + .app_data(metrics.clone()) + .app_data(state.clone()) + .service(web::resource("/metrics").route(web::get().to(metrics_handler))) + .service(web::resource("/handler").route(web::get().to(some_handler))) + }) + .bind(("127.0.0.1", 8080))? + .run() + .await +} From de0f38f06d17499c118cf30642e1722b1f182876 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Wed, 10 Aug 2022 09:33:55 +0200 Subject: [PATCH 62/76] .github/workflows/: Add `wasm32` as a cross-compile target (#79) Signed-off-by: ackintosh --- .github/workflows/rust.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 864faad5..7d00d45d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -147,6 +147,7 @@ jobs: - mipsel-unknown-linux-gnu - powerpc-unknown-linux-gnu - powerpc64-unknown-linux-gnu + - wasm32-unknown-unknown steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 From 3cff4d696c999d6a9d0162a98ae345f52ea47894 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Sat, 13 Aug 2022 10:00:55 +0900 Subject: [PATCH 63/76] Add a test for Family (counter and histogram) Signed-off-by: ackintosh --- src/encoding/proto.rs | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index b1be09e4..0d801e96 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -109,12 +109,8 @@ pub trait SendEncodeMetric: EncodeMetric + Send {} impl SendEncodeMetric for T {} -impl EncodeMetric - for Box< - dyn SendEncodeMetric>>, - > -{ - type Iterator = Box>; +impl EncodeMetric for Box>> { + type Iterator = IntoIter; fn encode(&self, labels: Vec) -> Self::Iterator { self.deref().encode(labels) @@ -805,6 +801,38 @@ mod tests { } } + #[test] + fn encode_family_counter_histogram() { + let mut registry = Registry::< + Box>>, + >::default(); + + let counter_family = Family::, Counter>::default(); + let histogram_family = + Family::, Histogram>::new_with_constructor(|| { + Histogram::new(exponential_buckets(1.0, 2.0, 10)) + }); + + registry.register("my_counter", "My counter", Box::new(counter_family.clone())); + registry.register( + "my_histogram", + "My histogram", + Box::new(histogram_family.clone()), + ); + + counter_family + .get_or_create(&vec![("path".to_string(), "/".to_string())]) + .inc(); + + histogram_family + .get_or_create(&vec![("path".to_string(), "/".to_string())]) + .observe(1.0); + + let metric_set = encode(®istry); + assert_eq!("my_counter", metric_set.metric_families[0].name); + assert_eq!("my_histogram", metric_set.metric_families[1].name); + } + #[test] fn encode_info() { let mut registry = Registry::default(); From 3548aa4a05afcacafb5d511d1c617bd946e4f7eb Mon Sep 17 00:00:00 2001 From: ackintosh Date: Sat, 13 Aug 2022 10:20:40 +0900 Subject: [PATCH 64/76] Add benchmark code for proto encoding Signed-off-by: ackintosh --- Cargo.toml | 5 +++ benches/encoding/proto.rs | 85 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 benches/encoding/proto.rs diff --git a/Cargo.toml b/Cargo.toml index b4880e7b..7cc00f35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,3 +47,8 @@ harness = false name = "text" path = "benches/encoding/text.rs" harness = false + +[[bench]] +name = "proto" +path = "benches/encoding/proto.rs" +harness = false diff --git a/benches/encoding/proto.rs b/benches/encoding/proto.rs new file mode 100644 index 00000000..81dbc73a --- /dev/null +++ b/benches/encoding/proto.rs @@ -0,0 +1,85 @@ +// Benchmark inspired by https://github.com/tikv/rust-prometheus/blob/ab1ca7285d3463504381a5025ae1951e020d6796/benches/text_encoder.rs + +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use prometheus_client::encoding::proto::{encode, Encode, EncodeMetric}; +use prometheus_client::metrics::counter::Counter; +use prometheus_client::metrics::family::Family; +use prometheus_client::metrics::histogram::{exponential_buckets, Histogram}; +use prometheus_client::registry::Registry; +use std::fmt::{Display, Formatter}; +use std::vec::IntoIter; + +pub fn proto(c: &mut Criterion) { + c.bench_function("encode", |b| { + #[derive(Clone, Hash, PartialEq, Eq, Encode)] + struct Labels { + path: String, + method: Method, + some_number: u64, + } + + #[derive(Clone, Hash, PartialEq, Eq)] + enum Method { + Get, + #[allow(dead_code)] + Put, + } + + impl Display for Method { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Method::Get => write!(f, "Get"), + Method::Put => write!(f, "Put"), + } + } + } + + let mut registry = Registry::< + Box>>, + >::default(); + + for i in 0..100 { + let counter_family = Family::::default(); + let histogram_family = Family::::new_with_constructor(|| { + Histogram::new(exponential_buckets(1.0, 2.0, 10)) + }); + + registry.register( + format!("my_counter{}", i), + "My counter", + Box::new(counter_family.clone()), + ); + registry.register( + format!("my_histogram{}", i), + "My histogram", + Box::new(histogram_family.clone()), + ); + + for j in 0_u32..100 { + counter_family + .get_or_create(&Labels { + path: format!("/path/{}", i), + method: Method::Get, + some_number: j.into(), + }) + .inc(); + + histogram_family + .get_or_create(&Labels { + path: format!("/path/{}", i), + method: Method::Get, + some_number: j.into(), + }) + .observe(j.into()); + } + } + + b.iter(|| { + let metric_set = encode(®istry); + black_box(metric_set); + }) + }); +} + +criterion_group!(benches, proto); +criterion_main!(benches); From 5af3aff7f2f467860b52789afb1db727d76eed8d Mon Sep 17 00:00:00 2001 From: ackintosh Date: Sat, 13 Aug 2022 11:19:22 +0900 Subject: [PATCH 65/76] Add a test for Family, Counter and Histogram Signed-off-by: ackintosh --- src/encoding/proto.rs | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 0d801e96..7fbd28af 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -833,6 +833,53 @@ mod tests { assert_eq!("my_histogram", metric_set.metric_families[1].name); } + #[test] + fn encode_family_and_counter_and_histogram() { + let mut registry = Registry::< + Box>>>, + >::default(); + + // Family + let counter_family = Family::, Counter>::default(); + let histogram_family = + Family::, Histogram>::new_with_constructor(|| { + Histogram::new(exponential_buckets(1.0, 2.0, 10)) + }); + + registry.register( + "my_family_counter", + "My counter", + Box::new(counter_family.clone()), + ); + registry.register( + "my_family_histogram", + "My histogram", + Box::new(histogram_family.clone()), + ); + + counter_family + .get_or_create(&vec![("path".to_string(), "/".to_string())]) + .inc(); + + histogram_family + .get_or_create(&vec![("path".to_string(), "/".to_string())]) + .observe(1.0); + + // Counter + let counter: Counter = Counter::default(); + registry.register("my_counter", "My counter", Box::new(counter.clone())); + counter.inc(); + + // Histogram + let histogram = Histogram::new(exponential_buckets(1.0, 2.0, 10)); + registry.register("my_histogram", "My histogram", Box::new(histogram.clone())); + histogram.observe(1.0); + + let metric_set = encode(®istry); + assert_eq!("my_counter", metric_set.metric_families[0].name); + assert_eq!("my_histogram", metric_set.metric_families[1].name); + } + #[test] fn encode_info() { let mut registry = Registry::default(); From 964940751dbea5e8df16d8e5b23226c845994dfe Mon Sep 17 00:00:00 2001 From: ackintosh Date: Mon, 15 Aug 2022 09:23:38 +0900 Subject: [PATCH 66/76] Remove `Box` to reduce allocation count Signed-off-by: ackintosh --- derive-proto-encode/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/derive-proto-encode/src/lib.rs b/derive-proto-encode/src/lib.rs index 0ad0ad98..95e3be84 100644 --- a/derive-proto-encode/src/lib.rs +++ b/derive-proto-encode/src/lib.rs @@ -33,7 +33,7 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { quote! { let mut labels = vec![]; #push_labels - Box::new(labels.into_iter()) + labels.into_iter() } } syn::Fields::Unnamed(_) => { @@ -62,7 +62,7 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { #match_arms }; - Box::new(vec![label].into_iter()) + vec![label].into_iter() } } syn::Data::Union(_) => panic!("Can not derive Encode for union."), @@ -70,7 +70,7 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { let gen = quote! { impl<'a> prometheus_client::encoding::proto::EncodeLabels for &'a #name { - type Iterator = Box + 'a>; + type Iterator = std::vec::IntoIter; fn encode(self) -> Self::Iterator { #body From 680483e2164ccecc95cf51f052366819dd25f01c Mon Sep 17 00:00:00 2001 From: ackintosh Date: Mon, 15 Aug 2022 09:53:03 +0900 Subject: [PATCH 67/76] Use std::iter::Once on enums as enum returns single element Signed-off-by: ackintosh --- benches/encoding/proto.rs | 15 ++++++++----- derive-proto-encode/src/lib.rs | 41 +++++++++++++++++----------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/benches/encoding/proto.rs b/benches/encoding/proto.rs index 81dbc73a..59356687 100644 --- a/benches/encoding/proto.rs +++ b/benches/encoding/proto.rs @@ -34,13 +34,20 @@ pub fn proto(c: &mut Criterion) { } } + #[derive(Clone, Hash, PartialEq, Eq, Encode)] + enum Region { + Africa, + #[allow(dead_code)] + Asia, + } + let mut registry = Registry::< Box>>, >::default(); for i in 0..100 { let counter_family = Family::::default(); - let histogram_family = Family::::new_with_constructor(|| { + let histogram_family = Family::::new_with_constructor(|| { Histogram::new(exponential_buckets(1.0, 2.0, 10)) }); @@ -65,11 +72,7 @@ pub fn proto(c: &mut Criterion) { .inc(); histogram_family - .get_or_create(&Labels { - path: format!("/path/{}", i), - method: Method::Get, - some_number: j.into(), - }) + .get_or_create(&Region::Africa) .observe(j.into()); } } diff --git a/derive-proto-encode/src/lib.rs b/derive-proto-encode/src/lib.rs index 95e3be84..e73c3a30 100644 --- a/derive-proto-encode/src/lib.rs +++ b/derive-proto-encode/src/lib.rs @@ -8,7 +8,7 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { let ast: DeriveInput = syn::parse(input).unwrap(); let name = &ast.ident; - let body: TokenStream2 = match ast.data { + match ast.data { syn::Data::Struct(s) => match s.fields { syn::Fields::Named(syn::FieldsNamed { named, .. }) => { let push_labels: TokenStream2 = named @@ -31,9 +31,15 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { .collect(); quote! { - let mut labels = vec![]; - #push_labels - labels.into_iter() + impl<'a> prometheus_client::encoding::proto::EncodeLabels for &'a #name { + type Iterator = std::vec::IntoIter; + + fn encode(self) -> Self::Iterator { + let mut labels = vec![]; + #push_labels + labels.into_iter() + } + } } } syn::Fields::Unnamed(_) => { @@ -58,26 +64,21 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { .collect(); quote! { - let label = match self { - #match_arms - }; - - vec![label].into_iter() - } - } - syn::Data::Union(_) => panic!("Can not derive Encode for union."), - }; + impl<'a> prometheus_client::encoding::proto::EncodeLabels for &'a #name { + type Iterator = std::iter::Once; - let gen = quote! { - impl<'a> prometheus_client::encoding::proto::EncodeLabels for &'a #name { - type Iterator = std::vec::IntoIter; + fn encode(self) -> Self::Iterator { + let label = match self { + #match_arms + }; - fn encode(self) -> Self::Iterator { - #body + std::iter::once(label) + } + } } } - }; - gen.into() + syn::Data::Union(_) => panic!("Can not derive Encode for union."), + }.into() } // Copied from https://github.com/djc/askama (MIT and APACHE licensed) and From 15ef4e009d84817b94bbef193e0b2602bb30bb79 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Fri, 19 Aug 2022 14:45:32 +0900 Subject: [PATCH 68/76] encoding/proto: Pass metric and label vec Signed-off-by: ackintosh --- src/encoding/proto.rs | 196 +++++++++++++++++++----------------------- 1 file changed, 90 insertions(+), 106 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 7fbd28af..2c345490 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -19,7 +19,7 @@ //! //! let family = metric_set.metric_families.first().unwrap(); //! assert_eq!("my_counter", family.name); -//! assert_eq!("My counter.", family.help); +//! assert_eq!("This is my counter.", family.help); //! ``` // Include the `openmetrics_data_model` module, which is generated from `proto/openmetrics_data_model.proto`. @@ -37,7 +37,6 @@ use crate::metrics::{counter, gauge, MetricType, TypedMetric}; use crate::registry::Registry; use std::collections::HashMap; use std::ops::Deref; -use std::vec::IntoIter; use void::Void; pub use openmetrics_data_model::*; @@ -60,9 +59,9 @@ where family.unit = unit.as_str().to_string(); } family.help = desc.help().to_string(); - family.metrics = metric - .encode(desc.labels().encode().collect::>()) - .collect::>(); + let mut labels = vec![]; + desc.labels().encode(&mut labels); + metric.encode(labels, &mut family.metrics); metric_set.metric_families.push(family); } @@ -84,20 +83,22 @@ impl From for openmetrics_data_model::MetricType { /// Trait implemented by each metric type, e.g. [`Counter`], to implement its encoding. pub trait EncodeMetric { - type Iterator: Iterator; - - fn encode(&self, labels: Vec) -> Self::Iterator; + fn encode( + &self, + labels: Vec, + family: &mut Vec, + ); fn metric_type(&self) -> MetricType; } -impl EncodeMetric - for Box>>> -{ - type Iterator = Box>; - - fn encode(&self, labels: Vec) -> Self::Iterator { - self.deref().encode(labels) +impl EncodeMetric for Box { + fn encode( + &self, + labels: Vec, + family: &mut Vec, + ) { + self.deref().encode(labels, family) } fn metric_type(&self) -> MetricType { @@ -109,22 +110,8 @@ pub trait SendEncodeMetric: EncodeMetric + Send {} impl SendEncodeMetric for T {} -impl EncodeMetric for Box>> { - type Iterator = IntoIter; - - fn encode(&self, labels: Vec) -> Self::Iterator { - self.deref().encode(labels) - } - - fn metric_type(&self) -> MetricType { - self.deref().metric_type() - } -} - pub trait EncodeLabels { - type Iterator: Iterator; - - fn encode(self) -> Self::Iterator; + fn encode(&self, labels: &mut Vec); } impl Into for &(K, V) { @@ -137,45 +124,39 @@ impl Into for &(K, V) { } // TODO: Is this needed? We already have `&'a [T]` below. -impl<'a, T> EncodeLabels for &'a Vec +impl EncodeLabels for Vec where - for<'b> &'b T: Into, + for<'a> &'a T: Into, { - type Iterator = Box + 'a>; - - fn encode(self) -> Self::Iterator { - Box::new(self.iter().map(|t| t.into())) + fn encode(&self, labels: &mut Vec) { + labels.extend(self.iter().map(|t| t.into())) } } - -impl<'a, T> EncodeLabels for &'a [T] +// TODO: Is this needed? We already have `&'a [T]` below. +impl EncodeLabels for [T] where - for<'b> &'b T: Into, + for<'a> &'a T: Into, { - type Iterator = Box + 'a>; - - fn encode(self) -> Self::Iterator { - Box::new(self.iter().map(|t| t.into())) + fn encode(&self, labels: &mut Vec) { + labels.extend(self.iter().map(|t| t.into())) } } -impl<'a> EncodeLabels for &'a Void { - type Iterator = Box>; - - fn encode(self) -> Self::Iterator { - unreachable!() +impl EncodeLabels for Void { + fn encode(&self, _labels: &mut Vec) { + void::unreachable(*self) } } fn encode_exemplar(exemplar: &Exemplar) -> openmetrics_data_model::Exemplar where N: Clone, - for<'a> &'a S: EncodeLabels, + S: EncodeLabels, f64: From, // required because Exemplar.value is defined as `double` in protobuf { let mut exemplar_proto = openmetrics_data_model::Exemplar::default(); exemplar_proto.value = exemplar.value.clone().into(); - exemplar_proto.label = exemplar.label_set.encode().collect::>(); + exemplar.label_set.encode(&mut exemplar_proto.label); exemplar_proto } @@ -204,13 +185,15 @@ where N: EncodeCounterValue, A: counter::Atomic, { - type Iterator = std::iter::Once; - - fn encode(&self, labels: Vec) -> Self::Iterator { + fn encode( + &self, + labels: Vec, + family: &mut Vec, + ) { let mut metric = encode_counter_with_maybe_exemplar(self.get(), None); metric.labels = labels; - std::iter::once(metric) + family.push(metric); } fn metric_type(&self) -> MetricType { @@ -220,14 +203,16 @@ where impl<'a, S, N, A> EncodeMetric for CounterWithExemplar where - for<'b> &'b S: EncodeLabels, + S: EncodeLabels, N: Clone + EncodeCounterValue, A: counter::Atomic, f64: From, { - type Iterator = std::iter::Once; - - fn encode(&self, labels: Vec) -> Self::Iterator { + fn encode( + &self, + labels: Vec, + family: &mut Vec, + ) { let (value, exemplar) = self.get(); let exemplar_proto = if let Some(e) = exemplar.as_ref() { @@ -239,7 +224,7 @@ where let mut metric = encode_counter_with_maybe_exemplar(value.clone(), exemplar_proto); metric.labels = labels; - std::iter::once(metric) + family.push(metric); } fn metric_type(&self) -> MetricType { @@ -305,9 +290,11 @@ where N: EncodeGaugeValue, A: gauge::Atomic, { - type Iterator = std::iter::Once; - - fn encode(&self, labels: Vec) -> Self::Iterator { + fn encode( + &self, + labels: Vec, + family: &mut Vec, + ) { let mut metric = openmetrics_data_model::Metric::default(); metric.metric_points = { @@ -325,7 +312,8 @@ where }; metric.labels = labels; - std::iter::once(metric) + + family.push(metric) } fn metric_type(&self) -> MetricType { @@ -338,28 +326,20 @@ where impl EncodeMetric for Family where - S: Clone + std::hash::Hash + Eq, - for<'b> &'b S: EncodeLabels, + S: EncodeLabels + Clone + std::hash::Hash + Eq, M: EncodeMetric + TypedMetric, C: MetricConstructor, { - type Iterator = IntoIter; - - fn encode(&self, labels: Vec) -> Self::Iterator { - self.read() - .iter() - .map(|(label_set, metric)| { - let mut labels = labels.clone(); - labels.extend(label_set.encode()); - metric.encode(labels) - }) - .flatten() - // TODO: Ideally we would not have to collect into a vector here, - // though we have to as we borrow from the `MutexGuard`. Once - // https://github.com/prometheus/client_rust/pull/78/ merged, we - // might be able to leverage `MutexGuard::map`. - .collect::>() - .into_iter() + fn encode( + &self, + labels: Vec, + family: &mut Vec, + ) { + for (label_set, metric) in self.read().iter() { + let mut labels = labels.clone(); + label_set.encode(&mut labels); + metric.encode(labels, family) + } } fn metric_type(&self) -> MetricType { @@ -371,14 +351,17 @@ where // Histogram impl EncodeMetric for Histogram { - type Iterator = std::iter::Once; - - fn encode(&self, labels: Vec) -> Self::Iterator { + fn encode( + &self, + labels: Vec, + family: &mut Vec, + ) { let (sum, count, buckets) = self.get(); // TODO: Would be better to use never type instead of `Void`. let mut metric = encode_histogram_with_maybe_exemplars::(sum, count, &buckets, None); metric.labels = labels; - std::iter::once(metric) + + family.push(metric) } fn metric_type(&self) -> MetricType { @@ -388,17 +371,20 @@ impl EncodeMetric for Histogram { impl EncodeMetric for HistogramWithExemplars where - for<'b> &'b S: EncodeLabels, + S: EncodeLabels, { - type Iterator = std::iter::Once; - - fn encode(&self, labels: Vec) -> Self::Iterator { + fn encode( + &self, + labels: Vec, + family: &mut Vec, + ) { let inner = self.inner(); let (sum, count, buckets) = inner.histogram.get(); let mut metric = encode_histogram_with_maybe_exemplars(sum, count, &buckets, Some(&inner.exemplars)); metric.labels = labels; - std::iter::once(metric) + + family.push(metric) } fn metric_type(&self) -> MetricType { @@ -413,7 +399,7 @@ fn encode_histogram_with_maybe_exemplars<'a, S>( exemplars: Option<&'a HashMap>>, ) -> openmetrics_data_model::Metric where - for<'b> &'b S: EncodeLabels, + S: EncodeLabels, { let mut metric = openmetrics_data_model::Metric::default(); @@ -454,17 +440,19 @@ where impl EncodeMetric for Info where - for<'b> &'b S: EncodeLabels, + S: EncodeLabels, { - type Iterator = std::iter::Once; - - fn encode(&self, mut labels: Vec) -> Self::Iterator { + fn encode( + &self, + mut labels: Vec, + family: &mut Vec, + ) { let mut metric = openmetrics_data_model::Metric::default(); metric.metric_points = { let mut metric_point = openmetrics_data_model::MetricPoint::default(); metric_point.value = { - labels.extend(self.0.encode()); + self.0.encode(&mut labels); let mut info_value = openmetrics_data_model::InfoValue::default(); info_value.info = labels; @@ -477,7 +465,7 @@ where vec![metric_point] }; - std::iter::once(metric) + family.push(metric); } fn metric_type(&self) -> MetricType { @@ -803,9 +791,7 @@ mod tests { #[test] fn encode_family_counter_histogram() { - let mut registry = Registry::< - Box>>, - >::default(); + let mut registry = Registry::>::default(); let counter_family = Family::, Counter>::default(); let histogram_family = @@ -835,9 +821,7 @@ mod tests { #[test] fn encode_family_and_counter_and_histogram() { - let mut registry = Registry::< - Box>>>, - >::default(); + let mut registry = Registry::>::default(); // Family let counter_family = Family::, Counter>::default(); @@ -876,8 +860,8 @@ mod tests { histogram.observe(1.0); let metric_set = encode(®istry); - assert_eq!("my_counter", metric_set.metric_families[0].name); - assert_eq!("my_histogram", metric_set.metric_families[1].name); + assert_eq!("my_family_counter", metric_set.metric_families[0].name); + assert_eq!("my_family_histogram", metric_set.metric_families[1].name); } #[test] From 182d7b00838fd468d4cb574b4aca5700d5931cdd Mon Sep 17 00:00:00 2001 From: ackintosh Date: Tue, 23 Aug 2022 14:38:00 +0900 Subject: [PATCH 69/76] derive-proto-encode: Update according to the changes in encoding/proto Signed-off-by: ackintosh --- derive-proto-encode/src/lib.rs | 20 ++++++-------------- derive-proto-encode/tests/lib.rs | 4 +++- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/derive-proto-encode/src/lib.rs b/derive-proto-encode/src/lib.rs index e73c3a30..90b33c00 100644 --- a/derive-proto-encode/src/lib.rs +++ b/derive-proto-encode/src/lib.rs @@ -31,13 +31,9 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { .collect(); quote! { - impl<'a> prometheus_client::encoding::proto::EncodeLabels for &'a #name { - type Iterator = std::vec::IntoIter; - - fn encode(self) -> Self::Iterator { - let mut labels = vec![]; + impl prometheus_client::encoding::proto::EncodeLabels for #name { + fn encode(&self, labels: &mut Vec) { #push_labels - labels.into_iter() } } } @@ -57,22 +53,18 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { let mut label = prometheus_client::encoding::proto::Label::default(); label.name = stringify!(#name).to_string(); label.value = stringify!(#ident).to_string(); - label + labels.push(label); } } }) .collect(); quote! { - impl<'a> prometheus_client::encoding::proto::EncodeLabels for &'a #name { - type Iterator = std::iter::Once; - - fn encode(self) -> Self::Iterator { - let label = match self { + impl prometheus_client::encoding::proto::EncodeLabels for #name { + fn encode(&self, labels: &mut Vec) { + match self { #match_arms }; - - std::iter::once(label) } } } diff --git a/derive-proto-encode/tests/lib.rs b/derive-proto-encode/tests/lib.rs index de18b4ab..e8c09445 100644 --- a/derive-proto-encode/tests/lib.rs +++ b/derive-proto-encode/tests/lib.rs @@ -96,7 +96,9 @@ fn remap_keyword_identifiers() { r#type: u64, } - let labels = Labels { r#type: 42 }.encode().collect::>(); + let mut labels = vec![]; + + Labels { r#type: 42 }.encode(&mut labels); assert_eq!("type", labels[0].name); assert_eq!("42", labels[0].value); From 038fc2a6544df8ba4bff04ff1e221c109f235bc0 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 16 Aug 2022 05:18:52 +0200 Subject: [PATCH 70/76] *: Move to `parking_lot` and thus make `owning_ref` obsolete (#78) Before `proemtheus-client` would use the `owning_ref` crate to map the target of a `std::sync::RwLockReadGuard`. `owning_ref` has multiple unsoundness issues, see https://rustsec.org/advisories/RUSTSEC-2022-0040.html. Instead of replacing `owning_ref` with a similar crate, we switch to locking via `parking_lot` which supports the above mapping natively. Signed-off-by: Max Inden --- CHANGELOG.md | 12 ++++++++++++ Cargo.toml | 4 ++-- src/encoding/text.rs | 2 +- src/metrics/exemplar.rs | 24 ++++++++++-------------- src/metrics/family.rs | 16 +++++++--------- src/metrics/histogram.rs | 18 ++++++++---------- 6 files changed, 40 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d881544c..1fb69ffc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ 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.18.0] - unreleased + +### Changed + +- Use `parking_lot` instead of `std::sync::*`. + + Before `proemtheus-client` would use the `owning_ref` crate to map the target + of a `std::sync::RwLockReadGuard`. `owning_ref` has multiple unsoundness + issues, see https://rustsec.org/advisories/RUSTSEC-2022-0040.html. Instead of + replacing `owning_ref` with a similar crate, we switch to locking via + `parking_lot` which supports the above mapping natively. + ## [0.17.0] ### Changed diff --git a/Cargo.toml b/Cargo.toml index 7cc00f35..8875fd4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "prometheus-client" -version = "0.17.0" +version = "0.18.0" authors = ["Max Inden "] edition = "2021" description = "Open Metrics client library allowing users to natively instrument applications." @@ -19,7 +19,7 @@ members = ["derive-text-encode", "derive-proto-encode"] [dependencies] dtoa = "1.0" itoa = "1.0" -owning_ref = "0.4" +parking_lot = "0.12" prometheus-client-derive-proto-encode = { version = "0.1.0", path = "derive-proto-encode", optional = true } prometheus-client-derive-text-encode = { version = "0.3.0", path = "derive-text-encode" } prost = { version = "0.9.0", optional = true } diff --git a/src/encoding/text.rs b/src/encoding/text.rs index edb03c1c..c3e774a2 100644 --- a/src/encoding/text.rs +++ b/src/encoding/text.rs @@ -436,7 +436,7 @@ where { fn encode(&self, encoder: Encoder) -> Result<(), std::io::Error> { let (value, exemplar) = self.get(); - encode_counter_with_maybe_exemplar(value, exemplar.as_ref().as_ref(), encoder) + encode_counter_with_maybe_exemplar(value, exemplar.as_ref(), encoder) } fn metric_type(&self) -> MetricType { diff --git a/src/metrics/exemplar.rs b/src/metrics/exemplar.rs index 485712f6..b08fdc39 100644 --- a/src/metrics/exemplar.rs +++ b/src/metrics/exemplar.rs @@ -4,13 +4,13 @@ use super::counter::{self, Counter}; use super::histogram::Histogram; -use owning_ref::OwningRef; +use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard}; use std::collections::HashMap; #[cfg(any(target_arch = "mips", target_arch = "powerpc"))] use std::sync::atomic::AtomicU32; #[cfg(not(any(target_arch = "mips", target_arch = "powerpc")))] use std::sync::atomic::AtomicU64; -use std::sync::{Arc, RwLock, RwLockReadGuard}; +use std::sync::Arc; #[derive(Debug)] pub struct Exemplar { @@ -74,7 +74,7 @@ impl> CounterWithExemplar { /// Increase the [`CounterWithExemplar`] by `v`, updating the [`Exemplar`] /// if a label set is provided, returning the previous value. pub fn inc_by(&self, v: N, label_set: Option) -> N { - let mut inner = self.inner.write().expect("Lock not to be poisoned."); + let mut inner = self.inner.write(); inner.exemplar = label_set.map(|label_set| Exemplar { label_set, @@ -86,10 +86,10 @@ impl> CounterWithExemplar { /// Get the current value of the [`CounterWithExemplar`] as well as its /// [`Exemplar`] if any. - pub fn get(&self) -> (N, RwLockGuardedCounterWithExemplar) { - let inner = self.inner.read().expect("Lock not to be poisoned."); + pub fn get(&self) -> (N, MappedRwLockReadGuard>>) { + let inner = self.inner.read(); let value = inner.counter.get(); - let exemplar = OwningRef::new(inner).map(|inner| &inner.exemplar); + let exemplar = RwLockReadGuard::map(inner, |inner| &inner.exemplar); (value, exemplar) } @@ -101,15 +101,11 @@ impl> CounterWithExemplar { /// The caller of this function has to uphold the property of an Open /// Metrics counter namely that the value is monotonically increasing, i.e. /// either stays the same or increases. - pub fn inner(&self) -> OwningRef>, A> { - OwningRef::new(self.inner.read().expect("Lock not to be poisoned.")) - .map(|inner| inner.counter.inner()) + pub fn inner(&self) -> MappedRwLockReadGuard { + RwLockReadGuard::map(self.inner.read(), |inner| inner.counter.inner()) } } -type RwLockGuardedCounterWithExemplar<'a, S, N, A> = - OwningRef>, Option>>; - ///////////////////////////////////////////////////////////////////////////////// // Histogram @@ -153,7 +149,7 @@ impl HistogramWithExemplars { } pub fn observe(&self, v: f64, label_set: Option) { - let mut inner = self.inner.write().expect("Lock not to be poisoned."); + let mut inner = self.inner.write(); let bucket = inner.histogram.observe_and_bucket(v); if let (Some(bucket), Some(label_set)) = (bucket, label_set) { inner.exemplars.insert( @@ -167,6 +163,6 @@ impl HistogramWithExemplars { } pub(crate) fn inner(&self) -> RwLockReadGuard> { - self.inner.read().expect("Lock not to be poisoned.") + self.inner.read() } } diff --git a/src/metrics/family.rs b/src/metrics/family.rs index be945075..fb5dbeb6 100644 --- a/src/metrics/family.rs +++ b/src/metrics/family.rs @@ -3,9 +3,9 @@ //! See [`Family`] for details. use super::{MetricType, TypedMetric}; -use owning_ref::OwningRef; +use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard}; use std::collections::HashMap; -use std::sync::{Arc, RwLock, RwLockReadGuard}; +use std::sync::Arc; /// Representation of the OpenMetrics *MetricFamily* data type. /// @@ -214,21 +214,19 @@ impl> Family OwningRef>, M> { - let read_guard = self.metrics.read().expect("Lock not to be poisoned."); + pub fn get_or_create(&self, label_set: &S) -> MappedRwLockReadGuard { if let Ok(metric) = - OwningRef::new(read_guard).try_map(|metrics| metrics.get(label_set).ok_or(())) + RwLockReadGuard::try_map(self.metrics.read(), |metrics| metrics.get(label_set)) { return metric; } - let mut write_guard = self.metrics.write().unwrap(); + let mut write_guard = self.metrics.write(); write_guard.insert(label_set.clone(), self.constructor.new_metric()); drop(write_guard); - let read_guard = self.metrics.read().unwrap(); - OwningRef::new(read_guard).map(|metrics| { + RwLockReadGuard::map(self.metrics.read(), |metrics| { metrics .get(label_set) .expect("Metric to exist after creating it.") @@ -236,7 +234,7 @@ impl> Family RwLockReadGuard> { - self.metrics.read().unwrap() + self.metrics.read() } } diff --git a/src/metrics/histogram.rs b/src/metrics/histogram.rs index c025c4e8..e641d768 100644 --- a/src/metrics/histogram.rs +++ b/src/metrics/histogram.rs @@ -3,9 +3,9 @@ //! See [`Histogram`] for details. use super::{MetricType, TypedMetric}; -use owning_ref::OwningRef; +use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard}; use std::iter::{self, once}; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::Arc; /// Open Metrics [`Histogram`] to measure distributions of discrete events. /// @@ -33,7 +33,7 @@ use std::sync::{Arc, Mutex, MutexGuard}; // https://github.com/tikv/rust-prometheus/pull/314. #[derive(Debug)] pub struct Histogram { - inner: Arc>, + inner: Arc>, } impl Clone for Histogram { @@ -56,7 +56,7 @@ pub(crate) struct Inner { impl Histogram { pub fn new(buckets: impl Iterator) -> Self { Self { - inner: Arc::new(Mutex::new(Inner { + inner: Arc::new(RwLock::new(Inner { sum: Default::default(), count: Default::default(), buckets: buckets @@ -78,7 +78,7 @@ impl Histogram { /// Needed in /// [`HistogramWithExemplars`](crate::metrics::exemplar::HistogramWithExemplars). pub(crate) fn observe_and_bucket(&self, v: f64) -> Option { - let mut inner = self.inner.lock().unwrap(); + let mut inner = self.inner.write(); inner.sum += v; inner.count += 1; @@ -97,17 +97,15 @@ impl Histogram { } } - pub(crate) fn get(&self) -> (f64, u64, MutexGuardedBuckets) { - let inner = self.inner.lock().unwrap(); + pub(crate) fn get(&self) -> (f64, u64, MappedRwLockReadGuard>) { + let inner = self.inner.read(); let sum = inner.sum; let count = inner.count; - let buckets = OwningRef::new(inner).map(|inner| &inner.buckets); + let buckets = RwLockReadGuard::map(inner, |inner| &inner.buckets); (sum, count, buckets) } } -pub(crate) type MutexGuardedBuckets<'a> = OwningRef, Vec<(f64, u64)>>; - impl TypedMetric for Histogram { const TYPE: MetricType = MetricType::Histogram; } From c68c4bad956712a38247a54011f15c13b5d0c2b5 Mon Sep 17 00:00:00 2001 From: Max Inden Date: Tue, 16 Aug 2022 05:43:45 +0200 Subject: [PATCH 71/76] CHANGELOG.md: Prepare v0.18.0 (#80) Signed-off-by: ackintosh --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fb69ffc..18229832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ 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.18.0] - unreleased +## [0.18.0] ### Changed @@ -16,6 +16,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 replacing `owning_ref` with a similar crate, we switch to locking via `parking_lot` which supports the above mapping natively. + See [PR 78] and [issue 77]. + +[PR 78]: https://github.com/prometheus/client_rust/pull/78 +[issue 77]: https://github.com/prometheus/client_rust/issues/77 + ## [0.17.0] ### Changed From 59624c569bf475f5193c8f59ac8668e55084b4e6 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Tue, 23 Aug 2022 14:54:34 +0900 Subject: [PATCH 72/76] Cargo.toml: Make `void` optional void is used in only encoding/proto. Signed-off-by: ackintosh --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8875fd4d..3503ed8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ homepage = "https://github.com/prometheus/client_rust" documentation = "https://docs.rs/prometheus-client" [features] -protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build", "dep:prometheus-client-derive-proto-encode"] +protobuf = ["dep:prost", "dep:prost-types", "dep:prost-build", "dep:prometheus-client-derive-proto-encode", "dep:void"] [workspace] members = ["derive-text-encode", "derive-proto-encode"] @@ -24,7 +24,7 @@ prometheus-client-derive-proto-encode = { version = "0.1.0", path = "derive-prot prometheus-client-derive-text-encode = { version = "0.3.0", path = "derive-text-encode" } prost = { version = "0.9.0", optional = true } prost-types = { version = "0.9.0", optional = true } -void = "1.0" +void = { version = "1.0", optional = true } [dev-dependencies] async-std = { version = "1", features = ["attributes"] } From 9c41272e5a3f3aa139f4de79e025a39526c1fa3c Mon Sep 17 00:00:00 2001 From: ackintosh Date: Tue, 23 Aug 2022 14:57:41 +0900 Subject: [PATCH 73/76] benches: Update according to the changes in encoding/proto Signed-off-by: ackintosh --- benches/encoding/proto.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/benches/encoding/proto.rs b/benches/encoding/proto.rs index 59356687..068a4d58 100644 --- a/benches/encoding/proto.rs +++ b/benches/encoding/proto.rs @@ -7,7 +7,6 @@ use prometheus_client::metrics::family::Family; use prometheus_client::metrics::histogram::{exponential_buckets, Histogram}; use prometheus_client::registry::Registry; use std::fmt::{Display, Formatter}; -use std::vec::IntoIter; pub fn proto(c: &mut Criterion) { c.bench_function("encode", |b| { @@ -41,9 +40,7 @@ pub fn proto(c: &mut Criterion) { Asia, } - let mut registry = Registry::< - Box>>, - >::default(); + let mut registry = Registry::>::default(); for i in 0..100 { let counter_family = Family::::default(); From 2d28710bb2db13f2985d1bb295f9178a52c46168 Mon Sep 17 00:00:00 2001 From: ackintosh Date: Tue, 23 Aug 2022 16:14:27 +0900 Subject: [PATCH 74/76] encoding/proto: same implementation to slice Signed-off-by: ackintosh --- src/encoding/proto.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/encoding/proto.rs b/src/encoding/proto.rs index 2c345490..4f9e19ff 100644 --- a/src/encoding/proto.rs +++ b/src/encoding/proto.rs @@ -123,28 +123,27 @@ impl Into for &(K, V) { } } -// TODO: Is this needed? We already have `&'a [T]` below. impl EncodeLabels for Vec where for<'a> &'a T: Into, { fn encode(&self, labels: &mut Vec) { - labels.extend(self.iter().map(|t| t.into())) + self.as_slice().encode(labels); } } -// TODO: Is this needed? We already have `&'a [T]` below. + impl EncodeLabels for [T] where for<'a> &'a T: Into, { fn encode(&self, labels: &mut Vec) { - labels.extend(self.iter().map(|t| t.into())) + labels.extend(self.iter().map(|t| t.into())); } } impl EncodeLabels for Void { fn encode(&self, _labels: &mut Vec) { - void::unreachable(*self) + void::unreachable(*self); } } From 250db460857b5ee1baadb4913ae07413968574bb Mon Sep 17 00:00:00 2001 From: ackintosh Date: Sat, 27 Aug 2022 09:38:01 +0900 Subject: [PATCH 75/76] Bump the crate version and add a changelog entry Signed-off-by: ackintosh --- CHANGELOG.md | 7 +++++++ Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18229832..e81431da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ 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.18.1] - unreleased + +### Added +- Added support for the OpenMetrics protobuf format. See [PR 47] + +[PR 47]: https://github.com/prometheus/client_rust/pull/47 + ## [0.18.0] ### Changed diff --git a/Cargo.toml b/Cargo.toml index 3503ed8c..4aa1ccf8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "prometheus-client" -version = "0.18.0" +version = "0.18.1" authors = ["Max Inden "] edition = "2021" description = "Open Metrics client library allowing users to natively instrument applications." From 33c940a6e7f8d95fbf4479c6e2301f40bff4670c Mon Sep 17 00:00:00 2001 From: ackintosh Date: Sat, 27 Aug 2022 09:51:56 +0900 Subject: [PATCH 76/76] Add --all-features Signed-off-by: ackintosh --- .github/workflows/rust.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7d00d45d..d9fdb9b1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -39,7 +39,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: test - args: --benches + args: --benches --all-features test: name: Test Suite @@ -73,7 +73,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: test - args: --all + args: --all --all-features fmt: name: Rustfmt @@ -135,7 +135,7 @@ jobs: RUSTDOCFLAGS: "--deny broken_intra_doc_links" with: command: doc - args: --verbose --workspace --no-deps --document-private-items + args: --verbose --workspace --no-deps --document-private-items --all-features cross-compile: name: Cross compile @@ -159,4 +159,4 @@ jobs: with: use-cross: true command: build - args: --release --target=${{ matrix.target }} + args: --release --target=${{ matrix.target }} --all-features