Skip to main content

elfo_core/telemetry/
config.rs

1//! [Config].
2//!
3//! [Config]: TelemetryConfig
4
5use std::fmt;
6
7use regex::Regex;
8use serde::{
9    de::{Deserializer, Error},
10    Deserialize,
11};
12
13/// Telemetry configuration.
14///
15/// # Example
16/// ```toml
17/// [some_group]
18/// system.telemetry.per_actor_group = false
19/// system.teleemtry.per_actor_key = true
20/// ```
21#[derive(Debug, Deserialize)]
22#[serde(default)]
23pub struct TelemetryConfig {
24    /// Whether to enable per-actor-group telemetry.
25    ///
26    /// `true` by default.
27    pub per_actor_group: bool,
28    /// Whether to enable per-actor-key telemetry.
29    ///
30    /// Can be either `true` to produce metrics for all keys
31    /// or regex pattern to combine keys into "groups".
32    ///
33    /// `false` by default.
34    ///
35    /// # Example
36    /// ```toml
37    /// per_actor_key = true # emit metrics keywise
38    /// per_actor_key = [".*:(.*?)", "${1}"] # group keys
39    /// ```
40    pub per_actor_key: PerActorKey,
41}
42
43/// How to produce metrics for actor keys.
44pub enum PerActorKey {
45    /// Produce metrics for all keys.
46    Bool(bool),
47    /// Combine keys into "groups" by pattern.
48    Replacement(Regex, String),
49}
50
51impl fmt::Debug for PerActorKey {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        match self {
54            Self::Bool(flag) => write!(f, "{flag:?}"),
55            Self::Replacement(pattern, template) => f
56                .debug_tuple("")
57                .field(&pattern.as_str())
58                .field(&template)
59                .finish(),
60        }
61    }
62}
63
64impl PerActorKey {
65    pub(crate) fn is_enabled(&self) -> bool {
66        match self {
67            Self::Bool(flag) => *flag,
68            Self::Replacement(_, _) => true,
69        }
70    }
71
72    pub(crate) fn key(&self, actor_key: &str) -> Option<String> {
73        match self {
74            Self::Bool(_) => None,
75            Self::Replacement(pattern, template) => {
76                Some(pattern.replace(actor_key, template).into())
77            }
78        }
79    }
80}
81
82impl<'de> Deserialize<'de> for PerActorKey {
83    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84    where
85        D: Deserializer<'de>,
86    {
87        #[derive(Deserialize)]
88        #[serde(untagged)]
89        enum BoolOrPairOfStrings {
90            Bool(bool),
91            Pair(String, String),
92        }
93
94        Ok(match BoolOrPairOfStrings::deserialize(deserializer)? {
95            BoolOrPairOfStrings::Bool(flag) => PerActorKey::Bool(flag),
96            BoolOrPairOfStrings::Pair(pattern, template) => {
97                let pattern = Regex::new(&pattern).map_err(D::Error::custom)?;
98                PerActorKey::Replacement(pattern, template)
99            }
100        })
101    }
102}
103
104impl Default for TelemetryConfig {
105    fn default() -> Self {
106        Self {
107            per_actor_group: true,
108            per_actor_key: PerActorKey::Bool(false),
109        }
110    }
111}