use std::fs; use crate::settings::Settings; use tracing::{debug, error, info, trace}; use tracing_subscriber::{filter::LevelFilter, prelude::*, registry, EnvFilter}; const RUST_LOG_ENV: &str = "RUST_LOG"; /// Initialise tracing and logging for the settings. /// /// 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 `uvth`, `tiny_http`, `dot_vox`, `gfx_device_gl::factory, /// `gfx_device_gl::shade` trace for `veloren_voxygen`, info for everything /// else /// `RUST_LOG="uvth=warn,tiny_http=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="uvth=debug"` pub fn init(settings: &Settings) -> Vec { // To hold the guards that we create, they will cause the logs to be // flushed when they're dropped. let mut _guards = 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("gfx_device_gl=warn".parse().unwrap()) .add_directive("uvth=warn".parse().unwrap()) .add_directive("tiny_http=warn".parse().unwrap()) .add_directive("mio::sys::windows=debug".parse().unwrap()) .add_directive( "veloren_server::persistence::character=info" .parse() .unwrap(), ) .add_directive(LevelFilter::INFO.into()) }; #[cfg(not(feature = "tracy"))] 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)), }; #[cfg(feature = "tracy")] let filter = base_exceptions(EnvFilter::new("")).add_directive(LevelFilter::TRACE.into()); // Create the terminal writer layer. let (non_blocking, _stdio_guard) = tracing_appender::non_blocking(std::io::stdout()); _guards.push(_stdio_guard); // Try to create the log file's parent folders. let log_folders_created = fs::create_dir_all(&settings.log.logs_path); const LOG_FILENAME: &str = "voxygen.log"; match log_folders_created { // If the parent folders were created then attach both a terminal and a // file writer to the registry and init it. Ok(_) => { let file_appender = tracing_appender::rolling::daily(&settings.log.logs_path, LOG_FILENAME); let (non_blocking_file, _file_guard) = tracing_appender::non_blocking(file_appender); _guards.push(_file_guard); #[cfg(not(feature = "tracy"))] registry() .with(tracing_subscriber::fmt::layer().with_writer(non_blocking)) .with(tracing_subscriber::fmt::layer().with_writer(non_blocking_file)) .with(filter) .init(); #[cfg(feature = "tracy")] registry() // NOTE: collecting stacks has a significant overhead (x6 overhead of // starting/stopping a span through the layer interface) .with(tracing_tracy::TracyLayer::new().with_stackdepth(0)) .with(filter) .init(); let logdir = &settings.log.logs_path; info!(?logdir, "Setup terminal and file logging."); }, // Otherwise just add a terminal writer and init it. Err(e) => { error!( ?e, "Failed to create log file!. Falling back to terminal logging only.", ); #[cfg(not(feature = "tracy"))] registry() .with(tracing_subscriber::fmt::layer().with_writer(non_blocking)) .with(filter); #[cfg(feature = "tracy")] registry() .with(tracing_tracy::TracyLayer::new().with_stackdepth(0)) .with(filter) .init(); info!("Setup terminal logging."); }, }; debug!("Tracing is successfully set to DEBUG or TRACE"); trace!("Tracing is successfully set to TRACE"); // Return the guards _guards }