Skip to main content

spin_telemetry/
env.rs

1use std::{env::VarError, sync::OnceLock};
2
3use opentelemetry_otlp::{
4    OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
5    OTEL_EXPORTER_OTLP_METRICS_ENDPOINT, OTEL_EXPORTER_OTLP_PROTOCOL,
6    OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
7};
8
9const OTEL_SDK_DISABLED: &str = "OTEL_SDK_DISABLED";
10const OTEL_EXPORTER_OTLP_TRACES_PROTOCOL: &str = "OTEL_EXPORTER_OTLP_TRACES_PROTOCOL";
11const OTEL_EXPORTER_OTLP_METRICS_PROTOCOL: &str = "OTEL_EXPORTER_OTLP_METRICS_PROTOCOL";
12const OTEL_EXPORTER_OTLP_LOGS_PROTOCOL: &str = "OTEL_EXPORTER_OTLP_LOGS_PROTOCOL";
13const SPIN_DISABLE_LOG_TO_TRACING: &str = "SPIN_DISABLE_LOG_TO_TRACING";
14
15/// Returns a boolean indicating if the OTEL tracing layer should be enabled.
16///
17/// It is considered enabled if any of the following environment variables are set and not empty:
18/// - `OTEL_EXPORTER_OTLP_ENDPOINT`
19/// - `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`
20///
21/// Note that this is overridden if OTEL_SDK_DISABLED is set and not empty.
22pub fn otel_tracing_enabled() -> bool {
23    any_vars_set(&[
24        OTEL_EXPORTER_OTLP_ENDPOINT,
25        OTEL_EXPORTER_OTLP_TRACES_ENDPOINT,
26    ]) && !otel_sdk_disabled()
27}
28
29/// Returns a boolean indicating if the OTEL metrics layer should be enabled.
30///
31/// It is considered enabled if any of the following environment variables are set and not empty:
32/// - `OTEL_EXPORTER_OTLP_ENDPOINT`
33/// - `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`
34///
35/// Note that this is overridden if OTEL_SDK_DISABLED is set and not empty.
36pub fn otel_metrics_enabled() -> bool {
37    any_vars_set(&[
38        OTEL_EXPORTER_OTLP_ENDPOINT,
39        OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
40    ]) && !otel_sdk_disabled()
41}
42
43/// Returns a boolean indicating if the OTEL log layer should be enabled.
44///
45/// It is considered enabled if any of the following environment variables are set and not empty:
46/// - `OTEL_EXPORTER_OTLP_ENDPOINT`
47/// - `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`
48///
49/// Note that this is overridden if OTEL_SDK_DISABLED is set and not empty.
50///
51/// The result is cached after the first call because this is checked on every guest log write.
52pub fn otel_logs_enabled() -> bool {
53    static ENABLED: OnceLock<bool> = OnceLock::new();
54    *ENABLED.get_or_init(|| {
55        any_vars_set(&[
56            OTEL_EXPORTER_OTLP_ENDPOINT,
57            OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
58        ]) && !otel_sdk_disabled()
59    })
60}
61
62/// Returns a boolean indicating if the compatibility layer that emits tracing events from
63/// applications logs should be disabled.
64///
65/// It is considered disabled if the environment variable `SPIN_DISABLED_LOG_TO_TRACING` is set and not
66/// empty. By default the features is enabled.
67pub fn spin_disable_log_to_tracing() -> bool {
68    any_vars_set(&[SPIN_DISABLE_LOG_TO_TRACING])
69}
70
71fn any_vars_set(enabling_vars: &[&str]) -> bool {
72    enabling_vars
73        .iter()
74        .any(|key| std::env::var_os(key).is_some_and(|val| !val.is_empty()))
75}
76
77/// Returns a boolean indicating if the OTEL SDK should be disabled for all signals.
78///
79/// It is considered disabled if the environment variable `OTEL_SDK_DISABLED` is set and not empty.
80pub fn otel_sdk_disabled() -> bool {
81    std::env::var_os(OTEL_SDK_DISABLED).is_some_and(|val| !val.is_empty())
82}
83
84/// The protocol to use for OTLP exporter.
85#[derive(Debug)]
86pub enum OtlpProtocol {
87    Grpc,
88    HttpProtobuf,
89    HttpJson,
90}
91
92impl OtlpProtocol {
93    /// Returns the protocol to be used for exporting traces as defined by the environment.
94    pub fn traces_protocol_from_env() -> Self {
95        Self::protocol_from_env(
96            std::env::var(OTEL_EXPORTER_OTLP_TRACES_PROTOCOL),
97            std::env::var(OTEL_EXPORTER_OTLP_PROTOCOL),
98        )
99    }
100
101    /// Returns the protocol to be used for exporting metrics as defined by the environment.
102    pub fn metrics_protocol_from_env() -> Self {
103        Self::protocol_from_env(
104            std::env::var(OTEL_EXPORTER_OTLP_METRICS_PROTOCOL),
105            std::env::var(OTEL_EXPORTER_OTLP_PROTOCOL),
106        )
107    }
108
109    /// Returns the protocol to be used for exporting logs as defined by the environment.
110    pub fn logs_protocol_from_env() -> Self {
111        Self::protocol_from_env(
112            std::env::var(OTEL_EXPORTER_OTLP_LOGS_PROTOCOL),
113            std::env::var(OTEL_EXPORTER_OTLP_PROTOCOL),
114        )
115    }
116
117    fn protocol_from_env(
118        specific_protocol: Result<String, VarError>,
119        general_protocol: Result<String, VarError>,
120    ) -> Self {
121        let protocol =
122            specific_protocol.unwrap_or(general_protocol.unwrap_or("http/protobuf".to_string()));
123
124        static WARN_ONCE: std::sync::Once = std::sync::Once::new();
125
126        match protocol.as_str() {
127            "grpc" => Self::Grpc,
128            "http/protobuf" => Self::HttpProtobuf,
129            "http/json" => Self::HttpJson,
130            s => {
131                WARN_ONCE.call_once(|| {
132                    terminal::warn!(
133                        "'{s}' is not a valid OTLP protocol, defaulting to http/protobuf"
134                    );
135                });
136                Self::HttpProtobuf
137            }
138        }
139    }
140}