Skip to main content

kaizen/telemetry/
resolve.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2//! Env + TOML resolution for third-party keys (see `TelemetryConfig`).
3
4use crate::core::config::ExporterConfig;
5
6const KAIZEN: &str = "KAIZEN_";
7
8/// Resolve env, preferring standard names, then `KAIZEN_` + same suffix.
9pub(crate) fn env_two(std_key: &str, kaizen_key: &str) -> Option<String> {
10    std::env::var(std_key)
11        .ok()
12        .filter(|s| !s.is_empty())
13        .or_else(|| std::env::var(kaizen_key).ok().filter(|s| !s.is_empty()))
14}
15
16/// Effective PostHog settings after env overlay.
17pub struct PostHogResolved {
18    pub host: String,
19    pub project_api_key: String,
20}
21
22/// Effective Datadog settings after env overlay.
23pub struct DatadogResolved {
24    pub site: String,
25    pub api_key: String,
26}
27
28/// Effective OTLP push endpoint.
29pub struct OtlpResolved {
30    pub endpoint: String,
31}
32
33impl PostHogResolved {
34    pub fn from_config(c: &ExporterConfig) -> Option<Self> {
35        let (host, key_opt) = match c {
36            ExporterConfig::PostHog {
37                host,
38                project_api_key,
39                ..
40            } => (host.as_deref(), project_api_key.as_deref()),
41            _ => return None,
42        };
43        let project_api_key = key_opt
44            .map(String::from)
45            .or_else(|| env_two("POSTHOG_API_KEY", "KAIZEN_POSTHOG_API_KEY"))?;
46        let host = host
47            .map(String::from)
48            .or_else(|| env_two("POSTHOG_HOST", "KAIZEN_POSTHOG_HOST"))
49            .unwrap_or_else(|| "https://us.i.posthog.com".to_string());
50        Some(Self {
51            host,
52            project_api_key,
53        })
54    }
55
56    /// Query / pull: API key and host from env only (no TOML row required).
57    pub fn from_env_only() -> Option<Self> {
58        let project_api_key = env_two("POSTHOG_API_KEY", "KAIZEN_POSTHOG_API_KEY")?;
59        let host = env_two("POSTHOG_HOST", "KAIZEN_POSTHOG_HOST")
60            .unwrap_or_else(|| "https://us.i.posthog.com".to_string());
61        Some(Self {
62            host,
63            project_api_key,
64        })
65    }
66}
67
68impl DatadogResolved {
69    pub fn from_config(c: &ExporterConfig) -> Option<Self> {
70        let (site, key_opt) = match c {
71            ExporterConfig::Datadog { site, api_key, .. } => (site.as_deref(), api_key.as_deref()),
72            _ => return None,
73        };
74        let api_key = key_opt
75            .map(String::from)
76            .or_else(|| env_two("DD_API_KEY", "KAIZEN_DD_API_KEY"))?;
77        let site = site
78            .map(String::from)
79            .or_else(|| env_two("DD_SITE", "KAIZEN_DD_SITE"))
80            .unwrap_or_else(|| "datadoghq.com".to_string());
81        Some(Self { site, api_key })
82    }
83
84    /// Query / pull: API key and site from env only.
85    pub fn from_env_only() -> Option<Self> {
86        let api_key = env_two("DD_API_KEY", "KAIZEN_DD_API_KEY")?;
87        let site =
88            env_two("DD_SITE", "KAIZEN_DD_SITE").unwrap_or_else(|| "datadoghq.com".to_string());
89        Some(Self { site, api_key })
90    }
91}
92
93impl OtlpResolved {
94    pub fn from_config(c: &ExporterConfig) -> Option<Self> {
95        let ep = match c {
96            ExporterConfig::Otlp { endpoint, .. } => endpoint.as_deref(),
97            _ => return None,
98        };
99        let endpoint = ep.map(String::from).or_else(|| {
100            env_two(
101                "OTEL_EXPORTER_OTLP_ENDPOINT",
102                "KAIZEN_OTEL_EXPORTER_OTLP_ENDPOINT",
103            )
104        })?;
105        Some(Self { endpoint })
106    }
107}
108
109/// Prevent unused `KAIZEN` const noise if we add more keys later; keeps resolution discoverable in docs.
110#[allow(dead_code)]
111fn _kaizen_prefix() -> &'static str {
112    KAIZEN
113}