diff --git a/Cargo.lock b/Cargo.lock index 82e7a20d..5a65a729 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,6 +797,7 @@ dependencies = [ "tokio-metrics", "tracing", "tracing-flame", + "tracing-journald", "tracing-opentelemetry", "tracing-subscriber", ] @@ -5178,6 +5179,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 b815e2b8..75e15233 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 diff --git a/arch/conduwuit.service b/arch/conduwuit.service index d5a65e4d..b66bc1da 100644 --- a/arch/conduwuit.service +++ b/arch/conduwuit.service @@ -17,6 +17,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 794ab870..1e403bba 100644 --- a/conduwuit-example.toml +++ b/conduwuit-example.toml @@ -671,6 +671,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 e3db4900..6b054bd6 100644 --- a/src/core/config/mod.rs +++ b/src/core/config/mod.rs @@ -811,6 +811,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 36a8896c..b7beb103 100644 --- a/src/main/logging.rs +++ b/src/main/logging.rs @@ -46,6 +46,16 @@ 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 { + println!("Initialising journald logging"); + 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) @@ -135,6 +145,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, ""); @@ -154,7 +186,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"); }