extern crate ansi_term;
use ansi_term::Colour;
use std::collections::HashMap;
use std::fs::File;
use std::io::{self, Write};
use std::sync::{Arc, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};
#[derive(PartialEq, PartialOrd, Clone, Copy)]
pub enum Level {
DEBUG,
INFO,
WARN,
ERROR,
FATAL,
NONE,
}
pub struct Message {
level: Level,
name: String,
created: SystemTime,
msg: String,
}
pub trait Handler: Send + Sync {
fn emit(&self, message: &Message);
}
pub struct ConsoleHandler {}
impl ConsoleHandler {
pub fn new() -> Arc<Box<Handler>> {
Arc::new(Box::new(ConsoleHandler {}))
}
}
impl Handler for ConsoleHandler {
fn emit(&self, message: &Message) {
let data = match message.level {
Level::DEBUG => Colour::Cyan.paint(format!("{} | {}\n", message.name, message.msg)),
Level::INFO => Colour::Green.paint(format!("{} | {}\n", message.name, message.msg)),
Level::WARN => Colour::Yellow.paint(format!("{} | {}\n", message.name, message.msg)),
Level::ERROR => Colour::Red.paint(format!("{} | {}\n", message.name, message.msg)),
Level::FATAL => Colour::Red.paint(format!("{} | {}\n", message.name, message.msg)),
Level::NONE => Colour::White.paint(""),
};
let stdout = io::stdout();
let mut handle = stdout.lock();
handle.write(data.to_string().as_bytes()).unwrap();
handle.flush().unwrap();
}
}
pub struct FileHandler {
out: Arc<RwLock<File>>,
}
impl FileHandler {
pub fn new(filename: &str) -> Arc<Box<Handler>> {
Arc::new(Box::new(FileHandler {
out: Arc::new(RwLock::new(File::create(filename).unwrap())),
}))
}
}
impl Handler for FileHandler {
fn emit(&self, message: &Message) {
let dur = message.created.duration_since(UNIX_EPOCH).unwrap();
let data = match message.level {
Level::DEBUG => {
format!(
"{:9}.{:0.09} | DEBUG | {:15} | {}\n",
dur.as_secs(),
dur.subsec_nanos(),
message.name,
message.msg
)
}
Level::INFO => {
format!(
"{:9}.{:0.09} | INFO | {:15} | {}\n",
dur.as_secs(),
dur.subsec_nanos(),
message.name,
message.msg
)
}
Level::WARN => {
format!(
"{:9}.{:0.09} | WARN | {:15} | {}\n",
dur.as_secs(),
dur.subsec_nanos(),
message.name,
message.msg
)
}
Level::ERROR => {
format!(
"{:9}.{:0.09} | ERROR | {:15} | {}\n",
dur.as_secs(),
dur.subsec_nanos(),
message.name,
message.msg
)
}
Level::FATAL => {
format!(
"{:9}.{:0.09} | FATAL | {:15} | {}\n",
dur.as_secs(),
dur.subsec_nanos(),
message.name,
message.msg
)
}
Level::NONE => "".to_string(),
};
let mut out = self.out.write().unwrap();
out.write(data.as_bytes()).unwrap();
out.flush().unwrap();
}
}
#[derive(Clone)]
pub struct _Logger {
_name: String,
_full_name: String,
pub level: Level,
_parent: Option<Arc<_Logger>>,
_handlers: Arc<RwLock<Vec<Arc<Box<Handler>>>>>,
_children: Arc<RwLock<HashMap<String, Arc<_Logger>>>>,
}
impl _Logger {
pub fn add_handler(&self, handler: Arc<Box<Handler>>) {
let mut hs = self._handlers.write().unwrap();
hs.push(handler);
}
pub fn clear_handlers(&self) {
let mut hs = self._handlers.write().unwrap();
hs.clear();
}
pub fn name(&self) -> String {
self._name.clone()
}
pub fn full_name(&self) -> String {
self._full_name.clone()
}
pub fn log(&self, level: Level, msg: &str) {
if self.level <= level {
let message = Message {
level: level,
name: self._full_name.clone(),
created: SystemTime::now(),
msg: String::from(msg),
};
self.log_msg(&message);
}
}
fn log_msg(&self, message: &Message) {
let hs = self._handlers.read().unwrap();
for h in hs.iter() {
h.emit(&message);
}
if let Some(ref parent) = self._parent {
parent.log_msg(message);
}
}
pub fn debug(&self, fmt: &str) {
self.log(Level::DEBUG, fmt);
}
pub fn info(&self, fmt: &str) {
self.log(Level::INFO, fmt);
}
pub fn warn(&self, fmt: &str) {
self.log(Level::WARN, fmt);
}
pub fn error(&self, fmt: &str) {
self.log(Level::ERROR, fmt);
}
pub fn fatal(&self, fmt: &str) {
self.log(Level::FATAL, fmt);
}
}
pub type Logger = Arc<_Logger>;
static mut ROOT: *const Logger = 0 as *const Logger;
fn init() {
unsafe {
if ROOT == (0 as *const Logger) {
let root = Box::new(Arc::new(_Logger {
_name: String::new(),
_full_name: String::new(),
level: Level::DEBUG,
_parent: None,
_handlers: Arc::new(RwLock::new(Vec::new())),
_children: Arc::new(RwLock::new(HashMap::new())),
}));
ROOT = std::mem::transmute(root);
}
}
}
pub fn root() -> Logger {
init();
unsafe { (*ROOT).clone() }
}
pub fn debug(fmt: &str) {
init();
let result = unsafe { (*ROOT).clone() };
result.log(Level::DEBUG, fmt);
}
pub fn info(fmt: &str) {
init();
let result = unsafe { (*ROOT).clone() };
result.log(Level::INFO, fmt);
}
pub fn warn(fmt: &str) {
init();
let result = unsafe { (*ROOT).clone() };
result.log(Level::WARN, fmt);
}
pub fn error(fmt: &str) {
init();
let result = unsafe { (*ROOT).clone() };
result.log(Level::ERROR, fmt);
}
pub fn fatal(fmt: &str) {
init();
let result = unsafe { (*ROOT).clone() };
result.log(Level::FATAL, fmt);
}
pub fn get(name: &str) -> Logger {
init();
let path: Vec<&str> = name.split(".").collect();
let mut result = unsafe { (*ROOT).clone() };
for (idx, step) in path.iter().enumerate() {
result = {
let mut map = result._children.write().unwrap();
map.entry(step.to_string())
.or_insert_with(|| {
let full = path[1..idx + 1].iter().fold(
String::from(path[0]),
|a, b| format!("{}.{}", a, b),
);
Arc::new(_Logger {
_name: step.to_string(),
_full_name: full,
level: Level::DEBUG,
_parent: Some(result.clone()),
_handlers: Arc::new(RwLock::new(Vec::new())),
_children: Arc::new(RwLock::new(HashMap::new())),
})
})
.clone()
};
}
result
}