diff --git a/metrics-exporter-prometheus/CHANGELOG.md b/metrics-exporter-prometheus/CHANGELOG.md index ca7192e9..88aa1d30 100644 --- a/metrics-exporter-prometheus/CHANGELOG.md +++ b/metrics-exporter-prometheus/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - ReleaseDate +### Added + +- Users can now configure the number of buckets, and bucket widths, for rolling summaries. ([#444](https://github.com/metrics-rs/metrics/pull/444)) + ## [0.13.1] - 2024-02-11 ### Added diff --git a/metrics-exporter-prometheus/src/builder.rs b/metrics-exporter-prometheus/src/builder.rs index 49c22c4f..1877a3c8 100644 --- a/metrics-exporter-prometheus/src/builder.rs +++ b/metrics-exporter-prometheus/src/builder.rs @@ -244,13 +244,25 @@ impl PrometheusBuilder { Ok(self) } - /// Sets the default bucket duration for rolling summaries + /// Sets the bucket width when using summaries. /// - /// Buckets will be cleared after this interval expires + /// Summaries are rolling, which means that they are divided into buckets of a fixed duration + /// (width), and older buckets are dropped as they age out. This means data from a period as + /// large as the width will be dropped at a time. + /// + /// The total amount of data kept for a summary is the number of buckets times the bucket width. + /// For example, a bucket count of 3 and a bucket width of 20 seconds would mean that 60 seconds + /// of data is kept at most, with the oldest 20 second chunk of data being dropped as the + /// summary rolls forward. + /// + /// Use more buckets with a smaller width to roll off smaller amounts of data at a time, or + /// fewer buckets with a larger width to roll it off in larger chunks. + /// + /// Defaults to 20 seconds. /// /// ## Errors /// - /// If `value` less than 1 error will be thrown + /// If the duration given is zero, an error variant will be thrown. pub fn set_bucket_duration(mut self, value: Duration) -> Result { if value.is_zero() { return Err(BuildError::ZeroBucketDuration); @@ -260,9 +272,22 @@ impl PrometheusBuilder { Ok(self) } - /// Sets the default bucket count for rolling summaries + /// Sets the bucket count when using summaries. + /// + /// Summaries are rolling, which means that they are divided into buckets of a fixed duration + /// (width), and older buckets are dropped as they age out. This means data from a period as + /// large as the width will be dropped at a time. /// - /// Count number buckets are created to store summary information + /// The total amount of data kept for a summary is the number of buckets times the bucket width. + /// For example, a bucket count of 3 and a bucket width of 20 seconds would mean that 60 seconds + /// of data is kept at most, with the oldest 20 second chunk of data being dropped as the + /// summary rolls forward. + /// + /// Use more buckets with a smaller width to roll off smaller amounts of data at a time, or + /// fewer buckets with a larger width to roll it off in larger chunks. + /// + /// Defaults to 3. + #[must_use] pub fn set_bucket_count(mut self, count: NonZeroU32) -> Self { self.bucket_count = Some(count); self diff --git a/metrics-exporter-prometheus/src/distribution.rs b/metrics-exporter-prometheus/src/distribution.rs index 83a3b4d1..5a8d0f0b 100644 --- a/metrics-exporter-prometheus/src/distribution.rs +++ b/metrics-exporter-prometheus/src/distribution.rs @@ -8,8 +8,11 @@ use crate::common::Matcher; use metrics_util::{Histogram, Quantile, Summary}; -const DEFAULT_SUMMARY_BUCKET_COUNT: u32 = 3; -const DEFAULT_SUMMARY_BUCKET_DURATION: u64 = 20; +const DEFAULT_SUMMARY_BUCKET_COUNT: NonZeroU32 = match NonZeroU32::new(3) { + Some(v) => v, + None => [][0], +}; +const DEFAULT_SUMMARY_BUCKET_DURATION: Duration = Duration::from_secs(20); /// Distribution type. #[derive(Clone)] @@ -107,11 +110,8 @@ impl DistributionBuilder { return Distribution::new_histogram(buckets); } - 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); + let b_duration = self.bucket_duration.map_or(DEFAULT_SUMMARY_BUCKET_DURATION, |d| d); + let b_count = self.bucket_count.map_or(DEFAULT_SUMMARY_BUCKET_COUNT, |c| c); Distribution::new_summary(self.quantiles.clone(), b_duration, b_count) } @@ -160,10 +160,7 @@ pub struct RollingSummary { impl Default for RollingSummary { fn default() -> Self { - RollingSummary::new( - NonZeroU32::new(DEFAULT_SUMMARY_BUCKET_COUNT).unwrap(), - Duration::from_secs(20), - ) + RollingSummary::new(DEFAULT_SUMMARY_BUCKET_COUNT, DEFAULT_SUMMARY_BUCKET_DURATION) } }