Skip to main content

elfo_telemeter/
config.rs

1//! Configuration for the telemeter.
2//!
3//! Note: all types here are exported only for documentation purposes
4//! and are not subject to stable guarantees. However, the config
5//! structure (usually encoded in TOML) follows stable guarantees.
6
7use std::{net::SocketAddr, ops::Deref, time::Duration};
8
9use serde::Deserialize;
10
11/// Telemeter configuration.
12///
13/// # Example
14/// ```toml
15/// [system.telemeters]
16/// sink = "OpenMetrics"
17/// listen = "0.0.0.0:9042"
18/// ```
19#[derive(Debug, Deserialize)]
20pub struct Config {
21    /// The sink's type.
22    pub sink: Sink,
23    /// The address to expose for scraping.
24    #[serde(alias = "address")]
25    pub listen: SocketAddr,
26    /// How long samples should be considered in summaries.
27    #[serde(default)]
28    pub retention: Retention,
29    /// Quantiles to use for aggregating distribution metrics into a summary.
30    ///
31    /// The default quantiles are `[0.75, 0.9, 0.95, 0.99]`.
32    #[serde(default = "default_quantiles")]
33    pub quantiles: Vec<Quantile>,
34    /// Labels that will be added to all metrics.
35    #[serde(default)]
36    pub global_labels: Vec<(String, String)>,
37    /// The maximum time between compaction ticks.
38    ///
39    /// `1.1s` by default.
40    #[serde(with = "humantime_serde", default = "default_compaction_interval")]
41    pub compaction_interval: Duration,
42}
43
44/// Sink for the telemeter output.
45#[derive(Debug, PartialEq, Deserialize)]
46pub enum Sink {
47    /// Expose metrics in the OpenMetrics/Prometheus format.
48    #[serde(alias = "Prometheus")]
49    OpenMetrics,
50}
51
52/// Histogram/summary retention policy.
53#[derive(Debug, PartialEq, Deserialize, Default)]
54pub enum Retention {
55    /// Keep all samples forever.
56    Forever,
57    /// Reset all samples on each scrape.
58    #[default]
59    ResetOnScrape,
60    // TODO: `SlidingWindow`
61}
62
63/// A quantile to use for aggregating distribution metrics into a summary
64/// with the `quantile` label. Must be in the range [0.0, 1.0].
65#[derive(Debug, Clone, Copy, Deserialize)]
66#[serde(try_from = "f64")]
67pub struct Quantile(f64);
68
69impl Deref for Quantile {
70    type Target = f64;
71
72    fn deref(&self) -> &Self::Target {
73        &self.0
74    }
75}
76
77impl TryFrom<f64> for Quantile {
78    type Error = String;
79
80    fn try_from(value: f64) -> Result<Self, Self::Error> {
81        (0.0..=1.0)
82            .contains(&value)
83            .then_some(Self(value))
84            .ok_or_else(|| format!("invalid quantile {value}, must be in the range [0.0, 1.0]"))
85    }
86}
87
88fn default_quantiles() -> Vec<Quantile> {
89    [0.75, 0.9, 0.95, 0.99].into_iter().map(Quantile).collect()
90}
91
92fn default_compaction_interval() -> Duration {
93    // 1m, 30s, 15s, 10s are often used values of prometheus's `scrape_interval`.
94    // 1.1s is a good value that splits the scrape interval uniformly enough.
95    Duration::from_millis(1100)
96}