extern crate time;
use std::sync::{Arc, Mutex, MutexGuard, PoisonError, Once, ONCE_INIT};
use std::io::Write;
#[macro_export]
macro_rules! timber {
($lnum:expr, $lname:expr, $($arg:tt)*) => {
if $lnum > 0 {
$crate::timber($lname, module_path!(), line!(), format_args!($($arg)*))
}
};
}
pub struct Timber {
log_file: Option<std::fs::File>,
}
struct Wrapper {
inner: Arc<Mutex<Timber>>,
}
impl Timber {
pub fn log(&mut self, args: std::fmt::Arguments) {
match self.log_file {
Some(ref mut log_file) => {
log_file.write(format!("{}", args).as_bytes()).expect("Failed to log!");
}
None => {
print!("{}", args);
}
}
}
pub fn timber(&mut self, level: &str, module: &str, line: u32, args: std::fmt::Arguments) {
let tm = time::now().to_local();
let current_thread = std::thread::current();
let thread = current_thread.name().unwrap_or("<unknown>");
let entry = format!("{:02}:{:02}:{:02}.{:06} | {} | {:16} | {:4} | {:40} | {}",
tm.tm_hour,
tm.tm_min,
tm.tm_sec,
tm.tm_nsec / 1000,
level,
thread,
line,
module,
args);
match self.log_file {
Some(ref mut log_file) => {
log_file.write(entry.as_bytes()).expect("Failed to timber!");
log_file.write("\n".as_bytes()).expect("Failed to timber!");
}
None => {
println!("{}", entry);
}
}
}
pub fn init(&mut self, path: &std::path::Path) -> Result<(), std::io::Error> {
self.log_file = Some(std::fs::File::create(path)?);
Ok(())
}
}
fn get_instance() -> &'static Wrapper {
static mut LOGGER: *const Wrapper = 0 as *const Wrapper;
static ONCE: Once = ONCE_INIT;
unsafe {
ONCE.call_once(|| {
let logger = Wrapper { inner: Arc::new(Mutex::new(Timber { log_file: None })) };
LOGGER = std::mem::transmute(Box::new(logger));
});
&(*LOGGER)
}
}
pub fn lock<'a>() -> Result<MutexGuard<'a, Timber>, PoisonError<MutexGuard<'a, Timber>>> {
get_instance().inner.lock()
}
pub fn timber(level: &str, module: &str, line: u32, args: std::fmt::Arguments) {
let mut timber = get_instance().inner.lock().unwrap();
timber.timber(level, module, line, args);
}
pub fn init(path: &std::path::Path) -> Result<(), std::io::Error> {
let mut timber = get_instance().inner.lock().unwrap();
timber.init(path)
}