use super::{DrainRef, KeyValue, RecordBuilder, Level, RecordInfo};
use std::marker::PhantomData;
use std::sync::Arc;
use crossbeam::sync::ArcCell;
use std::{time, fmt, io};
use drain;
struct LoggerInner {
drain: DrainRef,
values: Vec<KeyValue>,
}
#[derive(Clone)]
pub struct Logger {
inner: Arc<LoggerInner>
}
impl Logger {
pub fn root() -> LoggerBuilder<'static> {
LoggerBuilder {
drain: Arc::new(ArcCell::new(Arc::new(Box::new(drain::Streamer::new(io::stderr()))))),
values: vec!(),
phantom : PhantomData::default(),
}
}
pub fn new<'a>(&'a self) -> LoggerBuilder<'a> {
LoggerBuilder {
drain: self.inner.drain.clone(),
values: self.inner.values.clone(),
phantom : PhantomData::default(),
}
}
pub fn new_root<'a>(&'a self) -> LoggerBuilder<'a> {
LoggerBuilder {
drain: Arc::new(ArcCell::new(Arc::new(Box::new(drain::Streamer::new(io::stderr()))))),
values: self.inner.values.clone(),
phantom : PhantomData::default(),
}
}
pub fn set_drain<D : drain::Drain>(&self, drain : D) {
let _ = self.inner.drain.set(Arc::new(Box::new(drain)));
}
pub fn swap_drain(&self, drain : Arc<Box<drain::Drain>>) -> Arc<Box<drain::Drain>> {
self.inner.drain.set(drain)
}
pub fn critical<'a, 'b>(&'a self, msg : &'b str) -> RecordBuilder<'a> {
self.log(Level::Critical, msg)
}
pub fn error<'a, 'b>(&'a self, msg : &'b str) -> RecordBuilder<'a> {
self.log(Level::Error, msg)
}
pub fn warning<'a, 'b>(&'a self, msg : &'b str) -> RecordBuilder<'a> {
self.log(Level::Warning, msg)
}
pub fn info<'a, 'b>(&'a self, msg : &'b str) -> RecordBuilder<'a> {
self.log(Level::Info, msg)
}
pub fn debug<'a, 'b>(&'a self, msg : &'b str) -> RecordBuilder<'a> {
self.log(Level::Debug, msg)
}
pub fn trace<'a, 'b>(&'a self, msg : &'b str) -> RecordBuilder<'a> {
self.log(Level::Trace, msg)
}
pub fn log<'a, 'b>(&'a self, lvl : Level, msg : &'b str) -> RecordBuilder<'a> {
let drain = self.inner.drain.get();
let info = RecordInfo {
ts: time::SystemTime::now(),
msg: msg.to_string(),
level: lvl,
};
let record_drain = drain.new_record(&info);
let mut builder = RecordBuilder {
record_drain: record_drain,
phantom: PhantomData::default(),
};
for &(ref k, ref v) in &self.inner.values {
builder.add(&k, &v);
}
builder
}
}
pub struct LoggerBuilder<'a> {
drain: DrainRef,
values: Vec<KeyValue>,
phantom: PhantomData<&'a LoggerInner>,
}
impl<'a> LoggerBuilder<'a> {
pub fn add<T : fmt::Display>(mut self, key : &str, val : T) -> Self {
self.values.push((key.to_owned(), format!("{}", val)));
self
}
pub fn end(self) -> Logger {
Logger {
inner: Arc::new(
LoggerInner {
values: self.values,
drain: self.drain,
}
)
}
}
}