diff --git a/crates/cli/src/telemetry.rs b/crates/cli/src/telemetry.rs index e6a1f23e..25ffa230 100644 --- a/crates/cli/src/telemetry.rs +++ b/crates/cli/src/telemetry.rs @@ -14,8 +14,9 @@ use std::time::Duration; +use anyhow::bail; use futures::stream::{Stream, StreamExt}; -use mas_config::{MetricsConfig, TelemetryConfig, TracingConfig}; +use mas_config::{MetricsExporterConfig, Propagator, TelemetryConfig, TracingExporterConfig}; use opentelemetry::{ global, propagation::TextMapPropagator, @@ -30,15 +31,15 @@ use opentelemetry_semantic_conventions as semcov; pub fn setup(config: &TelemetryConfig) -> anyhow::Result> { global::set_error_handler(|e| tracing::error!("{}", e))?; - let propagator = propagator(); + let propagator = propagator(&config.tracing.propagators)?; // The CORS filter needs to know what headers it should whitelist for // CORS-protected requests. mas_core::filters::cors::set_propagator(&propagator); global::set_text_map_propagator(propagator); - let tracer = tracer(&config.tracing)?; - meter(&config.metrics)?; + let tracer = tracer(&config.tracing.exporter)?; + meter(&config.metrics.exporter)?; Ok(tracer) } @@ -46,15 +47,24 @@ pub fn shutdown() { global::shutdown_tracer_provider(); } -fn propagator() -> impl TextMapPropagator { - // TODO: make this configurable - let baggage_propagator = BaggagePropagator::new(); - let trace_context_propagator = TraceContextPropagator::new(); +fn match_propagator( + propagator: Propagator, +) -> anyhow::Result> { + match propagator { + Propagator::TraceContext => Ok(Box::new(TraceContextPropagator::new())), + Propagator::Baggage => Ok(Box::new(BaggagePropagator::new())), + p => bail!( + "The service was compiled without support for the {:?} propagator, but config uses it.", + p + ), + } +} - TextMapCompositePropagator::new(vec![ - Box::new(baggage_propagator), - Box::new(trace_context_propagator), - ]) +fn propagator(propagators: &[Propagator]) -> anyhow::Result { + let propagators: Result, _> = + propagators.iter().cloned().map(match_propagator).collect(); + + Ok(TextMapCompositePropagator::new(propagators?)) } #[cfg(feature = "otlp")] @@ -87,11 +97,11 @@ fn stdout_tracer() -> Tracer { .install_simple() } -fn tracer(config: &TracingConfig) -> anyhow::Result> { +fn tracer(config: &TracingExporterConfig) -> anyhow::Result> { let tracer = match config { - TracingConfig::None => return Ok(None), - TracingConfig::Stdout => stdout_tracer(), - TracingConfig::Otlp { endpoint } => otlp_tracer(endpoint)?, + TracingExporterConfig::None => return Ok(None), + TracingExporterConfig::Stdout => stdout_tracer(), + TracingExporterConfig::Otlp { endpoint } => otlp_tracer(endpoint)?, }; Ok(Some(tracer)) @@ -131,11 +141,11 @@ fn stdout_meter() { .init(); } -fn meter(config: &MetricsConfig) -> anyhow::Result<()> { +fn meter(config: &MetricsExporterConfig) -> anyhow::Result<()> { match config { - MetricsConfig::None => {} - MetricsConfig::Stdout => stdout_meter(), - MetricsConfig::Otlp { endpoint } => otlp_meter(endpoint)?, + MetricsExporterConfig::None => {} + MetricsExporterConfig::Stdout => stdout_meter(), + MetricsExporterConfig::Otlp { endpoint } => otlp_meter(endpoint)?, }; Ok(()) diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 0301850e..f3aa92e7 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -31,7 +31,10 @@ pub use self::{ database::DatabaseConfig, http::HttpConfig, oauth2::{Algorithm, KeySet, OAuth2ClientConfig, OAuth2Config}, - telemetry::{MetricsConfig, TelemetryConfig, TracingConfig}, + telemetry::{ + MetricsConfig, MetricsExporterConfig, Propagator, TelemetryConfig, TracingConfig, + TracingExporterConfig, + }, templates::TemplatesConfig, util::ConfigurationSection, }; diff --git a/crates/config/src/telemetry.rs b/crates/config/src/telemetry.rs index 06ad8f01..00596775 100644 --- a/crates/config/src/telemetry.rs +++ b/crates/config/src/telemetry.rs @@ -19,10 +19,21 @@ use serde_with::skip_serializing_none; use super::ConfigurationSection; +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "lowercase")] +#[non_exhaustive] +pub enum Propagator { + TraceContext, + Baggage, + Jaeger, + B3, + B3Multi, +} + #[skip_serializing_none] #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] #[serde(tag = "exporter", rename_all = "lowercase")] -pub enum TracingConfig { +pub enum TracingExporterConfig { None, Stdout, Otlp { @@ -31,34 +42,49 @@ pub enum TracingConfig { }, } -impl Default for TracingConfig { - fn default() -> Self { - Self::None - } -} - -#[skip_serializing_none] -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] -#[serde(tag = "exporter", rename_all = "lowercase")] -pub enum MetricsConfig { - None, - Stdout, - Otlp { - #[serde(default)] - endpoint: Option, - }, -} - -impl Default for MetricsConfig { +impl Default for TracingExporterConfig { fn default() -> Self { Self::None } } +#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] +pub struct TracingConfig { + #[serde(default, flatten)] + pub exporter: TracingExporterConfig, + + pub propagators: Vec, +} + +#[skip_serializing_none] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[serde(tag = "exporter", rename_all = "lowercase")] +pub enum MetricsExporterConfig { + None, + Stdout, + Otlp { + #[serde(default)] + endpoint: Option, + }, +} + +impl Default for MetricsExporterConfig { + fn default() -> Self { + Self::None + } +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] +pub struct MetricsConfig { + #[serde(default, flatten)] + pub exporter: MetricsExporterConfig, +} + #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] pub struct TelemetryConfig { #[serde(default)] pub tracing: TracingConfig, + #[serde(default)] pub metrics: MetricsConfig, }