feat(log): configurable creation of log file

additionally allows to ignore any errors with the log file

furthermore prints out full log file path to the user incase of a panic
This commit is contained in:
Songtronix 2019-12-18 20:35:17 +01:00
parent 9141cc07d0
commit b03e4ac261
3 changed files with 60 additions and 31 deletions

View File

@ -1,6 +1,12 @@
use fern::colors::{Color, ColoredLevelConfig};
pub fn init(term_log_level: log::LevelFilter, file_log_level: log::LevelFilter) {
use crate::settings::Settings;
pub fn init(
settings: &Settings,
term_log_level: log::LevelFilter,
file_log_level: log::LevelFilter,
) {
let colors = ColoredLevelConfig::new()
.error(Color::Red)
.warn(Color::Yellow)
@ -8,7 +14,7 @@ pub fn init(term_log_level: log::LevelFilter, file_log_level: log::LevelFilter)
.debug(Color::Green)
.trace(Color::BrightBlack);
let base = fern::Dispatch::new()
let mut base = fern::Dispatch::new()
.level_for("dot_vox::parser", log::LevelFilter::Warn)
.level_for("gfx_device_gl::factory", log::LevelFilter::Warn)
.level_for("veloren_voxygen::discord", log::LevelFilter::Warn)
@ -17,25 +23,35 @@ pub fn init(term_log_level: log::LevelFilter, file_log_level: log::LevelFilter)
let time = chrono::offset::Utc::now();
let file_cfg = fern::Dispatch::new()
.level(file_log_level)
.format(|out, message, record| {
out.finish(format_args!(
"{}[{}:{}][{}] {}",
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
record.target(),
record
.line()
.map(|x| x.to_string())
.unwrap_or("X".to_string()),
record.level(),
message
))
})
.chain(
let mut file_cfg =
fern::Dispatch::new()
.level(file_log_level)
.format(|out, message, record| {
out.finish(format_args!(
"{}[{}:{}][{}] {}",
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
record.target(),
record
.line()
.map(|x| x.to_string())
.unwrap_or("X".to_string()),
record.level(),
message
))
});
// Based on settings ignore errors incase log file can't be created
if !settings.log.ignore_errors {
file_cfg = file_cfg.chain(
fern::log_file(&format!("voxygen-{}.log", time.format("%Y-%m-%d-%H")))
.expect("Failed to create log file!"),
);
} else {
if let Ok(log_file) = fern::log_file(&format!("voxygen-{}.log", time.format("%Y-%m-%d-%H")))
{
file_cfg = file_cfg.chain(log_file);
}
}
let stdout_cfg = fern::Dispatch::new()
.level(term_log_level)
@ -48,8 +64,10 @@ pub fn init(term_log_level: log::LevelFilter, file_log_level: log::LevelFilter)
})
.chain(std::io::stdout());
base.chain(file_cfg)
.chain(stdout_cfg)
if settings.log.log_to_file {
base = base.chain(file_cfg);
}
base.chain(stdout_cfg)
.apply()
.expect("Failed to setup logging!");
}

View File

@ -34,7 +34,7 @@ pub mod window;
pub use crate::error::Error;
use crate::{audio::AudioFrontend, menu::main::MainMenuState, settings::Settings, window::Window};
use log::{self, debug, error};
use log::{debug, error};
use std::{mem, panic, str::FromStr};
/// A type used to store state that is shared between all play states.
@ -107,10 +107,13 @@ fn main() {
.and_then(|s| log::LevelFilter::from_str(&s).ok())
.unwrap_or(log::LevelFilter::Debug);
logging::init(term_log_level, file_log_level);
// Load the settings
// Note: This won't log anything due to it being called before ``logging::init``.
// The issue is we need to read a setting to decide whether we create a log file or not.
let settings = Settings::load();
logging::init(&settings, term_log_level, file_log_level);
// Save settings to add new fields or create the file if it is not already there
if let Err(err) = settings.save_to_file() {
panic!("Failed to save settings: {:?}", err);
@ -136,10 +139,7 @@ fn main() {
info_message: None,
};
let settings = &global_state.settings;
// Set up panic handler to relay swish panic messages to the user
let settings_clone = settings.clone();
let default_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| {
let panic_info_payload = panic_info.payload();
@ -186,7 +186,12 @@ fn main() {
\n\
Panic Payload: {:?}\n\
PanicInfo: {}",
settings_clone.log.file, reason, panic_info,
// TODO: Verify that this works
Settings::get_settings_path()
.join("voxygen-<date>.log")
.display(),
reason,
panic_info,
);
error!(

View File

@ -151,17 +151,23 @@ impl Default for NetworkingSettings {
}
}
/// `Log` stores the name to the log file.
/// `Log` stores whether we should create a log file
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct Log {
pub file: PathBuf,
// Whether to create a log file or not.
// Default is to create one.
pub log_to_file: bool,
// Should we ignore errors if we are unable to create the log file
// Default is to panic if log file can't be created.
pub ignore_errors: bool,
}
impl Default for Log {
fn default() -> Self {
Self {
file: "voxygen.log".into(),
log_to_file: true,
ignore_errors: false,
}
}
}
@ -290,7 +296,7 @@ impl Settings {
Ok(())
}
fn get_settings_path() -> PathBuf {
pub fn get_settings_path() -> PathBuf {
if let Some(val) = std::env::var_os("VOXYGEN_CONFIG") {
let settings = PathBuf::from(val).join("settings.ron");
if settings.exists() || settings.parent().map(|x| x.exists()).unwrap_or(false) {