use std::{
fs,
fs::File,
io::{Read, Write},
path::Path,
};
use log4rs::config::RawConfig;
use crate::ConfigError;
pub fn initialize_logging(config_file: &Path, base_path: &Path, default: &str) -> Result<(), ConfigError> {
println!(
"Initializing logging according to {:?}",
config_file.to_str().unwrap_or("[??]")
);
if !config_file.exists() {
if let Some(d) = config_file.parent() {
fs::create_dir_all(d)
.map_err(|e| ConfigError::new("Could not create parent directory for log file", Some(e.to_string())))?
};
let mut file = File::create(config_file)
.map_err(|e| ConfigError::new("Could not create default log file", Some(e.to_string())))?;
file.write_all(default.as_ref())
.map_err(|e| ConfigError::new("Could not create default log file", Some(e.to_string())))?;
}
let mut file =
File::open(config_file).map_err(|e| ConfigError::new("Could not locate file: {}", Some(e.to_string())))?;
let mut contents = String::new();
file.read_to_string(&mut contents)
.map_err(|e| ConfigError::new("Could not read file: {}", Some(e.to_string())))?;
let replace_str = base_path
.to_str()
.expect("Could not replace {{log_dir}} variable from the log4rs config")
.replace('\\', "/");
let contents = contents.replace("{{log_dir}}", &replace_str);
let config: RawConfig =
serde_yaml::from_str(&contents).expect("Could not parse the contents of the log file as yaml");
log4rs::init_raw_config(config).expect("Could not initialize logging");
Ok(())
}
#[macro_export]
macro_rules! log_if_error {
(level:$level:tt, target: $target:expr, $msg:expr, $expr:expr $(,)*) => {{
match $expr {
Ok(v) => Some(v),
Err(err) => {
log::$level!(target: $target, $msg, err);
None
}
}
}};
(level:$level:tt, $msg:expr, $expr:expr $(,)*) => {{
log_if_error!(level:$level, target: "$crate", $msg, $expr)
}};
(target: $target:expr, $msg:expr, $expr:expr $(,)*) => {{
log_if_error!(level:warn, target: $target, $msg, $expr)
}};
($msg:expr, $expr:expr $(,)*) => {{
log_if_error!(level:warn, target: "$crate", $msg, $expr)
}};
}
#[macro_export]
macro_rules! log_if_error_fmt {
(level: $level:tt, target: $target:expr, $msg:expr, $expr:expr, $($args:tt)+) => {{
match $expr {
Ok(v) => Some(v),
Err(_) => {
log::$level!(target: $target, $msg, $($args)+);
None
}
}
}};
}
#[cfg(test)]
mod test {
#[test]
fn log_if_error() {
let err = Result::<(), _>::Err("What a shame");
let opt = log_if_error!("Error: {}", err);
assert!(opt.is_none());
let opt = log_if_error!(level: trace, "Error: {}", err);
assert!(opt.is_none());
let opt = log_if_error!(level: trace, "Error: {}", Result::<_, &str>::Ok("answer"));
assert_eq!(opt, Some("answer"));
}
}