#[cfg(not(feature = "tracy"))] use std::fs; use std::path::Path; use termcolor::{ColorChoice, StandardStream}; use tracing::info; use tracing_appender::non_blocking::WorkerGuard; use tracing_subscriber::{ filter::LevelFilter, fmt::writer::MakeWriter, prelude::*, registry, EnvFilter, }; const RUST_LOG_ENV: &str = "RUST_LOG"; /// Initialise tracing and logging for the logs_path. /// /// This function will attempt to set up both a file and a terminal logger, /// falling back to just a terminal logger if the file is unable to be created. /// /// The logging level is by default set to `INFO`, to change this for any /// particular crate or module you must use the `RUST_LOG` environment /// variable. /// /// For example to set this crate's debug level to `TRACE` you would need the /// following in your environment. /// `RUST_LOG="veloren_voxygen=trace"` /// /// more complex tracing can be done by concatenating with a `,` as seperator: /// - warn for `prometheus_hyper`, `dot_vox`, `gfx_device_gl::factory, /// `gfx_device_gl::shade` trace for `veloren_voxygen`, info for everything /// else /// `RUST_LOG="prometheus_hyper=warn,dot_vox::parser=warn,gfx_device_gl:: /// factory=warn,gfx_device_gl::shade=warn,veloren_voxygen=trace,info"` /// /// By default a few directives are set to `warn` by default, until explicitly /// overwritten! e.g. `RUST_LOG="gfx_device_gl=debug"` pub fn init(log_path_file: Option<(&Path, &str)>, terminal: W2) -> Vec where W2: MakeWriter + 'static, ::Writer: Send + Sync, { // To hold the guards that we create, they will cause the logs to be // flushed when they're dropped. let mut _guards: Vec = vec![]; // We will do lower logging than the default (INFO) by INCLUSION. This // means that if you need lower level logging for a specific module, then // put it in the environment in the correct format i.e. DEBUG logging for // this crate would be veloren_voxygen=debug. let base_exceptions = |env: EnvFilter| { env.add_directive("dot_vox::parser=warn".parse().unwrap()) .add_directive("veloren_common::trade=info".parse().unwrap()) .add_directive("veloren_world::sim=info".parse().unwrap()) .add_directive("veloren_world::civ=info".parse().unwrap()) .add_directive("hyper=info".parse().unwrap()) .add_directive("prometheus_hyper=info".parse().unwrap()) .add_directive("mio::pool=info".parse().unwrap()) .add_directive("mio::sys::windows=info".parse().unwrap()) .add_directive("h2=info".parse().unwrap()) .add_directive("tokio_util=info".parse().unwrap()) .add_directive("rustls=info".parse().unwrap()) .add_directive("naga=info".parse().unwrap()) .add_directive("gfx_backend_vulkan=info".parse().unwrap()) .add_directive("wgpu_core=info".parse().unwrap()) .add_directive("wgpu_core::device=warn".parse().unwrap()) .add_directive("veloren_network_protocol=info".parse().unwrap()) .add_directive("quinn_proto::connection=info".parse().unwrap()) .add_directive( "veloren_server::persistence::character=info" .parse() .unwrap(), ) .add_directive("veloren_server::settings=info".parse().unwrap()) .add_directive(LevelFilter::INFO.into()) }; let filter = match std::env::var_os(RUST_LOG_ENV).map(|s| s.into_string()) { Some(Ok(env)) => { let mut filter = base_exceptions(EnvFilter::new("")); for s in env.split(',').into_iter() { match s.parse() { Ok(d) => filter = filter.add_directive(d), Err(err) => println!("WARN ignoring log directive: `{}`: {}", s, err), }; } filter }, _ => base_exceptions(EnvFilter::from_env(RUST_LOG_ENV)), }; let registry = registry(); #[cfg(not(feature = "tracy"))] let mut file_setup = false; #[cfg(feature = "tracy")] let file_setup = false; #[cfg(feature = "tracy")] let _terminal = terminal; // Create the terminal writer layer. #[cfg(feature = "tracy")] let registry = registry.with(tracing_tracy::TracyLayer::new().with_stackdepth(0)); #[cfg(not(feature = "tracy"))] let registry = { let (non_blocking, _stdio_guard) = tracing_appender::non_blocking(terminal.make_writer()); _guards.push(_stdio_guard); registry.with(tracing_subscriber::fmt::layer().with_writer(non_blocking)) }; // Try to create the log file's parent folders. #[cfg(not(feature = "tracy"))] if let Some((path, file)) = log_path_file { match fs::create_dir_all(path) { Ok(_) => { let file_appender = tracing_appender::rolling::daily(path, file); let (non_blocking_file, _file_guard) = tracing_appender::non_blocking(file_appender); _guards.push(_file_guard); file_setup = true; registry .with(tracing_subscriber::fmt::layer().with_writer(non_blocking_file)) .with(filter) .init(); }, Err(e) => { tracing::error!( ?e, "Failed to create log file!. Falling back to terminal logging only.", ); registry.with(filter).init(); }, } } else { registry.with(filter).init(); } #[cfg(feature = "tracy")] registry.with(filter).init(); if file_setup { let (path, file) = log_path_file.unwrap(); info!(?path, ?file, "Setup terminal and file logging."); } if tracing::level_enabled!(tracing::Level::TRACE) { info!("Tracing Level: TRACE"); } else if tracing::level_enabled!(tracing::Level::DEBUG) { info!("Tracing Level: DEBUG"); }; // Return the guards _guards } pub fn init_stdout(log_path_file: Option<(&Path, &str)>) -> Vec { init(log_path_file, || StandardStream::stdout(ColorChoice::Auto)) }