diff --git a/src/core/error.rs b/src/core/error.rs index 26bac6e06004609bd5cea8c38f175430fe2980a2..8567f30361862a47bb3d96c861d3c85384c25c70 100644 --- a/src/core/error.rs +++ b/src/core/error.rs @@ -47,6 +47,8 @@ pub enum Error { Regex(#[from] regex::Error), #[error("Tracing filter error: {0}")] TracingFilter(#[from] tracing_subscriber::filter::ParseError), + #[error("Tracing reload error: {0}")] + TracingReload(#[from] tracing_subscriber::reload::Error), #[error("Image error: {0}")] Image(#[from] image::error::ImageError), #[error("Request error: {0}")] diff --git a/src/core/log/reload.rs b/src/core/log/reload.rs index 7646254edb996666121e41241067de938517c900..cfed785d8cf56824dafe11adea1846c59a1a7a1e 100644 --- a/src/core/log/reload.rs +++ b/src/core/log/reload.rs @@ -1,7 +1,12 @@ -use std::sync::Arc; +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; use tracing_subscriber::{reload, EnvFilter}; +use crate::{error, Result}; + /// We need to store a reload::Handle value, but can't name it's type explicitly /// because the S type parameter depends on the subscriber's previous layers. In /// our case, this includes unnameable 'impl Trait' types. @@ -24,32 +29,39 @@ impl<L, S> ReloadHandle<L> for reload::Handle<L, S> { fn reload(&self, new_value: L) -> Result<(), reload::Error> { Self::reload(self, new_value) } } -struct LogLevelReloadHandlesInner { - handles: Vec<Box<dyn ReloadHandle<EnvFilter> + Send + Sync>>, -} - -/// Wrapper to allow reloading the filter on several several -/// [`tracing_subscriber::reload::Handle`]s at once, with the same value. #[derive(Clone)] pub struct LogLevelReloadHandles { - inner: Arc<LogLevelReloadHandlesInner>, + handles: Arc<Mutex<HandleMap>>, } +type HandleMap = HashMap<String, Handle>; +type Handle = Box<dyn ReloadHandle<EnvFilter> + Send + Sync>; + impl LogLevelReloadHandles { - #[must_use] - pub fn new(handles: Vec<Box<dyn ReloadHandle<EnvFilter> + Send + Sync>>) -> Self { - Self { - inner: Arc::new(LogLevelReloadHandlesInner { - handles, - }), - } + pub fn add(&self, name: &str, handle: Handle) { + self.handles + .lock() + .expect("locked") + .insert(name.into(), handle); } - pub fn reload(&self, new_value: &EnvFilter) -> Result<(), reload::Error> { - for handle in &self.inner.handles { - handle.reload(new_value.clone())?; - } + pub fn reload(&self, new_value: &EnvFilter) -> Result<()> { + self.handles + .lock() + .expect("locked") + .values() + .for_each(|handle| { + _ = handle.reload(new_value.clone()).or_else(error::else_log); + }); Ok(()) } } + +impl Default for LogLevelReloadHandles { + fn default() -> Self { + Self { + handles: Arc::new(HandleMap::new().into()), + } + } +} diff --git a/src/main/tracing.rs b/src/main/tracing.rs index bbfe4dc4245d6a01493590bb0c6ac93e6e214368..4c8fde5a20915e168286bf4f22f75cda0d45dfcd 100644 --- a/src/main/tracing.rs +++ b/src/main/tracing.rs @@ -4,7 +4,7 @@ config, config::Config, debug_warn, - log::{capture, LogLevelReloadHandles, ReloadHandle}, + log::{capture, LogLevelReloadHandles}, }; use tracing_subscriber::{layer::SubscriberExt, reload, EnvFilter, Layer, Registry}; @@ -15,6 +15,8 @@ #[allow(clippy::redundant_clone)] pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard, Arc<capture::State>) { + let reload_handles = LogLevelReloadHandles::default(); + let fmt_layer = tracing_subscriber::fmt::Layer::new(); let filter_layer = match EnvFilter::try_new(&config.log) { Ok(s) => s, @@ -24,9 +26,8 @@ pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard }, }; - let mut reload_handles = Vec::<Box<dyn ReloadHandle<EnvFilter> + Send + Sync>>::new(); let (fmt_reload_filter, fmt_reload_handle) = reload::Layer::new(filter_layer.clone()); - reload_handles.push(Box::new(fmt_reload_handle)); + reload_handles.add("format", Box::new(fmt_reload_handle)); let subscriber = Registry::default().with(fmt_layer.with_filter(fmt_reload_filter)); @@ -38,7 +39,7 @@ pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard let subscriber = { let sentry_layer = sentry_tracing::layer(); let (sentry_reload_filter, sentry_reload_handle) = reload::Layer::new(filter_layer.clone()); - reload_handles.push(Box::new(sentry_reload_handle)); + reload_handles.add("sentry", Box::new(sentry_reload_handle)); subscriber.with(sentry_layer.with_filter(sentry_reload_filter)) }; @@ -73,7 +74,7 @@ pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard let telemetry = tracing_opentelemetry::layer().with_tracer(tracer); let (jaeger_reload_filter, jaeger_reload_handle) = reload::Layer::new(filter_layer.clone()); - reload_handles.push(Box::new(jaeger_reload_handle)); + reload_handles.add("jaeger", Box::new(jaeger_reload_handle)); Some(telemetry.with_filter(jaeger_reload_filter)) } else { None @@ -87,7 +88,7 @@ pub(crate) fn init(config: &Config) -> (LogLevelReloadHandles, TracingFlameGuard #[cfg_attr(not(feature = "perf_measurements"), allow(clippy::let_unit_value))] let flame_guard = (); - let ret = (LogLevelReloadHandles::new(reload_handles), flame_guard, cap_state); + let ret = (reload_handles, flame_guard, cap_state); // Enable the tokio console. This is slightly kludgy because we're judggling // compile-time and runtime conditions to elide it, each of those changing the