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}