metrics_runtime/
builder.rs

1use crate::{config::Configuration, Receiver};
2use std::{error::Error, fmt, time::Duration};
3
4/// Errors during receiver creation.
5#[derive(Debug, Clone)]
6pub enum BuilderError {
7    /// Failed to spawn the upkeep thread.
8    ///
9    /// As histograms are windowed, reads and writes require getting the current time so they can
10    /// perform the required maintenance, or upkeep, on the internal structures to roll over old
11    /// buckets, etc.
12    ///
13    /// Acquiring the current time is fast compared to most operations, but is a significant
14    /// portion of the other time it takes to write to a histogram, which limits overall throughput
15    /// under high load.
16    ///
17    /// We spin up a background thread, or the "upkeep thread", which updates a global time source
18    /// that the read and write operations exclusively rely on.  While this source is not as
19    /// up-to-date as the real clock, it is much faster to access.
20    UpkeepFailure,
21
22    #[doc(hidden)]
23    _NonExhaustive,
24}
25
26impl Error for BuilderError {}
27
28impl fmt::Display for BuilderError {
29    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30        match self {
31            BuilderError::UpkeepFailure => write!(f, "failed to spawn quanta upkeep thread"),
32            BuilderError::_NonExhaustive => write!(f, "non-exhaustive matching"),
33        }
34    }
35}
36
37/// Builder for [`Receiver`].
38#[derive(Clone)]
39pub struct Builder {
40    pub(crate) histogram_window: Duration,
41    pub(crate) histogram_granularity: Duration,
42    pub(crate) upkeep_interval: Duration,
43}
44
45impl Default for Builder {
46    fn default() -> Self {
47        Self {
48            histogram_window: Duration::from_secs(10),
49            histogram_granularity: Duration::from_secs(1),
50            upkeep_interval: Duration::from_millis(50),
51        }
52    }
53}
54
55impl Builder {
56    /// Creates a new [`Builder`] with default values.
57    pub fn new() -> Self {
58        Default::default()
59    }
60
61    /// Sets the histogram configuration.
62    ///
63    /// Defaults to a 10 second window with 1 second granularity.
64    ///
65    /// This controls both how long of a time window we track histogram data for, and the
66    /// granularity in which we roll off old data.
67    ///
68    /// As an example, with the default values, we would keep the last 10 seconds worth of
69    /// histogram data, and would remove 1 seconds worth of data at a time as the window rolled
70    /// forward.
71    pub fn histogram(mut self, window: Duration, granularity: Duration) -> Self {
72        self.histogram_window = window;
73        self.histogram_granularity = granularity;
74        self
75    }
76
77    /// Sets the upkeep interval.
78    ///
79    /// Defaults to 50 milliseconds.
80    ///
81    /// This controls how often the time source, used internally by histograms, is updated with the
82    /// real time.  For performance reasons, histograms use a sampled time source when they perform
83    /// checks to see if internal maintenance needs to occur.  If the histogram granularity is set
84    /// very low, then this interval might need to be similarly reduced to make sure we're able to
85    /// update the time more often than histograms need to perform upkeep.
86    pub fn upkeep_interval(mut self, interval: Duration) -> Self {
87        self.upkeep_interval = interval;
88        self
89    }
90
91    /// Create a [`Receiver`] based on this configuration.
92    pub fn build(self) -> Result<Receiver, BuilderError> {
93        let config = Configuration::from_builder(&self);
94        Receiver::from_config(config)
95    }
96}