use log::{
self,
LogRecord,
LogLevelFilter,
LogMetadata,
SetLoggerError
};
use std::io::prelude::*;
use std::fs::{File,OpenOptions};
use std::io::BufWriter;
use std::ops::DerefMut;
use std::path::PathBuf;
use std::sync::RwLock;
use time;
pub struct FileLogger {
rwlck: RwLock<BufWriter<File>>
}
impl FileLogger {
pub fn new(path: PathBuf) -> FileLogger {
let mut opts = OpenOptions::new();
opts.create(true);
opts.write(true);
opts.append(true);
let file = match opts.open(&path) {
Ok(f) => f,
Err(e) => panic!("Unable to use file for logging! {}", e),
};
FileLogger {
rwlck: RwLock::new(BufWriter::new(file))
}
}
}
impl log::Log for FileLogger {
fn enabled(&self, _: &LogMetadata) -> bool {
true
}
fn log(&self, record: &LogRecord) {
if self.enabled(record.metadata()) {
match self.rwlck.write() {
Ok(ref mut w) => {
let mut bw = w.deref_mut();
let now = time::now();
bw.write_fmt(format_args!("{} {:5} {:4} -- {}: {}\n",
now.rfc3339(),
record.level(),
record.location().line(),
record.location().module_path(),
record.args()))
.and(bw.flush()).unwrap();
},
Err(e) => {
println!("Unable to acquire write lock! {:?}", e);
},
}
}
}
}
pub fn init_file_logger(level: LogLevelFilter,
path: PathBuf) -> Result<(), SetLoggerError> {
log::set_logger(|max_log_level| {
max_log_level.set(level);
Box::new(FileLogger::new(path))
})
}