use std::sync::{Mutex, mpsc};
use std::{mem, io, thread};
thread_local! {
static TL_BUF: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(128))
}
pub trait Drain: Send + Sync {
fn log(&self, info: &Record, &OwnedKeyValueList) -> io::Result<()>;
}
impl<D: Drain+?Sized> Drain for Box<D> {
fn log(&self, info: &Record, o: &OwnedKeyValueList) -> io::Result<()> {
(**self).log(info, o)
}
}
impl<D: Drain+?Sized> Drain for Arc<D> {
fn log(&self, info: &Record, o: &OwnedKeyValueList) -> io::Result<()> {
(**self).log(info, o)
}
}
pub struct Discard;
impl Drain for Discard {
fn log(&self, _: &Record, _: &OwnedKeyValueList) -> io::Result<()> {
Ok(())
}
}
pub struct Streamer<W: io::Write, F: format::Format> {
io: Mutex<W>,
format: F,
}
impl<W: io::Write, F: format::Format> Streamer<W, F> {
pub fn new(io: W, format: F) -> Self {
Streamer {
io: Mutex::new(io),
format: format,
}
}
}
impl<W: 'static + io::Write + Send, F: format::Format + Send> Drain for Streamer<W, F> {
fn log(&self,
info: &Record,
logger_values: &OwnedKeyValueList)
-> io::Result<()> {
TL_BUF.with(|buf| {
let mut buf = buf.borrow_mut();
let res = {
|| {
try!(self.format.format(&mut *buf, info, logger_values));
{
let mut io = try!(self.io.lock().map_err(|_| io::Error::new(io::ErrorKind::Other, "lock error")));
try!(io.write_all(&buf));
}
Ok(())
}
}();
buf.clear();
res
})
}
}
pub struct AsyncStreamer<F: format::Format> {
format: F,
io: Mutex<AsyncIoWriter>,
}
impl<F: format::Format> AsyncStreamer<F> {
pub fn new<W: io::Write + Send + 'static>(io: W, format: F) -> Self {
AsyncStreamer {
io: Mutex::new(AsyncIoWriter::new(io)),
format: format,
}
}
}
impl<F: format::Format + Send> Drain for AsyncStreamer<F> {
fn log(&self,
info: &Record,
logger_values: &OwnedKeyValueList)
-> io::Result<()> {
TL_BUF.with(|buf| {
let mut buf = buf.borrow_mut();
let res = {
|| {
try!(self.format.format(&mut *buf, info, logger_values));
{
let mut io = try!(self.io.lock().map_err(|_| io::Error::new(io::ErrorKind::Other, "lock error")));
let mut new_buf = Vec::with_capacity(128);
mem::swap(&mut *buf, &mut new_buf);
try!(io.write_nocopy(new_buf));
}
Ok(())
}}()
;
if res.is_err() {
buf.clear();
}
res
})
}
}
pub struct Filter<D: Drain> {
drain: D,
cond: Box<Fn(&Record) -> bool + 'static + Send + Sync>,
}
impl<D: Drain> Filter<D> {
pub fn new<F: 'static + Sync + Send + Fn(&Record) -> bool>(drain: D, cond: F) -> Self {
Filter {
drain: drain,
cond: Box::new(cond),
}
}
}
impl<D: Drain> Drain for Filter<D> {
fn log(&self,
info: &Record,
logger_values: &OwnedKeyValueList)
-> io::Result<()> {
if (self.cond)(&info) {
self.drain.log(info, logger_values)
} else {
Ok(())
}
}
}
pub struct LevelFilter<D: Drain> {
level: Level,
drain: D,
}
impl<D: Drain> LevelFilter<D> {
pub fn new(drain: D, level: Level) -> Self {
LevelFilter {
level: level,
drain: drain,
}
}
}
impl<D: Drain> Drain for LevelFilter<D> {
fn log(&self,
info: &Record,
logger_values: &OwnedKeyValueList)
-> io::Result<()> {
if info.level().is_at_least(self.level) {
self.drain.log(info, logger_values)
} else {
Ok(())
}
}
}
pub struct Duplicate<D1: Drain, D2: Drain> {
drain1: D1,
drain2: D2,
}
impl<D1: Drain, D2: Drain> Duplicate<D1, D2> {
pub fn new(drain1: D1, drain2: D2) -> Self {
Duplicate {
drain1: drain1,
drain2: drain2,
}
}
}
impl<D1: Drain, D2: Drain> Drain for Duplicate<D1, D2> {
fn log(&self,
info: &Record,
logger_values: &OwnedKeyValueList)
-> io::Result<()> {
let res1 = self.drain1.log(info, logger_values);
let res2 = self.drain2.log(info, logger_values);
match (res1, res2) {
(Ok(_), Ok(_)) => Ok(()),
(Ok(_), Err(e)) => Err(e),
(Err(e), Ok(_)) => Err(e),
(Err(e1), Err(_)) => Err(e1),
}
}
}
pub struct Failover<D1: Drain, D2: Drain> {
drain1: D1,
drain2: D2,
}
impl<D1: Drain, D2: Drain> Failover<D1, D2> {
pub fn new(drain1: D1, drain2: D2) -> Self {
Failover {
drain1: drain1,
drain2: drain2,
}
}
}
impl<D1: Drain, D2: Drain> Drain for Failover<D1, D2> {
fn log(&self,
info: &Record,
logger_values: &OwnedKeyValueList)
-> io::Result<()> {
match self.drain1.log(info, logger_values) {
Ok(_) => Ok(()),
Err(_) => self.drain2.log(info, logger_values),
}
}
}
enum AsyncIoMsg {
Bytes(Vec<u8>),
Flush,
Eof,
}
struct AsyncIoWriter {
sender: mpsc::Sender<AsyncIoMsg>,
join: Option<thread::JoinHandle<()>>,
}
impl AsyncIoWriter {
pub fn new<W: io::Write + Send + 'static>(mut io: W) -> Self {
let (tx, rx) = mpsc::channel();
let join = thread::spawn(move || {
loop {
match rx.recv().unwrap() {
AsyncIoMsg::Bytes(buf) => io.write_all(&buf).unwrap(),
AsyncIoMsg::Flush => io.flush().unwrap(),
AsyncIoMsg::Eof => return,
}
}
});
AsyncIoWriter {
sender: tx,
join: Some(join),
}
}
pub fn write_nocopy(&mut self, buf: Vec<u8>) -> io::Result<()> {
try!(self.sender
.send(AsyncIoMsg::Bytes(buf))
.map_err(|e| io::Error::new(io::ErrorKind::BrokenPipe, e)));
Ok(())
}
}
impl io::Write for AsyncIoWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let _ = self.sender.send(AsyncIoMsg::Bytes(buf.to_vec())).unwrap();
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
let _ = self.sender.send(AsyncIoMsg::Flush);
Ok(())
}
}
impl Drop for AsyncIoWriter {
fn drop(&mut self) {
let _ = self.sender.send(AsyncIoMsg::Eof);
let _ = self.join.take().unwrap().join();
}
}
pub fn stream<W: io::Write + Send, F: format::Format>(io: W, format: F) -> Streamer<W, F> {
Streamer::new(io, format)
}
pub fn async_stream<W: io::Write + Send + 'static, F: format::Format>(io: W, format: F) -> AsyncStreamer<F> {
AsyncStreamer::new(io, format)
}
pub fn discard() -> Discard {
Discard
}
pub fn filter<D: Drain, F: 'static + Send + Sync + Fn(&Record) -> bool>(cond: F,
d: D)
-> Filter<D> {
Filter::new(d, cond)
}
pub fn level_filter<D: Drain>(level: Level, d: D) -> LevelFilter<D> {
LevelFilter::new(d, level)
}
pub fn duplicate<D1: Drain, D2: Drain>(d1: D1, d2: D2) -> Duplicate<D1, D2> {
Duplicate::new(d1, d2)
}
pub fn failover<D1: Drain, D2: Drain>(d1: D1, d2: D2) -> Failover<D1, D2> {
Failover::new(d1, d2)
}