From 4f9b1d6dbda71cb1bc31b10095c31c08df31b7a7 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Thu, 27 Nov 2025 18:20:54 +0000 Subject: [PATCH] Add config options to coarsely disable log/tracing without initialization. Signed-off-by: Jason Volk --- src/core/config/mod.rs | 20 +++++++++++++++++ src/core/log/mod.rs | 22 +++++++++++++------ src/core/server.rs | 6 +++--- src/main/logging.rs | 49 +++++++++++++++++++++++++++--------------- src/main/server.rs | 5 +---- tuwunel-example.toml | 16 ++++++++++++++ 6 files changed, 87 insertions(+), 31 deletions(-) diff --git a/src/core/config/mod.rs b/src/core/config/mod.rs index 4a16136e..d5beb655 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -912,6 +912,26 @@ pub struct Config { #[serde(default)] pub log_to_stderr: bool, + /// Setting to false disables the logging/tracing system at a lower level. + /// In contrast to configuring an empty `log` string where the system is + /// still operating but muted, when this option is false the system was not + /// initialized and is not operating. Changing this option has no effect + /// after startup. This option is intended for developers and expert use + /// only: configuring an empty log string is preferred over using this. + /// + /// default: true + #[serde(default = "true_fn")] + pub log_enable: bool, + + /// Setting to false disables the logging/tracing system at a lower level + /// similar to `log_enable`. In this case the system is configured normally, + /// but not registered as the global handler in the final steps. This option + /// is for developers and expert use only. + /// + /// default: true + #[serde(default = "true_fn")] + pub log_global_default: bool, + /// OpenID token expiration/TTL in seconds. /// /// These are the OpenID tokens that are primarily used for Matrix account diff --git a/src/core/log/mod.rs b/src/core/log/mod.rs index f7b2521a..e406d8d3 100644 --- a/src/core/log/mod.rs +++ b/src/core/log/mod.rs @@ -8,23 +8,31 @@ pub mod fmt_span; mod reload; mod suppress; -pub use capture::Capture; -pub use console::{ConsoleFormat, ConsoleWriter, is_systemd_mode}; -pub use reload::{LogLevelReloadHandles, ReloadHandle}; -pub use suppress::Suppress; -pub use tracing::Level; +use std::sync::Arc; + +pub use tracing::{Level, subscriber::Subscriber}; pub use tracing_core::{Event, Metadata}; pub use tracing_subscriber::EnvFilter; +pub use self::{ + capture::Capture, + console::{ConsoleFormat, ConsoleWriter, is_systemd_mode}, + reload::{LogLevelReloadHandles, ReloadHandle}, + suppress::Suppress, +}; + /// Logging subsystem. This is a singleton member of super::Server which holds /// all logging and tracing related state rather than shoving it all in /// super::Server directly. -pub struct Log { +pub struct Logging { + /// Subscriber assigned to globals and defaults; may also be NoSubscriber. + pub subscriber: Arc, + /// General log level reload handles. pub reload: LogLevelReloadHandles, /// Tracing capture state for ephemeral/oneshot uses. - pub capture: std::sync::Arc, + pub capture: Arc, } // Wraps for logging macros. Use these macros rather than extern tracing:: or diff --git a/src/core/server.rs b/src/core/server.rs index 547f86bd..fff6ba4c 100644 --- a/src/core/server.rs +++ b/src/core/server.rs @@ -9,7 +9,7 @@ use std::{ use ruma::OwnedServerName; use tokio::{runtime, sync::broadcast}; -use crate::{Err, Result, config, config::Config, log::Log, metrics::Metrics}; +use crate::{Err, Result, config, config::Config, log::Logging, metrics::Metrics}; /// Server runtime state; public portion pub struct Server { @@ -41,7 +41,7 @@ pub struct Server { pub signal: broadcast::Sender<&'static str>, /// Logging subsystem state - pub log: Log, + pub log: Logging, /// Metrics subsystem state pub metrics: Metrics, @@ -49,7 +49,7 @@ pub struct Server { impl Server { #[must_use] - pub fn new(config: Config, runtime: Option, log: Log) -> Self { + pub fn new(config: Config, runtime: Option, log: Logging) -> Self { Self { name: config.server_name.clone(), config: config::Manager::new(config), diff --git a/src/main/logging.rs b/src/main/logging.rs index 4e158548..d365ee2a 100644 --- a/src/main/logging.rs +++ b/src/main/logging.rs @@ -1,11 +1,12 @@ use std::sync::Arc; +use tracing::subscriber::NoSubscriber; use tracing_subscriber::{EnvFilter, Layer, Registry, fmt, layer::SubscriberExt, reload}; use tuwunel_core::{ Result, config::Config, debug_warn, err, - log::{ConsoleFormat, ConsoleWriter, LogLevelReloadHandles, capture, fmt_span}, + log::{ConsoleFormat, ConsoleWriter, LogLevelReloadHandles, Logging, capture, fmt_span}, result::UnwrapOrErr, }; @@ -14,13 +15,20 @@ pub(crate) type TracingFlameGuard = Option>>; #[cfg(not(feature = "perf_measurements"))] -pub(crate) type TracingFlameGuard = (); +pub(crate) type TracingFlameGuard = Option<()>; #[allow(clippy::redundant_clone)] -pub(crate) fn init( - config: &Config, -) -> Result<(LogLevelReloadHandles, TracingFlameGuard, Arc)> { +pub(crate) fn init(config: &Config) -> Result<(TracingFlameGuard, Logging)> { let reload_handles = LogLevelReloadHandles::default(); + let cap_state = Arc::new(capture::State::new()); + + if !config.log_enable { + return Ok((None, Logging { + reload: reload_handles, + capture: cap_state, + subscriber: Arc::new(NoSubscriber::new()), + })); + } let console_span_events = fmt_span::from_str(&config.log_span_events).unwrap_or_err(); @@ -37,14 +45,11 @@ pub(crate) fn init( .event_format(ConsoleFormat::new(config)) .with_writer(ConsoleWriter::new(config)); - let (console_reload_filter, console_reload_handle) = - reload::Layer::new(console_filter.clone()); + let (console_reload_filter, console_reload_handle) = reload::Layer::new(console_filter); reload_handles.add("console", Box::new(console_reload_handle)); - let cap_state = Arc::new(capture::State::new()); let cap_layer = capture::Layer::new(&cap_state); - let subscriber = Registry::default() .with(console_layer.with_filter(console_reload_filter)) .with(cap_layer); @@ -117,33 +122,43 @@ pub(crate) fn init( not(feature = "perf_measurements"), allow(clippy::let_unit_value) )] - let flame_guard = (); + let flame_guard = None; - let ret = (reload_handles, flame_guard, cap_state); + let subscriber = Arc::new(subscriber); // 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 // subscriber's type. let (console_enabled, console_disabled_reason) = tokio_console_enabled(config); #[cfg(all(feature = "tokio_console", tokio_unstable, tuwunel_disable))] - if console_enabled { + if console_enabled && config.log_global_default { let console_layer = console_subscriber::ConsoleLayer::builder() .with_default_env() .spawn(); - set_global_default(subscriber.with(console_layer)); - return Ok(ret); + set_global_default(subscriber.clone().with(console_layer)); + return Ok((flame_guard, Log { + reload: reload_handles, + capture: cap_state, + subscriber, + })); } - set_global_default(subscriber); + if config.log_global_default { + set_global_default(subscriber.clone()); + } // If there's a reason the tokio console was disabled when it might be desired // we output that here after initializing logging - if !console_enabled && !console_disabled_reason.is_empty() { + if !console_enabled && !console_disabled_reason.is_empty() && config.log_global_default { debug_warn!("{console_disabled_reason}"); } - Ok(ret) + Ok((flame_guard, Logging { + reload: reload_handles, + capture: cap_state, + subscriber, + })) } fn tokio_console_enabled(config: &Config) -> (bool, &'static str) { diff --git a/src/main/server.rs b/src/main/server.rs index de68b7f0..b8717c22 100644 --- a/src/main/server.rs +++ b/src/main/server.rs @@ -5,7 +5,6 @@ use tuwunel_core::{ Error, Result, config::Config, implement, info, - log::Log, utils::{stream, sys}, }; @@ -45,7 +44,7 @@ pub fn new(args: Option<&Args>, runtime: Option<&runtime::Handle>) -> Result, runtime: Option<&runtime::Handle>) -> Result