use std::{env, io::stderr}; use color_eyre::{Result, eyre::eyre}; use tracing_error::ErrorLayer; use tracing_subscriber::{EnvFilter, fmt, prelude::*, util::TryInitError}; use crate::console::ProcessMode; lazy_static::lazy_static! { pub static ref LOG_ENV: String = format!("{}_LOG", env!("CARGO_PKG_NAME").to_uppercase()); pub static ref LOG_FILE: String = format!("{}.log", env!("CARGO_PKG_NAME")); } pub fn init(process_mode: ProcessMode) -> Result<()> { // // File initialization // let directory = env::current_dir()?; std::fs::create_dir_all(directory.clone())?; let log_path = directory.join(LOG_FILE.clone()); let log_file = match process_mode { ProcessMode::Console(_) => std::fs::File::open("NUL")?, ProcessMode::Gui => std::fs::File::create(log_path)?, }; // // Filtering // // Stage 1: Construct base filter let env_filter = EnvFilter::builder().with_default_directive( if cfg!(debug_assertions) { tracing::Level::DEBUG } else { 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("egui=info".parse().unwrap()) .add_directive("eframe=info".parse().unwrap()) .add_directive("epaint=info".parse().unwrap()) .add_directive("windows=info".parse().unwrap()); // // Subscription // // Build the subscriber and apply it tracing_subscriber::registry() .with(env_filter) .with( // Logging to file fmt::layer() .with_writer(log_file) .with_target(true) .with_ansi(false), ) .with({ // Logging to stderr let layer = fmt::layer() .with_writer(stderr) .with_timer(tracing_subscriber::fmt::time()) .with_ansi(true); // Enable compact mode for release logs #[cfg(not(debug_assertions))] let layer = layer.compact(); layer }) .with(ErrorLayer::default()) .try_init() .map_err(|err: TryInitError| eyre!(err)) }