use std::{ffi::CStr, os::raw::c_char, path::Path};
pub use log::{LevelFilter, debug, error, info, log, trace, warn};
use log4rs::{
append::file::FileAppender,
config::{Appender, Config, Root},
encode::pattern::PatternEncoder,
};
pub const DEFAULT_PATTERN: &str = "{M} - {l} - {m}{n}";
pub const BARE_PATTERN: &str = "{m}{n}";
pub fn init_file(state_dir: *const c_char, name: &str, level: i32) {
init_file_with(state_dir, name, level, DEFAULT_PATTERN);
}
pub fn init_file_with(state_dir: *const c_char, name: &str, level: i32, pattern: &str) {
if let Err(e) = try_install(state_dir, name, level, pattern) {
eprintln!("{name}: log init failed: {e}");
}
}
fn try_install(
state_dir: *const c_char,
name: &str,
level: i32,
pattern: &str,
) -> anyhow::Result<()> {
if state_dir.is_null() {
anyhow::bail!("no state directory");
}
let dir = unsafe { CStr::from_ptr(state_dir) }
.to_string_lossy()
.into_owned();
let path = Path::new(&dir).join(format!("{name}.log"));
let appender = FileAppender::builder()
.encoder(Box::new(PatternEncoder::new(pattern)))
.append(true)
.build(&path)?;
let config = Config::builder()
.appender(Appender::builder().build("logfile", Box::new(appender)))
.build(Root::builder().appender("logfile").build(level_of(level)))?;
let _ = log4rs::init_config(config);
Ok(())
}
fn level_of(level: i32) -> LevelFilter {
match level {
..=0 => LevelFilter::Off,
1 => LevelFilter::Error,
2 => LevelFilter::Warn,
3 => LevelFilter::Info,
4 => LevelFilter::Debug,
5.. => LevelFilter::Trace,
}
}