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}