From 2085cb1002c10b16a4ff0d7844869def08f6cdec Mon Sep 17 00:00:00 2001 From: Christopher Parratto Date: Tue, 30 Jan 2024 16:26:28 -0600 Subject: [PATCH 1/2] Adds bucket duration as configurable element for setting rolling summaries. cleanup --- metrics-exporter-prometheus/src/builder.rs | 19 +++++++++++++++++++ metrics-exporter-prometheus/src/common.rs | 4 ++++ .../src/distribution.rs | 15 ++++++++++++--- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/metrics-exporter-prometheus/src/builder.rs b/metrics-exporter-prometheus/src/builder.rs index 6d02bb4a..ef02b8c5 100644 --- a/metrics-exporter-prometheus/src/builder.rs +++ b/metrics-exporter-prometheus/src/builder.rs @@ -96,6 +96,7 @@ pub struct PrometheusBuilder { #[cfg(feature = "http-listener")] allowed_addresses: Option>, quantiles: Vec, + bucket_duration: Option, buckets: Option>, bucket_overrides: Option>>, idle_timeout: Option, @@ -120,6 +121,7 @@ impl PrometheusBuilder { #[cfg(feature = "http-listener")] allowed_addresses: None, quantiles, + bucket_duration: None, buckets: None, bucket_overrides: None, idle_timeout: None, @@ -239,6 +241,22 @@ impl PrometheusBuilder { Ok(self) } + /// Sets the default bucket duration for rolling summaries + /// + /// Buckets will be cleared after this interval expires + /// + /// ## Errors + /// + /// If `value` less than 1 error will be thrown + pub fn set_bucket_duration(mut self, value: Duration) -> Result { + if value.is_zero() { + return Err(BuildError::ZeroBucketDuration); + } + + self.bucket_duration = Some(value); + Ok(self) + } + /// Sets the buckets to use when rendering histograms. /// /// Buckets values represent the higher bound of each buckets. If buckets are set, then all @@ -536,6 +554,7 @@ impl PrometheusBuilder { distributions: RwLock::new(HashMap::new()), distribution_builder: DistributionBuilder::new( self.quantiles, + self.bucket_duration, self.buckets, self.bucket_overrides, ), diff --git a/metrics-exporter-prometheus/src/common.rs b/metrics-exporter-prometheus/src/common.rs index b61873fb..94ff6ab6 100644 --- a/metrics-exporter-prometheus/src/common.rs +++ b/metrics-exporter-prometheus/src/common.rs @@ -74,6 +74,10 @@ pub enum BuildError { /// Bucket bounds or quantiles were empty. #[error("bucket bounds/quantiles cannot be empty")] EmptyBucketsOrQuantiles, + + /// Bucket duration cannot be zero + #[error("bucket durations cannot be set to zero")] + ZeroBucketDuration, } pub struct Snapshot { diff --git a/metrics-exporter-prometheus/src/distribution.rs b/metrics-exporter-prometheus/src/distribution.rs index 24475d82..476014ce 100644 --- a/metrics-exporter-prometheus/src/distribution.rs +++ b/metrics-exporter-prometheus/src/distribution.rs @@ -34,8 +34,14 @@ impl Distribution { } /// Creates a summary distribution. - pub fn new_summary(quantiles: Arc>) -> Distribution { - let summary = RollingSummary::default(); + pub fn new_summary( + quantiles: Arc>, + bucket_duration: Option, + ) -> Distribution { + let summary = bucket_duration.map_or( + RollingSummary::new(NonZeroU32::new(3).unwrap(), Duration::from_secs(20)), + |duration| RollingSummary::new(NonZeroU32::new(3).unwrap(), duration), + ); Distribution::Summary(summary, quantiles, 0.0) } @@ -60,6 +66,7 @@ impl Distribution { pub struct DistributionBuilder { quantiles: Arc>, buckets: Option>, + bucket_duration: Option, bucket_overrides: Option)>>, } @@ -67,11 +74,13 @@ impl DistributionBuilder { /// Creates a new instance of `DistributionBuilder`. pub fn new( quantiles: Vec, + bucket_duration: Option, buckets: Option>, bucket_overrides: Option>>, ) -> DistributionBuilder { DistributionBuilder { quantiles: Arc::new(quantiles), + bucket_duration, buckets, bucket_overrides: bucket_overrides.map(|entries| { let mut matchers = entries.into_iter().collect::>(); @@ -95,7 +104,7 @@ impl DistributionBuilder { return Distribution::new_histogram(buckets); } - Distribution::new_summary(self.quantiles.clone()) + Distribution::new_summary(self.quantiles.clone(), self.bucket_duration) } /// Returns the distribution type for the given metric key. From e869445e9b9ea45aaa921accec957f55c00166d6 Mon Sep 17 00:00:00 2001 From: Christopher Parratto Date: Wed, 14 Feb 2024 11:10:23 -0600 Subject: [PATCH 2/2] Adds prometheus builder support for specifying bucket count and duration. --- metrics-exporter-prometheus/src/builder.rs | 12 ++++++++ .../src/distribution.rs | 28 +++++++++++++------ 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/metrics-exporter-prometheus/src/builder.rs b/metrics-exporter-prometheus/src/builder.rs index ef02b8c5..49c22c4f 100644 --- a/metrics-exporter-prometheus/src/builder.rs +++ b/metrics-exporter-prometheus/src/builder.rs @@ -5,6 +5,7 @@ use std::convert::TryFrom; use std::future::Future; #[cfg(feature = "http-listener")] use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::num::NonZeroU32; #[cfg(any(feature = "http-listener", feature = "push-gateway"))] use std::pin::Pin; use std::sync::RwLock; @@ -97,6 +98,7 @@ pub struct PrometheusBuilder { allowed_addresses: Option>, quantiles: Vec, bucket_duration: Option, + bucket_count: Option, buckets: Option>, bucket_overrides: Option>>, idle_timeout: Option, @@ -122,6 +124,7 @@ impl PrometheusBuilder { allowed_addresses: None, quantiles, bucket_duration: None, + bucket_count: None, buckets: None, bucket_overrides: None, idle_timeout: None, @@ -257,6 +260,14 @@ impl PrometheusBuilder { Ok(self) } + /// Sets the default bucket count for rolling summaries + /// + /// Count number buckets are created to store summary information + pub fn set_bucket_count(mut self, count: NonZeroU32) -> Self { + self.bucket_count = Some(count); + self + } + /// Sets the buckets to use when rendering histograms. /// /// Buckets values represent the higher bound of each buckets. If buckets are set, then all @@ -556,6 +567,7 @@ impl PrometheusBuilder { self.quantiles, self.bucket_duration, self.buckets, + self.bucket_count, self.bucket_overrides, ), descriptions: RwLock::new(HashMap::new()), diff --git a/metrics-exporter-prometheus/src/distribution.rs b/metrics-exporter-prometheus/src/distribution.rs index 476014ce..83a3b4d1 100644 --- a/metrics-exporter-prometheus/src/distribution.rs +++ b/metrics-exporter-prometheus/src/distribution.rs @@ -8,6 +8,9 @@ use crate::common::Matcher; use metrics_util::{Histogram, Quantile, Summary}; +const DEFAULT_SUMMARY_BUCKET_COUNT: u32 = 3; +const DEFAULT_SUMMARY_BUCKET_DURATION: u64 = 20; + /// Distribution type. #[derive(Clone)] pub enum Distribution { @@ -36,13 +39,10 @@ impl Distribution { /// Creates a summary distribution. pub fn new_summary( quantiles: Arc>, - bucket_duration: Option, + bucket_duration: Duration, + bucket_count: NonZeroU32, ) -> Distribution { - let summary = bucket_duration.map_or( - RollingSummary::new(NonZeroU32::new(3).unwrap(), Duration::from_secs(20)), - |duration| RollingSummary::new(NonZeroU32::new(3).unwrap(), duration), - ); - Distribution::Summary(summary, quantiles, 0.0) + Distribution::Summary(RollingSummary::new(bucket_count, bucket_duration), quantiles, 0.0) } /// Records the given `samples` in the current distribution. @@ -67,6 +67,7 @@ pub struct DistributionBuilder { quantiles: Arc>, buckets: Option>, bucket_duration: Option, + bucket_count: Option, bucket_overrides: Option)>>, } @@ -76,12 +77,14 @@ impl DistributionBuilder { quantiles: Vec, bucket_duration: Option, buckets: Option>, + bucket_count: Option, bucket_overrides: Option>>, ) -> DistributionBuilder { DistributionBuilder { quantiles: Arc::new(quantiles), bucket_duration, buckets, + bucket_count, bucket_overrides: bucket_overrides.map(|entries| { let mut matchers = entries.into_iter().collect::>(); matchers.sort_by(|a, b| a.0.cmp(&b.0)); @@ -104,7 +107,13 @@ impl DistributionBuilder { return Distribution::new_histogram(buckets); } - Distribution::new_summary(self.quantiles.clone(), self.bucket_duration) + let b_duration = self + .bucket_duration + .map_or(Duration::from_secs(DEFAULT_SUMMARY_BUCKET_DURATION), |d| d); + let b_count = + self.bucket_count.map_or(NonZeroU32::new(DEFAULT_SUMMARY_BUCKET_COUNT).unwrap(), |c| c); + + Distribution::new_summary(self.quantiles.clone(), b_duration, b_count) } /// Returns the distribution type for the given metric key. @@ -151,7 +160,10 @@ pub struct RollingSummary { impl Default for RollingSummary { fn default() -> Self { - RollingSummary::new(NonZeroU32::new(3).unwrap(), Duration::from_secs(20)) + RollingSummary::new( + NonZeroU32::new(DEFAULT_SUMMARY_BUCKET_COUNT).unwrap(), + Duration::from_secs(20), + ) } }