diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 81b26909..ba9d25cb 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -35,12 +35,12 @@ tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } tracing-opentelemetry = "0.19.0" opentelemetry = { version = "0.19.0", features = ["trace", "metrics", "rt-tokio"] } opentelemetry-semantic-conventions = "0.11.0" -opentelemetry-jaeger = { version = "0.18.0", features = ["rt-tokio", "collector_client"], optional = true } -opentelemetry-otlp = { version = "0.12.0", features = ["trace", "metrics"], optional = true } -opentelemetry-zipkin = { version = "0.17.0", features = ["opentelemetry-http"], default-features = false, optional = true } -opentelemetry-http = { version = "0.8.0", features = ["tokio", "hyper"], optional = true } -opentelemetry-prometheus = { version = "0.12.0", optional = true } -prometheus = { version = "0.13.3", optional = true } +opentelemetry-jaeger = { version = "0.18.0", features = ["rt-tokio", "collector_client"] } +opentelemetry-otlp = { version = "0.12.0", features = ["trace", "metrics"] } +opentelemetry-zipkin = { version = "0.17.0", features = ["opentelemetry-http"], default-features = false } +opentelemetry-http = { version = "0.8.0", features = ["tokio", "hyper"] } +opentelemetry-prometheus = { version = "0.12.0" } +prometheus = "0.13.3" sentry = { version = "0.31.5", default-features = false, features = ["backtrace", "contexts", "panic", "tower"] } sentry-tracing = "0.31.5" sentry-tower = { version = "0.31.5", features = ["http"] } @@ -68,13 +68,13 @@ oauth2-types = { path = "../oauth2-types" } indoc = "2.0.3" [features] -default = ["jaeger", "zipkin", "webpki-roots", "policy-cache"] +default = ["webpki-roots", "policy-cache"] # Features used for the prebuilt binaries -dist = ["otlp", "jaeger", "zipkin", "prometheus", "policy-cache", "native-roots", "mas-config/dist"] +dist = ["policy-cache", "native-roots", "mas-config/dist"] # Features used in the Docker image -docker = ["otlp", "jaeger", "zipkin", "prometheus", "native-roots", "mas-config/docker"] +docker = ["native-roots", "mas-config/docker"] # Enable wasmtime compilation cache policy-cache = ["mas-policy/cache"] @@ -83,12 +83,3 @@ policy-cache = ["mas-policy/cache"] native-roots = ["mas-http/native-roots", "mas-handlers/native-roots"] # Use the webpki root certificates webpki-roots = ["mas-http/webpki-roots", "mas-handlers/webpki-roots"] - -# Enable OpenTelemetry OTLP exporter. Requires protoc. -otlp = ["dep:opentelemetry-otlp"] -# Enable OpenTelemetry Jaeger exporter and propagator. -jaeger = ["dep:opentelemetry-jaeger", "dep:opentelemetry-http"] -# Enable OpenTelemetry Zipkin exporter and B3 propagator. -zipkin = ["dep:opentelemetry-zipkin", "dep:opentelemetry-http"] -# Enable OpenTelemetry Prometheus exporter. Requires "protoc" -prometheus = ["dep:opentelemetry-prometheus", "dep:prometheus"] diff --git a/crates/cli/src/telemetry.rs b/crates/cli/src/telemetry.rs index 7e9c0d8d..c06adf45 100644 --- a/crates/cli/src/telemetry.rs +++ b/crates/cli/src/telemetry.rs @@ -14,7 +14,7 @@ use std::time::Duration; -use anyhow::{bail, Context as _}; +use anyhow::Context as _; use hyper::{header::CONTENT_TYPE, Body, Response}; use mas_config::{ JaegerExporterProtocolConfig, MetricsExporterConfig, Propagator, TelemetryConfig, @@ -32,26 +32,21 @@ use opentelemetry::{ }, Context, }; -#[cfg(feature = "jaeger")] use opentelemetry_jaeger::Propagator as JaegerPropagator; -#[cfg(feature = "prometheus")] use opentelemetry_prometheus::PrometheusExporter; use opentelemetry_semantic_conventions as semcov; -#[cfg(feature = "zipkin")] use opentelemetry_zipkin::{B3Encoding, Propagator as ZipkinPropagator}; use tokio::sync::OnceCell; use url::Url; static METRICS_BASIC_CONTROLLER: OnceCell = OnceCell::const_new(); - -#[cfg(feature = "prometheus")] static PROMETHEUS_EXPORTER: OnceCell = OnceCell::const_new(); pub async fn setup( config: &TelemetryConfig, ) -> anyhow::Result<(Option, Option)> { global::set_error_handler(|e| tracing::error!("{}", e))?; - let propagator = propagator(&config.tracing.propagators)?; + let propagator = propagator(&config.tracing.propagators); // The CORS filter needs to know what headers it should whitelist for // CORS-protected requests. @@ -79,40 +74,23 @@ pub fn shutdown() { } } -fn match_propagator( - propagator: Propagator, -) -> anyhow::Result> { +fn match_propagator(propagator: Propagator) -> Box { + use Propagator as P; match propagator { - Propagator::TraceContext => Ok(Box::new(TraceContextPropagator::new())), - Propagator::Baggage => Ok(Box::new(BaggagePropagator::new())), - - #[cfg(feature = "jaeger")] - Propagator::Jaeger => Ok(Box::new(JaegerPropagator::new())), - - #[cfg(feature = "zipkin")] - Propagator::B3 => Ok(Box::new(ZipkinPropagator::with_encoding( - B3Encoding::SingleHeader, - ))), - - #[cfg(feature = "zipkin")] - Propagator::B3Multi => Ok(Box::new(ZipkinPropagator::with_encoding( - B3Encoding::MultipleHeader, - ))), - - p => bail!( - "The service was compiled without support for the {p:?} propagator, but config uses it.", - ), + P::TraceContext => Box::new(TraceContextPropagator::new()), + P::Baggage => Box::new(BaggagePropagator::new()), + P::Jaeger => Box::new(JaegerPropagator::new()), + P::B3 => Box::new(ZipkinPropagator::with_encoding(B3Encoding::SingleHeader)), + P::B3Multi => Box::new(ZipkinPropagator::with_encoding(B3Encoding::MultipleHeader)), } } -fn propagator(propagators: &[Propagator]) -> anyhow::Result { - let propagators: Result, _> = - propagators.iter().cloned().map(match_propagator).collect(); +fn propagator(propagators: &[Propagator]) -> impl TextMapPropagator { + let propagators = propagators.iter().copied().map(match_propagator).collect(); - Ok(TextMapCompositePropagator::new(propagators?)) + TextMapCompositePropagator::new(propagators) } -#[cfg(any(feature = "zipkin", feature = "jaeger"))] async fn http_client() -> anyhow::Result { let client = mas_http::make_untraced_client() .await @@ -129,7 +107,6 @@ fn stdout_tracer() -> Tracer { .install_simple() } -#[cfg(feature = "otlp")] fn otlp_tracer(endpoint: Option<&Url>) -> anyhow::Result { use opentelemetry_otlp::WithExportConfig; @@ -148,19 +125,6 @@ fn otlp_tracer(endpoint: Option<&Url>) -> anyhow::Result { Ok(tracer) } -#[cfg(not(feature = "otlp"))] -#[allow(unused_variables)] -fn otlp_tracer(endpoint: Option<&Url>) -> anyhow::Result { - anyhow::bail!("The service was compiled without OTLP exporter support, but config exports traces via OTLP.") -} - -#[cfg(not(feature = "jaeger"))] -#[allow(unused_variables)] -fn jaeger_agent_tracer(host: &str, port: u16) -> anyhow::Result { - anyhow::bail!("The service was compiled without Jaeger exporter support, but config exports traces via Jaeger.") -} - -#[cfg(feature = "jaeger")] fn jaeger_agent_tracer(host: &str, port: u16) -> anyhow::Result { let pipeline = opentelemetry_jaeger::new_agent_pipeline() .with_service_name(env!("CARGO_PKG_NAME")) @@ -174,17 +138,6 @@ fn jaeger_agent_tracer(host: &str, port: u16) -> anyhow::Result { Ok(tracer) } -#[cfg(not(feature = "jaeger"))] -#[allow(unused_variables, clippy::unused_async)] -async fn jaeger_collector_tracer( - endpoint: &str, - username: Option<&str>, - password: Option<&str>, -) -> anyhow::Result { - anyhow::bail!("The service was compiled without Jaeger exporter support, but config exports traces via Jaeger.") -} - -#[cfg(feature = "jaeger")] async fn jaeger_collector_tracer( endpoint: &str, username: Option<&str>, @@ -212,13 +165,6 @@ async fn jaeger_collector_tracer( Ok(tracer) } -#[cfg(not(feature = "zipkin"))] -#[allow(unused_variables, clippy::unused_async)] -async fn zipkin_tracer(collector_endpoint: &Option) -> anyhow::Result { - anyhow::bail!("The service was compiled without Jaeger exporter support, but config exports traces via Jaeger.") -} - -#[cfg(feature = "zipkin")] async fn zipkin_tracer(collector_endpoint: &Option) -> anyhow::Result { let http_client = http_client().await?; @@ -260,7 +206,6 @@ async fn tracer(config: &TracingExporterConfig) -> anyhow::Result Ok(Some(tracer)) } -#[cfg(feature = "otlp")] fn otlp_meter(endpoint: Option<&url::Url>) -> anyhow::Result { use opentelemetry_otlp::WithExportConfig; @@ -283,12 +228,6 @@ fn otlp_meter(endpoint: Option<&url::Url>) -> anyhow::Result { Ok(controller) } -#[cfg(not(feature = "otlp"))] -#[allow(unused_variables)] -fn otlp_meter(endpoint: Option<&url::Url>) -> anyhow::Result { - anyhow::bail!("The service was compiled without OTLP exporter support, but config exports metrics via OTLP.") -} - fn stdout_meter() -> anyhow::Result { let exporter = sdk::export::metrics::stdout().build()?; let controller = sdk::metrics::controllers::basic(sdk::metrics::processors::factory( @@ -306,26 +245,6 @@ fn stdout_meter() -> anyhow::Result { Ok(controller) } -#[cfg(not(feature = "prometheus"))] -pub fn prometheus_service() -> tower::util::ServiceFn< - impl FnMut(T) -> std::future::Ready, std::convert::Infallible>> + Clone, -> { - tracing::warn!("Prometheus exporter was not enabled at compilation time, but the Prometheus resource was mounted on a listener"); - - tower::service_fn(move |_req| { - let response = Response::builder() - .status(500) - .header(CONTENT_TYPE, "text/plain") - .body(Body::from( - "Prometheus exporter was not enabled at compilation time", - )) - .unwrap(); - - std::future::ready(Ok(response)) - }) -} - -#[cfg(feature = "prometheus")] pub fn prometheus_service() -> tower::util::ServiceFn< impl FnMut(T) -> std::future::Ready, std::convert::Infallible>> + Clone, > { @@ -361,12 +280,6 @@ pub fn prometheus_service() -> tower::util::ServiceFn< }) } -#[cfg(not(feature = "prometheus"))] -fn prometheus_meter() -> anyhow::Result { - anyhow::bail!("The service was compiled without Prometheus exporter support, but config exports metrics via Prometheus.") -} - -#[cfg(feature = "prometheus")] fn prometheus_meter() -> anyhow::Result { let controller = sdk::metrics::controllers::basic(sdk::metrics::processors::factory( // All histogram metrics are in milliseconds. Each bucket is ~2x the previous one. diff --git a/crates/config/src/sections/telemetry.rs b/crates/config/src/sections/telemetry.rs index 10407eb0..d6ada1b3 100644 --- a/crates/config/src/sections/telemetry.rs +++ b/crates/config/src/sections/telemetry.rs @@ -25,9 +25,8 @@ use url::Url; use super::ConfigurationSection; /// Propagation format for incoming and outgoing requests -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "lowercase")] -#[non_exhaustive] pub enum Propagator { /// Propagate according to the W3C Trace Context specification TraceContext,