diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 173ca50b4..3835f5bad 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -62,7 +62,7 @@ setup-tracing = [ "tracing-subscriber/std", "tracing-subscriber/tracing-log", ] -setup-otel-exporter = [ +otel-exporter = [ "setup-tracing", "dep:log", "dep:opentelemetry", @@ -78,3 +78,4 @@ setup-otel-exporter = [ "tracing-subscriber/tracing", "tracing-subscriber/tracing-serde", ] +setup-otel-exporter = ["otel-exporter"] diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 8d763ec7a..b59a1b060 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -10,8 +10,8 @@ mod plugins; mod rt; mod start; -#[cfg(feature = "setup-otel-exporter")] -mod telemetry; +#[cfg(feature = "otel-exporter")] +pub mod telemetry; // Public API // Useful re-exports diff --git a/runtime/src/start.rs b/runtime/src/start.rs index 47bdc50f3..58c8325fc 100644 --- a/runtime/src/start.rs +++ b/runtime/src/start.rs @@ -65,10 +65,25 @@ pub async fn start( #[cfg(feature = "setup-otel-exporter")] let _guard = { - let guard = crate::telemetry::init_tracing_subscriber(crate_name, package_version); + use tracing_subscriber::{fmt, prelude::*, registry, EnvFilter}; + let (layers, guard) = + crate::telemetry::otel_tracing_subscriber(crate_name, package_version); + + registry() + .with(layers) + .with(fmt::layer().without_time()) + .with( + // let user override RUST_LOG in local run if they want to + EnvFilter::try_from_default_env().unwrap_or_else(|_| { + // otherwise use our default + format!("info,{}=debug", crate_name).into() + }), + ) + .init(); tracing::warn!( "Default tracing subscriber with otel exporter initialized (https://docs.shuttle.dev/docs/telemetry)" ); + guard }; diff --git a/runtime/src/telemetry.rs b/runtime/src/telemetry.rs index 83d6f08c2..91be59a05 100644 --- a/runtime/src/telemetry.rs +++ b/runtime/src/telemetry.rs @@ -18,7 +18,7 @@ use opentelemetry_sdk::{ propagation::TraceContextPropagator, resource::{Resource, ResourceDetector, TelemetryResourceDetector}, runtime, - trace::TracerProvider, + trace::{Tracer, TracerProvider}, }; use opentelemetry_semantic_conventions::{ attribute::{CODE_FILEPATH, CODE_LINENO, SERVICE_NAME, SERVICE_VERSION}, @@ -32,10 +32,9 @@ use tracing_core::{ use tracing_log::AsLog; use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer, OtelData}; use tracing_subscriber::{ - layer::{Context, SubscriberExt}, + layer::{Context, Layered}, registry::LookupSpan, - util::SubscriberInitExt, - EnvFilter, Layer, + Layer, Registry, }; #[derive(Clone, Debug)] @@ -361,7 +360,7 @@ pub(crate) fn log_level_as_severity(level: log::Level) -> Severity { } // Create a Resource that captures information about the entity for which telemetry is recorded. -pub fn resource(crate_name: &'static str, package_version: &'static str) -> Resource { +fn resource(crate_name: &'static str, package_version: &'static str) -> Resource { let project_name = std::env::var("SHUTTLE_PROJECT_NAME").ok(); // `TelemetryResourceDetector::detect()` automatically provides: @@ -395,7 +394,7 @@ pub fn resource(crate_name: &'static str, package_version: &'static str) -> Reso ))) } -pub fn init_log_subscriber(endpoint: &Option, resource: Resource) -> LoggerProvider { +fn init_log_subscriber(endpoint: &Option, resource: Resource) -> LoggerProvider { let mut builder = LoggerProvider::builder().with_resource(resource); if let Some(endpoint) = endpoint { @@ -412,7 +411,7 @@ pub fn init_log_subscriber(endpoint: &Option, resource: Resource) -> Log } // Construct MeterProvider for MetricsLayer -pub fn init_meter_provider(endpoint: &Option, resource: Resource) -> SdkMeterProvider { +fn init_meter_provider(endpoint: &Option, resource: Resource) -> SdkMeterProvider { let mut builder = MeterProviderBuilder::default().with_resource(resource); if let Some(endpoint) = endpoint { @@ -438,7 +437,7 @@ pub fn init_meter_provider(endpoint: &Option, resource: Resource) -> Sdk } // Construct TracerProvider for OpenTelemetryLayer -pub fn init_tracer_provider(endpoint: &Option, resource: Resource) -> TracerProvider { +fn init_tracer_provider(endpoint: &Option, resource: Resource) -> TracerProvider { // TODO(the-wondersmith): make trace sample rate & strategy configurable // let sampler = opentelemetry_sdk::trace::Sampler::ParentBased(Box::new( // opentelemetry_sdk::trace::Sampler::TraceIdRatioBased(1.0), @@ -465,11 +464,16 @@ pub fn init_tracer_provider(endpoint: &Option, resource: Resource) -> Tr provider } -// Initialize tracing-subscriber and return ExporterGuard for opentelemetry-related termination processing -pub fn init_tracing_subscriber( +pub type OtelLayerType = Layered< + LogCourier, + Layered, MetricsLayer, Registry>, + Registry, +>; +// Construct tracing-subscriber layers and return ExporterGuard for opentelemetry-related termination processing +pub fn otel_tracing_subscriber( crate_name: &'static str, package_version: &'static str, -) -> ProviderGuard { +) -> (OtelLayerType, ProviderGuard) { global::set_text_map_propagator(TraceContextPropagator::new()); let resource = resource(crate_name, package_version); @@ -481,22 +485,10 @@ pub fn init_tracing_subscriber( let meter = init_meter_provider(&endpoint, resource.clone()); let logger = init_log_subscriber(&endpoint, resource); - let level_filter = - std::env::var("RUST_LOG").unwrap_or_else(|_| format!("info,{}=debug", crate_name)); - - let layers = EnvFilter::from(&level_filter) - .and_then(MetricsLayer::new(meter.clone())) + let layers: OtelLayerType = MetricsLayer::new(meter.clone()) .and_then(OpenTelemetryLayer::new(tracer.tracer("shuttle-telemetry"))) - .and_then( - tracing_subscriber::fmt::layer() - .compact() - .with_level(true) - .with_target(true), - ) .and_then(LogCourier::new(logger.logger("shuttle-telemetry"))); - tracing_subscriber::registry().with(layers).init(); - if endpoint.is_none() { tracing::warn!( "No value set for `{}` env var, \ @@ -505,9 +497,12 @@ pub fn init_tracing_subscriber( ); } - ProviderGuard { - logger, - tracer, - meter, - } + ( + layers, + ProviderGuard { + logger, + tracer, + meter, + }, + ) }