use std::io::stderr; use color_eyre::eyre::eyre; use color_eyre::Result; use tracing_error::ErrorLayer; use tracing_subscriber::prelude::*; use tracing_subscriber::util::TryInitError; use tracing_subscriber::{fmt, EnvFilter}; use crate::config; lazy_static::lazy_static! { pub static ref LOG_ENV: String = format!("{}_LOG", config::PROJECT_NAME.clone()); pub static ref LOG_FILE: String = format!("{}.log", env!("CARGO_PKG_NAME")); } pub fn init() -> Result<()> { // // File initialization // let directory = config::get_data_dir(); std::fs::create_dir_all(directory.clone())?; let log_path = directory.join(LOG_FILE.clone()); let log_file = std::fs::File::create(log_path)?; // // Filtering // // Stage 1: Construct base filter let env_filter = EnvFilter::builder() .with_default_directive(tracing::Level::INFO.into()); // Stage 2: Attempt to read from {RUST|CRATE_NAME}_LOG env var or ignore let env_filter = env_filter.try_from_env().unwrap_or_else(|_| { env_filter.with_env_var(LOG_ENV.to_string()).from_env_lossy() }); // Stage 3: Enable directives to reduce verbosity for release mode builds #[cfg(not(debug_assertions))] let env_filter = env_filter .add_directive("tokio_util=info".parse().unwrap()) .add_directive("futures=info".parse().unwrap()) .add_directive("russh=info".parse().unwrap()) .add_directive("crossterm=info".parse().unwrap()) .add_directive("ratatui=info".parse().unwrap()); // // Subscription // // Build the subscriber and apply it tracing_subscriber::registry() .with(env_filter) .with(ErrorLayer::default()) .with( // Logging to file fmt::layer() .with_file(true) .with_line_number(true) .with_writer(log_file) .with_target(false) .with_ansi(false), ) .with({ // Logging to stderr let layer = fmt::layer() .with_writer(stderr) .with_timer(tracing_subscriber::fmt::time()) .with_thread_ids(true) .with_ansi(true); // Enable compact mode for release logs #[cfg(not(debug_assertions))] let layer = layer .compact() .without_time() .with_span_events( tracing_subscriber::fmt::format::FmtSpan::NONE, ) .with_target(false) .with_thread_ids(false); layer }) .try_init() .map_err(|err: TryInitError| eyre!(err)) }