#![feature(custom_derive)]
#![warn(missing_docs)]
extern crate isatty;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate toml;
extern crate slog;
extern crate slog_json;
extern crate slog_term;
use std::result::Result;
use std::fs::OpenOptions;
use std::sync::Mutex;
use std::panic::{RefUnwindSafe, UnwindSafe};
pub type Drain = Box<SendSyncDrain<Ok=(), Err=Box<std::error::Error>>>;
pub trait SendSyncDrain: slog::Drain + Send + Sync + RefUnwindSafe + UnwindSafe {}
impl<T> SendSyncDrain for T
where T: slog::Drain + Send + Sync + RefUnwindSafe + UnwindSafe + ?Sized
{
}
pub mod config {
use std::collections::BTreeMap;
#[derive(Deserialize, Debug)]
pub struct Config {
pub output : BTreeMap<String, Output>,
}
pub type Output = BTreeMap<String, String>;
}
include!("_file.rs");
include!("_term.rs");
pub trait DrainFactory {
fn from_config(&self, config : &config::Output) -> Result<Option<Drain>, String>;
}
pub fn all_factories() -> Vec<Box<DrainFactory>> {
vec![Box::new(FileDrainFactory), Box::new(TermDrainFactory)]
}
pub fn from_config(config_str : &str) -> Result<Drain, String> {
from_config_with(config_str, &all_factories())
}
struct DuplicateMultiple {
drains : Vec<Drain>,
}
impl slog::Drain for DuplicateMultiple {
type Ok = ();
type Err = Box<std::error::Error>;
fn log(&self, info: &slog::Record, kv : &slog::OwnedKVList) -> std::result::Result<(), Self::Err> {
for d in &self.drains {
d.log(info, kv)?
}
Ok(())
}
}
struct BoxErrorDrain<D>(D)
where D : slog::Drain;
impl<D, E> slog::Drain for BoxErrorDrain<D>
where D : slog::Drain<Ok=(), Err=E>,
E : std::error::Error+'static {
type Ok =();
type Err = Box<std::error::Error>;
fn log(&self, info: &slog::Record, kv : &slog::OwnedKVList) -> std::result::Result<(), Self::Err> {
self.0.log(info, kv).map_err(|e| Box::new(e) as Box<std::error::Error>)
}
}
pub fn from_config_with(config_str : &str, factories : &[Box<DrainFactory>]) -> Result<Drain, String> {
let config : config::Config = toml::from_str(config_str)
.map_err(|e| format!("couldn't decode configuration: {}", e))?;
let mut sub_drains = vec![];
for output in &config.output {
let mut drain_from_factory = None;
for factory in factories {
match factory.from_config(output.1)? {
Some(drain) => {
drain_from_factory = Some(drain);
break;
},
None => {},
}
}
let drain_from_factory = drain_from_factory.ok_or(format!("no backend implementing output {} found", output.0))?;
sub_drains.push(drain_from_factory);
}
Ok(Box::new(DuplicateMultiple{drains: sub_drains}))
}
#[cfg(test)]
mod tests {
}