From 9eb1d098bd5d29eee489564b1e25bb045c25ff5a Mon Sep 17 00:00:00 2001 From: Jade Ellis Date: Thu, 22 May 2025 13:19:30 +0100 Subject: [PATCH] feat: Support logging to journald with tracing-journald This stubs out on non-unix platforms. --- Cargo.lock | 12 ++++++++++++ Cargo.toml | 4 +++- arch/conduwuit.service | 4 ++++ conduwuit-example.toml | 9 +++++++++ debian/conduwuit.service | 3 +++ src/core/config/mod.rs | 18 ++++++++++++++++++ src/main/Cargo.toml | 7 +++++++ src/main/logging.rs | 36 +++++++++++++++++++++++++++++++++++- 8 files changed, 91 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 160be0c7..af8a07c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -794,6 +794,7 @@ dependencies = [ "tokio-metrics", "tracing", "tracing-flame", + "tracing-journald", "tracing-opentelemetry", "tracing-subscriber", ] @@ -5067,6 +5068,17 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tracing-journald" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0b4143302cf1022dac868d521e36e8b27691f72c84b3311750d5188ebba657" +dependencies = [ + "libc", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "tracing-log" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 1abff107..0cdef14b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -213,6 +213,8 @@ default-features = false version = "0.3.19" default-features = false features = ["env-filter", "std", "tracing", "tracing-log", "ansi", "fmt"] +[workspace.dependencies.tracing-journald] +version = "0.3.1" [workspace.dependencies.tracing-core] version = "0.1.33" default-features = false @@ -381,7 +383,7 @@ features = [ "unstable-msc4121", "unstable-msc4125", "unstable-msc4186", - "unstable-msc4203", # sending to-device events to appservices + "unstable-msc4203", # sending to-device events to appservices "unstable-msc4210", # remove legacy mentions "unstable-extensible-events", "unstable-pdu", diff --git a/arch/conduwuit.service b/arch/conduwuit.service index c86e37bd..67d08993 100644 --- a/arch/conduwuit.service +++ b/arch/conduwuit.service @@ -16,6 +16,10 @@ DeviceAllow=char-tty StandardInput=tty-force StandardOutput=tty StandardError=journal+console + +Environment="CONTINUWUITY_LOG_TO_JOURNALD=1" +Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N" + TTYReset=yes # uncomment to allow buffer to be cleared every restart TTYVTDisallocate=no diff --git a/conduwuit-example.toml b/conduwuit-example.toml index 1a8be2aa..0ed3f6d1 100644 --- a/conduwuit-example.toml +++ b/conduwuit-example.toml @@ -660,6 +660,15 @@ # #log_thread_ids = false +# Enable journald logging on Unix platforms +# +#log_to_journald = false + +# The syslog identifier to use with journald logging +# Only used when journald logging is enabled +# +#journald_identifier = "conduwuit" + # OpenID token expiration/TTL in seconds. # # These are the OpenID tokens that are primarily used for Matrix account diff --git a/debian/conduwuit.service b/debian/conduwuit.service index be2f3dae..b95804d3 100644 --- a/debian/conduwuit.service +++ b/debian/conduwuit.service @@ -14,6 +14,9 @@ Type=notify Environment="CONTINUWUITY_CONFIG=/etc/conduwuit/conduwuit.toml" +Environment="CONTINUWUITY_LOG_TO_JOURNALD=1" +Environment="CONTINUWUITY_JOURNALD_IDENTIFIER=%N" + ExecStart=/usr/sbin/conduwuit ReadWritePaths=/var/lib/conduwuit /etc/conduwuit diff --git a/src/core/config/mod.rs b/src/core/config/mod.rs index d4a10345..1e51c17b 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -795,6 +795,24 @@ pub struct Config { #[serde(default)] pub log_thread_ids: bool, + /// Enable journald logging on Unix platforms + /// + /// When enabled, log output will be sent to the systemd journal + /// This is only supported on Unix platforms + /// + /// default: false + #[cfg(target_family = "unix")] + #[serde(default)] + pub log_to_journald: bool, + + /// The syslog identifier to use with journald logging + /// + /// Only used when journald logging is enabled + /// + /// Defaults to the binary name + #[cfg(target_family = "unix")] + pub journald_identifier: Option, + /// OpenID token expiration/TTL in seconds. /// /// These are the OpenID tokens that are primarily used for Matrix account diff --git a/src/main/Cargo.toml b/src/main/Cargo.toml index 0c5e2b6f..2d8d26b5 100644 --- a/src/main/Cargo.toml +++ b/src/main/Cargo.toml @@ -43,6 +43,7 @@ default = [ "io_uring", "jemalloc", "jemalloc_conf", + "journald", "media_thumbnail", "release_max_log_level", "systemd", @@ -130,6 +131,11 @@ sentry_telemetry = [ systemd = [ "conduwuit-router/systemd", ] +journald = [ # This is a stub on non-unix platforms + "dep:tracing-journald", +] + + # enable the tokio_console server ncompatible with release_max_log_level tokio_console = [ "dep:console-subscriber", @@ -183,6 +189,7 @@ tracing-opentelemetry.optional = true tracing-opentelemetry.workspace = true tracing-subscriber.workspace = true tracing.workspace = true +tracing-journald = { workspace = true, optional = true } [target.'cfg(all(not(target_env = "msvc"), target_os = "linux"))'.dependencies] hardened_malloc-rs.workspace = true diff --git a/src/main/logging.rs b/src/main/logging.rs index eeeda127..b3ad366b 100644 --- a/src/main/logging.rs +++ b/src/main/logging.rs @@ -43,6 +43,15 @@ pub(crate) fn init( .with(console_layer.with_filter(console_reload_filter)) .with(cap_layer); + // If journald logging is enabled on Unix platforms, create a separate + // subscriber for it + #[cfg(all(target_family = "unix", feature = "journald"))] + if config.log_to_journald { + if let Err(e) = init_journald_logging(config) { + eprintln!("Failed to initialize journald logging: {e}"); + } + } + #[cfg(feature = "sentry_telemetry")] let subscriber = { let sentry_filter = EnvFilter::try_new(&config.sentry_filter) @@ -122,6 +131,28 @@ pub(crate) fn init( Ok(ret) } +#[cfg(all(target_family = "unix", feature = "journald"))] +fn init_journald_logging(config: &Config) -> Result<()> { + use tracing_journald::Layer as JournaldLayer; + + let journald_filter = + EnvFilter::try_new(&config.log).map_err(|e| err!(Config("log", "{e}.")))?; + + let mut journald_layer = JournaldLayer::new() + .map_err(|e| err!(Config("journald", "Failed to initialize journald layer: {e}.")))?; + + if let Some(ref identifier) = config.journald_identifier { + journald_layer = journald_layer.with_syslog_identifier(identifier.to_owned()); + } + + let journald_subscriber = + Registry::default().with(journald_layer.with_filter(journald_filter)); + + let _guard = tracing::subscriber::set_default(journald_subscriber); + + Ok(()) +} + fn tokio_console_enabled(config: &Config) -> (bool, &'static str) { if !cfg!(all(feature = "tokio_console", tokio_unstable)) { return (false, ""); @@ -141,7 +172,10 @@ fn tokio_console_enabled(config: &Config) -> (bool, &'static str) { (true, "") } -fn set_global_default(subscriber: S) { +fn set_global_default(subscriber: S) +where + S: tracing::Subscriber + Send + Sync + 'static, +{ tracing::subscriber::set_global_default(subscriber) .expect("the global default tracing subscriber failed to be initialized"); }