Skip to main content

greentic_deployer/
telemetry.rs

1use std::collections::HashMap;
2
3use greentic_config_types::{TelemetryConfig as ResolvedTelemetryConfig, TelemetryExporterKind};
4use greentic_telemetry::{
5    TelemetryConfig,
6    export::{ExportConfig, ExportMode, Sampling},
7    init_telemetry_from_config,
8};
9
10use crate::config::DeployerConfig;
11use crate::error::{DeployerError, Result};
12
13pub fn init(config: &DeployerConfig) -> Result<()> {
14    let telemetry_cfg = config.telemetry_config();
15    if !telemetry_cfg.enabled || matches!(telemetry_cfg.exporter, TelemetryExporterKind::None) {
16        return Ok(());
17    }
18
19    let export = export_from_config(telemetry_cfg);
20    let cfg = TelemetryConfig {
21        service_name: format!("greentic-deployer-{}", config.provider.as_str()),
22    };
23
24    init_telemetry_from_config(cfg, export).map_err(|err| DeployerError::Telemetry(err.to_string()))
25}
26
27fn export_from_config(cfg: &ResolvedTelemetryConfig) -> ExportConfig {
28    let sampling = Sampling::TraceIdRatio(cfg.sampling as f64);
29
30    let mut export = ExportConfig::json_default();
31    export.sampling = sampling;
32
33    match cfg.exporter {
34        TelemetryExporterKind::Stdout => export,
35        TelemetryExporterKind::Otlp => {
36            export.mode = ExportMode::OtlpGrpc;
37            export.endpoint = cfg
38                .endpoint
39                .clone()
40                .or_else(|| std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").ok())
41                .or_else(|| Some("https://otel.greentic.ai".to_string()));
42            export.headers = HashMap::new();
43            export.compression = None;
44            export
45        }
46        TelemetryExporterKind::Gcp => {
47            export.mode = ExportMode::GcpCloudTrace;
48            export.endpoint = cfg.endpoint.clone();
49            export
50        }
51        TelemetryExporterKind::Azure => {
52            export.mode = ExportMode::AzureAppInsights;
53            export.endpoint = cfg.endpoint.clone();
54            export
55        }
56        TelemetryExporterKind::Aws => {
57            export.mode = ExportMode::AwsXRay;
58            export.endpoint = cfg.endpoint.clone();
59            export
60        }
61        TelemetryExporterKind::None => ExportConfig::json_default(),
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    fn base_config(exporter: TelemetryExporterKind) -> ResolvedTelemetryConfig {
70        ResolvedTelemetryConfig {
71            enabled: true,
72            exporter,
73            endpoint: Some("https://otel.test".to_string()),
74            sampling: 0.5,
75        }
76    }
77
78    #[test]
79    fn stdout_uses_json_export() {
80        let export = export_from_config(&base_config(TelemetryExporterKind::Stdout));
81        assert!(matches!(export.mode, ExportMode::JsonStdout));
82        assert!(
83            matches!(export.sampling, Sampling::TraceIdRatio(v) if (v - 0.5).abs() < f64::EPSILON)
84        );
85    }
86
87    #[test]
88    fn otlp_prefers_config_endpoint() {
89        let export = export_from_config(&base_config(TelemetryExporterKind::Otlp));
90        assert!(matches!(export.mode, ExportMode::OtlpGrpc));
91        assert_eq!(export.endpoint.as_deref(), Some("https://otel.test"));
92    }
93
94    #[test]
95    fn cloud_exporters_use_cloud_modes() {
96        let gcp = export_from_config(&base_config(TelemetryExporterKind::Gcp));
97        assert!(matches!(gcp.mode, ExportMode::GcpCloudTrace));
98        assert_eq!(gcp.endpoint.as_deref(), Some("https://otel.test"));
99
100        let azure = export_from_config(&base_config(TelemetryExporterKind::Azure));
101        assert!(matches!(azure.mode, ExportMode::AzureAppInsights));
102        assert_eq!(azure.endpoint.as_deref(), Some("https://otel.test"));
103
104        let aws = export_from_config(&base_config(TelemetryExporterKind::Aws));
105        assert!(matches!(aws.mode, ExportMode::AwsXRay));
106        assert_eq!(aws.endpoint.as_deref(), Some("https://otel.test"));
107    }
108}