multi-logger 0.0.1

Rusty Horde Loggers
use file::FileLogger;
use log::{
    self,
    LogLevelFilter,
    LogMetadata,
    LogRecord,
    SetLoggerError
};
use stdout::StdoutLogger;
use std::path::PathBuf;

bitflags! {
    #[derive(Debug)]
    flags Loggers: u32 {
        const STDOUT = 0b00000001,
        const FILE   = 0b00000010,
        //const DB     = 0b00000100,
        //const SOCKET = 0b00001000,
        const LOCAL  = STDOUT.bits | FILE.bits,
    }
}

pub struct MultiLogger {
    loggers: Loggers,
    file: Option<FileLogger>,
    stdout: Option<StdoutLogger>,
}

impl MultiLogger {
    pub fn new() -> MultiLogger {
        MultiLogger {
            loggers: Loggers::empty(),
            file: None,
            stdout: None,
        }
    }

    pub fn toggle_stdout(&mut self) -> &mut MultiLogger {
        self.loggers.toggle(STDOUT);
        self.stdout = Some(StdoutLogger);
        self
    }

    pub fn toggle_file(&mut self, path: PathBuf) -> &mut MultiLogger {
        self.loggers.toggle(FILE);
        self.file = Some(FileLogger::new(path));
        self
    }
}

impl log::Log for MultiLogger {
    fn enabled(&self, _: &LogMetadata) -> bool {
        true
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            if self.loggers.contains(FILE) {
                match self.file {
                    Some(ref f) => { f.log(record); },
                    None        => {},
                }
            }

            if self.loggers.contains(STDOUT) {
                match self.stdout {
                    Some(ref s) => { s.log(record); },
                    None        => {},
                }
            }
        }
    }
}

pub fn init_chained_logger(lvl: LogLevelFilter,
                           cl: MultiLogger) -> Result<(), SetLoggerError> {
    log::set_logger(|max_log_level| {
        max_log_level.set(lvl);
        Box::new(cl)
    })
}

#[cfg(test)]
mod test {
    use super::*;
    use std::env;
    use log::LogLevelFilter;

    #[test]
    fn test_loggers() {
        let mut loggers = STDOUT | FILE;
        assert_eq!(loggers.bits, 3);
        loggers.toggle(STDOUT);
        assert_eq!(loggers.bits, 2);
        loggers.toggle(FILE);
        loggers.toggle(STDOUT);
        assert_eq!(loggers.bits, 1);
        loggers.toggle(STDOUT);
        assert_eq!(loggers.bits, 0);
        loggers = LOCAL;
        assert_eq!(loggers.bits, 3);
    }

    #[test]
    fn test_chained() {
        let mut tmp_log = env::temp_dir();
        tmp_log.push("log.log");

        let mut cl = MultiLogger::new();
        cl.toggle_stdout();
        cl.toggle_file(tmp_log);
        assert!(init_chained_logger(LogLevelFilter::Debug, cl).is_ok());
        error!("TEST");
    }
}