diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 6fe8a448a..c49ab9f83 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -996,6 +996,7 @@ dependencies = [ "backoff", "connlib-client-shared", "connlib-shared", + "firezone-logging", "ip_network", "jni 0.21.1", "libc", @@ -1021,6 +1022,7 @@ dependencies = [ "backoff", "connlib-client-shared", "connlib-shared", + "firezone-logging", "ip_network", "libc", "oslog", @@ -1043,7 +1045,6 @@ name = "connlib-client-shared" version = "0.1.0" dependencies = [ "anyhow", - "async-trait", "backoff", "bimap", "chrono", @@ -1055,13 +1056,9 @@ dependencies = [ "serde", "serde_json", "socket-factory", - "time", "tokio", "tokio-tungstenite", "tracing", - "tracing-appender", - "tracing-stackdriver", - "tracing-subscriber", "tun", "url", ] @@ -1771,6 +1768,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "firezone-logging", "futures", "git-version", "hex-literal", @@ -1786,8 +1784,6 @@ dependencies = [ "socket-factory", "tokio", "tracing", - "tracing-log", - "tracing-subscriber", "tun", "uuid", "windows 0.57.0", @@ -1813,6 +1809,7 @@ dependencies = [ "domain", "either", "firezone-bin-shared", + "firezone-logging", "firezone-tunnel", "futures", "futures-bounded", @@ -1849,6 +1846,7 @@ dependencies = [ "dirs", "firezone-bin-shared", "firezone-headless-client", + "firezone-logging", "futures", "hex", "keyring", @@ -1897,6 +1895,7 @@ dependencies = [ "connlib-shared", "dirs", "firezone-bin-shared", + "firezone-logging", "futures", "humantime", "ip_network", @@ -1926,6 +1925,18 @@ dependencies = [ "winreg 0.52.0", ] +[[package]] +name = "firezone-logging" +version = "0.1.0" +dependencies = [ + "time", + "tracing", + "tracing-appender", + "tracing-log", + "tracing-stackdriver", + "tracing-subscriber", +] + [[package]] name = "firezone-relay" version = "0.1.0" @@ -1981,6 +1992,7 @@ dependencies = [ "connlib-shared", "derivative", "domain", + "firezone-logging", "firezone-relay", "futures", "futures-util", @@ -5501,6 +5513,7 @@ dependencies = [ "boringtun", "bytecodec", "bytes", + "firezone-logging", "hex", "hex-display", "ip-packet", @@ -5511,7 +5524,6 @@ dependencies = [ "stun_codec", "thiserror", "tracing", - "tracing-subscriber", ] [[package]] @@ -5520,6 +5532,7 @@ version = "0.1.0" dependencies = [ "anyhow", "boringtun", + "firezone-logging", "futures", "hex", "ip-packet", @@ -5535,7 +5548,6 @@ dependencies = [ "system-info", "tokio", "tracing", - "tracing-subscriber", ] [[package]] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 83ef82166..28398c069 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -14,6 +14,7 @@ members = [ "http-health-check", "http-test-server", "ip-packet", + "logging", "phoenix-channel", "relay", "snownet-tests", @@ -47,6 +48,7 @@ connlib-client-shared = { path = "connlib/clients/shared" } firezone-gateway = { path = "gateway" } firezone-headless-client = { path = "headless-client" } firezone-gui-client = { path = "gui-client/src-tauri" } +firezone-logging = { path = "logging" } firezone-bin-shared = { path = "bin-shared" } snownet = { path = "connlib/snownet" } firezone-relay = { path = "relay" } diff --git a/rust/bin-shared/Cargo.toml b/rust/bin-shared/Cargo.toml index 3c6ff1c1e..808500902 100644 --- a/rust/bin-shared/Cargo.toml +++ b/rust/bin-shared/Cargo.toml @@ -14,11 +14,10 @@ ip_network = { version = "0.4", default-features = false, features = ["serde"] } socket-factory = { workspace = true } tokio = { workspace = true, features = ["rt", "sync"] } tracing = { workspace = true } -tracing-log = "0.2" -tracing-subscriber = { workspace = true, features = ["env-filter"] } tun = { workspace = true } [dev-dependencies] +firezone-logging = { workspace = true } hex-literal = "0.4.1" tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/rust/bin-shared/benches/tunnel.rs b/rust/bin-shared/benches/tunnel.rs index dcfd8541c..7e9ef20bd 100644 --- a/rust/bin-shared/benches/tunnel.rs +++ b/rust/bin-shared/benches/tunnel.rs @@ -1,11 +1,8 @@ use anyhow::Result; -use tracing_subscriber::EnvFilter; fn main() -> Result<()> { - let _ = tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env()) - .with_test_writer() - .try_init(); + let _guard = firezone_logging::test("debug"); + let rt = tokio::runtime::Runtime::new()?; rt.block_on(platform::perf())?; Ok(()) diff --git a/rust/bin-shared/src/lib.rs b/rust/bin-shared/src/lib.rs index ac5ae2c49..4a9640c13 100644 --- a/rust/bin-shared/src/lib.rs +++ b/rust/bin-shared/src/lib.rs @@ -13,11 +13,6 @@ pub mod windows; #[cfg(target_os = "windows")] pub use windows as platform; -use tracing_log::LogTracer; -use tracing_subscriber::{ - fmt, prelude::__tracing_subscriber_SubscriberExt, EnvFilter, Layer, Registry, -}; - /// Output of `git describe` at compile time /// e.g. `1.0.0-pre.4-20-ged5437c88-modified` where: /// @@ -59,14 +54,3 @@ pub use network_changes::{new_dns_notifier, new_network_notifier}; #[cfg(any(target_os = "linux", target_os = "windows"))] pub use tun_device_manager::TunDeviceManager; - -pub fn setup_global_subscriber(additional_layer: L) -where - L: Layer + Send + Sync, -{ - let subscriber = Registry::default() - .with(additional_layer.with_filter(EnvFilter::from_default_env())) - .with(fmt::layer().with_filter(EnvFilter::from_default_env())); - tracing::subscriber::set_global_default(subscriber).expect("Could not set global default"); - LogTracer::init().unwrap(); -} diff --git a/rust/bin-shared/src/tun_device_manager.rs b/rust/bin-shared/src/tun_device_manager.rs index de5b2d2c6..ef2305883 100644 --- a/rust/bin-shared/src/tun_device_manager.rs +++ b/rust/bin-shared/src/tun_device_manager.rs @@ -24,15 +24,11 @@ mod tests { net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4}, time::Duration, }; - use tracing_subscriber::EnvFilter; #[tokio::test] #[ignore = "Needs admin / sudo and Internet"] async fn tunnel() { - let _ = tracing_subscriber::fmt() - .with_env_filter(EnvFilter::from_default_env()) - .with_test_writer() - .try_init(); + let _guard = firezone_logging::test("debug"); no_packet_loops().await; tunnel_drop(); diff --git a/rust/connlib/clients/android/Cargo.toml b/rust/connlib/clients/android/Cargo.toml index a51601bbb..afe7f1410 100644 --- a/rust/connlib/clients/android/Cargo.toml +++ b/rust/connlib/clients/android/Cargo.toml @@ -16,6 +16,7 @@ mock = ["connlib-client-shared/mock"] backoff = "0.4.0" connlib-client-shared = { workspace = true } connlib-shared = { workspace = true } +firezone-logging = { workspace = true } ip_network = "0.4" jni = { version = "0.21.1", features = ["invocation"] } libc = "0.2" diff --git a/rust/connlib/clients/android/src/lib.rs b/rust/connlib/clients/android/src/lib.rs index 75f51fffe..03cbf4d88 100644 --- a/rust/connlib/clients/android/src/lib.rs +++ b/rust/connlib/clients/android/src/lib.rs @@ -6,7 +6,7 @@ use crate::tun::Tun; use backoff::ExponentialBackoffBuilder; use connlib_client_shared::{ - callbacks::ResourceDescription, file_logger, keypair, Callbacks, ConnectArgs, Error, LoginUrl, + callbacks::ResourceDescription, keypair, Callbacks, ConnectArgs, Error, LoginUrl, LoginUrlError, Session, V4RouteList, V6RouteList, }; use connlib_shared::{get_user_agent, messages::ResourceId}; @@ -30,7 +30,6 @@ use std::{sync::OnceLock, time::Duration}; use thiserror::Error; use tokio::runtime::Runtime; use tracing_subscriber::prelude::*; -use tracing_subscriber::EnvFilter; mod make_writer; mod tun; @@ -43,7 +42,7 @@ const MAX_PARTITION_TIME: Duration = Duration::from_secs(60 * 60 * 24 * 30); pub struct CallbackHandler { vm: JavaVM, callback_handler: GlobalRef, - handle: file_logger::Handle, + handle: firezone_logging::file::Handle, } impl Clone for CallbackHandler { @@ -118,7 +117,7 @@ fn call_method( .map_err(|source| CallbackError::CallMethodFailed { name, source }) } -fn init_logging(log_dir: &Path, log_filter: String) -> file_logger::Handle { +fn init_logging(log_dir: &Path, log_filter: String) -> firezone_logging::file::Handle { // On Android, logging state is persisted indefinitely after the System.loadLibrary // call, which means that a disconnect and tunnel process restart will not // reinitialize the guard. This is a problem because the guard remains tied to @@ -127,27 +126,27 @@ fn init_logging(log_dir: &Path, log_filter: String) -> file_logger::Handle { // // So we use a static variable to track whether the guard has been initialized and avoid // re-initialized it if so. - static LOGGING_HANDLE: OnceLock = OnceLock::new(); + static LOGGING_HANDLE: OnceLock = OnceLock::new(); if let Some(handle) = LOGGING_HANDLE.get() { return handle.clone(); } - let (file_layer, handle) = file_logger::layer(log_dir); + let (file_layer, handle) = firezone_logging::file::layer(log_dir); LOGGING_HANDLE .set(handle.clone()) .expect("Logging guard should never be initialized twice"); let _ = tracing_subscriber::registry() - .with(file_layer.with_filter(EnvFilter::new(log_filter.clone()))) + .with(file_layer) .with( tracing_subscriber::fmt::layer() .with_ansi(false) .without_time() .with_level(false) - .with_writer(make_writer::MakeWriter::new("connlib")) - .with_filter(EnvFilter::new(log_filter)), + .with_writer(make_writer::MakeWriter::new("connlib")), ) + .with(firezone_logging::filter(&log_filter)) .try_init(); handle diff --git a/rust/connlib/clients/apple/Cargo.toml b/rust/connlib/clients/apple/Cargo.toml index e085ad16c..4bebd8199 100644 --- a/rust/connlib/clients/apple/Cargo.toml +++ b/rust/connlib/clients/apple/Cargo.toml @@ -15,6 +15,7 @@ anyhow = "1.0.86" backoff = "0.4.0" connlib-client-shared = { workspace = true } connlib-shared = { workspace = true } +firezone-logging = { workspace = true } ip_network = "0.4" libc = "0.2" phoenix-channel = { workspace = true } diff --git a/rust/connlib/clients/apple/src/lib.rs b/rust/connlib/clients/apple/src/lib.rs index 528dea26b..7bd4d1fbc 100644 --- a/rust/connlib/clients/apple/src/lib.rs +++ b/rust/connlib/clients/apple/src/lib.rs @@ -7,8 +7,8 @@ mod tun; use anyhow::Result; use backoff::ExponentialBackoffBuilder; use connlib_client_shared::{ - callbacks::ResourceDescription, file_logger, keypair, Callbacks, ConnectArgs, Error, LoginUrl, - Session, V4RouteList, V6RouteList, + callbacks::ResourceDescription, keypair, Callbacks, ConnectArgs, Error, LoginUrl, Session, + V4RouteList, V6RouteList, }; use connlib_shared::get_user_agent; use ip_network::{Ipv4Network, Ipv6Network}; @@ -21,7 +21,6 @@ use std::{ time::Duration, }; use tokio::runtime::Runtime; -use tracing_subscriber::EnvFilter; use tracing_subscriber::{prelude::*, util::TryInitError}; use tun::Tun; @@ -96,7 +95,7 @@ pub struct WrappedSession { runtime: Runtime, #[allow(dead_code)] - logger: file_logger::Handle, + logger: firezone_logging::file::Handle, } // SAFETY: `CallbackHandler.swift` promises to be thread-safe. @@ -146,8 +145,11 @@ impl Callbacks for CallbackHandler { } } -fn init_logging(log_dir: PathBuf, log_filter: String) -> Result { - let (file_layer, handle) = file_logger::layer(&log_dir); +fn init_logging( + log_dir: PathBuf, + log_filter: String, +) -> Result { + let (file_layer, handle) = firezone_logging::file::layer(&log_dir); tracing_subscriber::registry() .with( @@ -158,10 +160,10 @@ fn init_logging(log_dir: PathBuf, log_filter: String) -> Result Result<()> { let cli = Cli::parse(); - setup_global_subscriber(layer::Identity::new()); + firezone_logging::setup_global_subscriber(layer::Identity::new()); let firezone_id = get_firezone_id(cli.firezone_id).await .context("Couldn't read FIREZONE_ID or write it to disk: Please provide it through the env variable or provide rw access to /var/lib/firezone/")?; diff --git a/rust/gui-client/src-tauri/Cargo.toml b/rust/gui-client/src-tauri/Cargo.toml index b1ef4d98a..9a4445740 100644 --- a/rust/gui-client/src-tauri/Cargo.toml +++ b/rust/gui-client/src-tauri/Cargo.toml @@ -22,6 +22,7 @@ connlib-shared = { workspace = true } crash-handler = "0.6.2" firezone-bin-shared = { workspace = true } firezone-headless-client = { path = "../../headless-client" } +firezone-logging = { workspace = true } futures = { version = "0.3", default-features = false } hex = "0.4.3" minidumper = "0.8.2" diff --git a/rust/gui-client/src-tauri/src/client/crash_handling.rs b/rust/gui-client/src-tauri/src/client/crash_handling.rs index 0c8daa4f9..e0ca0e7fc 100755 --- a/rust/gui-client/src-tauri/src/client/crash_handling.rs +++ b/rust/gui-client/src-tauri/src/client/crash_handling.rs @@ -133,9 +133,8 @@ impl minidumper::ServerHandler for Handler { /// created to store it. #[allow(clippy::print_stderr)] fn create_minidump_file(&self) -> Result<(File, PathBuf), std::io::Error> { - let format = - time::format_description::parse(connlib_client_shared::file_logger::TIME_FORMAT) - .expect("static format description should always be parsable"); + let format = time::format_description::parse(firezone_logging::file::TIME_FORMAT) + .expect("static format description should always be parsable"); let date = self .start_time .format(&format) diff --git a/rust/gui-client/src-tauri/src/client/gui.rs b/rust/gui-client/src-tauri/src/client/gui.rs index d8600fb18..48bab7dee 100644 --- a/rust/gui-client/src-tauri/src/client/gui.rs +++ b/rust/gui-client/src-tauri/src/client/gui.rs @@ -522,8 +522,7 @@ impl Controller { async fn handle_request(&mut self, req: ControllerRequest) -> Result<(), Error> { match req { Req::ApplySettings(settings) => { - let filter = - tracing_subscriber::EnvFilter::try_new(&self.advanced_settings.log_filter) + let filter = firezone_logging::try_filter(&self.advanced_settings.log_filter) .context("Couldn't parse new log filter directives")?; self.advanced_settings = settings; self.log_filter_reloader diff --git a/rust/gui-client/src-tauri/src/client/logging.rs b/rust/gui-client/src-tauri/src/client/logging.rs index 586c75f11..7c9060616 100644 --- a/rust/gui-client/src-tauri/src/client/logging.rs +++ b/rust/gui-client/src-tauri/src/client/logging.rs @@ -2,7 +2,6 @@ use crate::client::gui::{ControllerRequest, CtlrTx, Managed}; use anyhow::{bail, Context, Result}; -use connlib_client_shared::file_logger; use firezone_headless_client::known_dirs; use serde::Serialize; use std::{ @@ -20,7 +19,7 @@ use tracing_subscriber::{fmt, layer::SubscriberExt, reload, EnvFilter, Layer, Re /// resulting in empty log files. #[must_use] pub(crate) struct Handles { - pub logger: file_logger::Handle, + pub logger: firezone_logging::file::Handle, pub reloader: Reloader, } @@ -58,9 +57,9 @@ pub(crate) fn setup(directives: &str) -> Result { let log_path = known_dirs::logs().context("Can't compute app log dir")?; std::fs::create_dir_all(&log_path).map_err(Error::CreateDirAll)?; - let (layer, logger) = file_logger::layer(&log_path); + let (layer, logger) = firezone_logging::file::layer(&log_path); let layer = layer.and_then(fmt::layer()); - let (filter, reloader) = reload::Layer::new(EnvFilter::try_new(directives)?); + let (filter, reloader) = reload::Layer::new(firezone_logging::try_filter(directives)?); let subscriber = Registry::default().with(layer.with_filter(filter)); set_global_default(subscriber)?; if let Err(error) = output_vt100::try_init() { diff --git a/rust/headless-client/Cargo.toml b/rust/headless-client/Cargo.toml index a080d8823..b4bd0d725 100644 --- a/rust/headless-client/Cargo.toml +++ b/rust/headless-client/Cargo.toml @@ -14,6 +14,7 @@ clap = { version = "4.5", features = ["derive", "env", "string"] } connlib-client-shared = { workspace = true } connlib-shared = { workspace = true } firezone-bin-shared = { workspace = true } +firezone-logging = { workspace = true } futures = "0.3.30" humantime = "2.1" ip_network = { version = "0.4", default-features = false } diff --git a/rust/headless-client/src/ipc_service.rs b/rust/headless-client/src/ipc_service.rs index f21852ab8..759e182a5 100644 --- a/rust/headless-client/src/ipc_service.rs +++ b/rust/headless-client/src/ipc_service.rs @@ -4,7 +4,7 @@ use crate::{ }; use anyhow::{Context as _, Result}; use clap::Parser; -use connlib_client_shared::{file_logger, keypair, ConnectArgs, LoginUrl, Session}; +use connlib_client_shared::{keypair, ConnectArgs, LoginUrl, Session}; use firezone_bin_shared::{ platform::{tcp_socket_factory, udp_socket_factory, DnsControlMethod}, TunDeviceManager, TOKEN_ENV_KEY, @@ -403,7 +403,7 @@ impl<'a> Handler<'a> { /// /// Returns: A `Handle` that must be kept alive. Dropping it stops logging /// and flushes the log file. -fn setup_logging(log_dir: Option) -> Result { +fn setup_logging(log_dir: Option) -> Result { // If `log_dir` is Some, use that. Else call `ipc_service_logs` let log_dir = log_dir.map_or_else( || known_dirs::ipc_service_logs().context("Should be able to compute IPC service logs dir"), @@ -411,9 +411,9 @@ fn setup_logging(log_dir: Option) -> Result Result<()> { - let _ = tracing_subscriber::fmt().with_test_writer().try_init(); + let _guard = firezone_logging::test("trace"); const ID: ServiceId = ServiceId::Test("H56FRXVH"); if super::connect_to_service(ID).await.is_ok() { @@ -190,7 +190,7 @@ mod tests { /// Make sure the IPC client and server can exchange messages #[tokio::test] async fn smoke() -> Result<()> { - let _ = tracing_subscriber::fmt().with_test_writer().try_init(); + let _guard = firezone_logging::test("trace"); let loops = 10; const ID: ServiceId = ServiceId::Test("OB5SZCGN"); @@ -265,7 +265,7 @@ mod tests { /// this test will fail. #[tokio::test] async fn loop_to_next_client() -> Result<()> { - let _ = tracing_subscriber::fmt().with_test_writer().try_init(); + let _guard = firezone_logging::test("trace"); let mut server = Server::new(ServiceId::Test("H6L73DG5")).await?; for i in 0..5 { diff --git a/rust/headless-client/src/ipc_service/ipc/windows.rs b/rust/headless-client/src/ipc_service/ipc/windows.rs index aa195843c..52aa507fe 100644 --- a/rust/headless-client/src/ipc_service/ipc/windows.rs +++ b/rust/headless-client/src/ipc_service/ipc/windows.rs @@ -196,7 +196,7 @@ mod tests { #[tokio::test] async fn single_instance() -> anyhow::Result<()> { - let _ = tracing_subscriber::fmt().with_test_writer().try_init(); + let _guard = firezone_logging::test("trace"); const ID: ServiceId = ServiceId::Test("2GOCMPBG"); let mut server_1 = Server::new(ID).await?; let pipe_path = server_1.pipe_path.clone(); diff --git a/rust/headless-client/src/ipc_service/windows.rs b/rust/headless-client/src/ipc_service/windows.rs index 8902b3455..4ec0c26bb 100644 --- a/rust/headless-client/src/ipc_service/windows.rs +++ b/rust/headless-client/src/ipc_service/windows.rs @@ -1,6 +1,5 @@ use crate::CliCommon; use anyhow::{bail, Context as _, Result}; -use connlib_client_shared::file_logger; use firezone_bin_shared::platform::DnsControlMethod; use futures::future::{self, Either}; use std::{ffi::OsString, pin::pin, time::Duration}; @@ -74,7 +73,7 @@ fn service_run(arguments: Vec) { // If Windows stops us gracefully, this function may never return. fn fallible_service_run( arguments: Vec, - logging_handle: file_logger::Handle, + logging_handle: firezone_logging::file::Handle, ) -> Result<()> { tracing::info!(?arguments, "fallible_windows_service_run"); diff --git a/rust/headless-client/src/main.rs b/rust/headless-client/src/main.rs index e088ac9eb..7d22eedfe 100644 --- a/rust/headless-client/src/main.rs +++ b/rust/headless-client/src/main.rs @@ -3,12 +3,12 @@ use anyhow::{anyhow, Context as _, Result}; use backoff::ExponentialBackoffBuilder; use clap::Parser; -use connlib_client_shared::{file_logger, keypair, ConnectArgs, LoginUrl, Session}; +use connlib_client_shared::{keypair, ConnectArgs, LoginUrl, Session}; use connlib_shared::{get_user_agent, DEFAULT_MTU}; use firezone_bin_shared::{ new_dns_notifier, new_network_notifier, platform::{tcp_socket_factory, udp_socket_factory}, - setup_global_subscriber, TunDeviceManager, TOKEN_ENV_KEY, + TunDeviceManager, TOKEN_ENV_KEY, }; use firezone_headless_client::{ device_id, signals, CallbackHandler, CliCommon, DnsController, InternalServerMsg, IpcServerMsg, @@ -128,9 +128,9 @@ fn main() -> Result<()> { .common .log_dir .as_deref() - .map(file_logger::layer) + .map(firezone_logging::file::layer) .unzip(); - setup_global_subscriber(layer); + firezone_logging::setup_global_subscriber(layer); tracing::info!( arch = std::env::consts::ARCH, diff --git a/rust/logging/Cargo.toml b/rust/logging/Cargo.toml new file mode 100644 index 000000000..6b42b9f1b --- /dev/null +++ b/rust/logging/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "firezone-logging" +version = "0.1.0" +edition = "2021" +authors = ["Firezone, Inc."] +publish = false +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +time = { version = "0.3.36", features = ["formatting"] } +tracing = { workspace = true } +tracing-appender = { version = "0.2.2" } +tracing-log = "0.2" +tracing-stackdriver = { version = "0.11.0" } +tracing-subscriber = { workspace = true, features = ["env-filter"] } + +[lints] +workspace = true diff --git a/rust/connlib/clients/shared/src/file_logger.rs b/rust/logging/src/file.rs similarity index 100% rename from rust/connlib/clients/shared/src/file_logger.rs rename to rust/logging/src/file.rs diff --git a/rust/logging/src/lib.rs b/rust/logging/src/lib.rs new file mode 100644 index 000000000..b3768660c --- /dev/null +++ b/rust/logging/src/lib.rs @@ -0,0 +1,51 @@ +pub mod file; + +use tracing::subscriber::DefaultGuard; +use tracing_log::LogTracer; +use tracing_subscriber::{ + filter::ParseError, fmt, layer::SubscriberExt as _, util::SubscriberInitExt, EnvFilter, Layer, + Registry, +}; + +/// Registers a global subscriber with stdout logging and `additional_layer` +pub fn setup_global_subscriber(additional_layer: L) +where + L: Layer + Send + Sync, +{ + let directives = std::env::var("RUST_LOG").unwrap_or_default(); + + let subscriber = Registry::default() + .with(additional_layer) + .with(fmt::layer()) + .with(filter(&directives)); + tracing::subscriber::set_global_default(subscriber).expect("Could not set global default"); + LogTracer::init().unwrap(); +} + +/// Constructs an opinionated [`EnvFilter`] with some crates already silenced. +pub fn filter(directives: &str) -> EnvFilter { + try_filter(directives).unwrap() +} + +/// Constructs an opinionated [`EnvFilter`] with some crates already silenced. +pub fn try_filter(directives: &str) -> Result { + /// A filter directive that silences noisy crates. + /// + /// For debugging, it is useful to set a catch-all log like `debug`. + /// This obviously creates a lot of logs from all kinds of crates. + /// For our usecase, logs from `netlink_proto` and other crates are very likely not what you want to see. + /// + /// By prepending this directive to the active log filter, a simple directive like `debug` actually produces useful logs. + /// If necessary, you can still activate logs from these crates by restating them in your directive with a lower filter, i.e. `netlink_proto=debug`. + const IRRELEVANT_CRATES: &str = "netlink_proto=warn,os_info=warn,rustls=warn"; + + EnvFilter::try_new(format!("{IRRELEVANT_CRATES},{directives}")) +} + +/// Initialises a logger to be used in tests. +pub fn test(directives: &str) -> DefaultGuard { + tracing_subscriber::fmt() + .with_test_writer() + .with_env_filter(directives) + .set_default() +} diff --git a/rust/relay/src/main.rs b/rust/relay/src/main.rs index 89a091b2e..26b3abd19 100644 --- a/rust/relay/src/main.rs +++ b/rust/relay/src/main.rs @@ -185,7 +185,8 @@ fn setup_tracing(args: &Args) -> Result<()> { let dispatch: Dispatch = match args.otlp_grpc_endpoint.clone() { None => tracing_subscriber::registry() - .with(log_layer(args).with_filter(env_filter())) + .with(log_layer(args)) + .with(env_filter()) .into(), Some(endpoint) => { let grpc_endpoint = format!("http://{endpoint}"); @@ -223,12 +224,9 @@ fn setup_tracing(args: &Args) -> Result<()> { tracing::trace!(target: "relay", "Successfully initialized metric provider on tokio runtime"); tracing_subscriber::registry() - .with(log_layer(args).with_filter(env_filter())) - .with( - tracing_opentelemetry::layer() - .with_tracer(tracer_provider.tracer("relay")) - .with_filter(env_filter()), - ) + .with(log_layer(args)) + .with(tracing_opentelemetry::layer().with_tracer(tracer_provider.tracer("relay"))) + .with(env_filter()) .into() } }; diff --git a/rust/snownet-tests/Cargo.toml b/rust/snownet-tests/Cargo.toml index fab191900..f125154e3 100644 --- a/rust/snownet-tests/Cargo.toml +++ b/rust/snownet-tests/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] anyhow = "1" boringtun = { workspace = true } +firezone-logging = { workspace = true } futures = "0.3" hex = "0.4" ip-packet = { workspace = true } @@ -21,7 +22,6 @@ snownet = { workspace = true } system-info = { version = "0.1.2", features = ["std"] } tokio = { workspace = true, features = ["full"] } tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] } [lints] workspace = true diff --git a/rust/snownet-tests/src/main.rs b/rust/snownet-tests/src/main.rs index 89181527b..edb6e9564 100644 --- a/rust/snownet-tests/src/main.rs +++ b/rust/snownet-tests/src/main.rs @@ -16,18 +16,13 @@ use redis::{aio::MultiplexedConnection, AsyncCommands}; use secrecy::{ExposeSecret as _, Secret}; use snownet::{Answer, ClientNode, Credentials, Node, Offer, RelaySocket, ServerNode}; use tokio::{io::ReadBuf, net::UdpSocket}; -use tracing_subscriber::EnvFilter; const MAX_UDP_SIZE: usize = (1 << 16) - 1; #[tokio::main] async fn main() -> Result<()> { - tracing_subscriber::fmt() - .with_env_filter( - EnvFilter::builder() - .parse("info,boringtun=debug,str0m=debug,boringtun=debug,snownet=debug")?, - ) - .init(); + let _guard = + firezone_logging::test("info,boringtun=debug,str0m=debug,boringtun=debug,snownet=debug"); let role = std::env::var("ROLE") .context("Missing ROLE env variable")?