use std::io;
use std::sync;
use log;
pub trait LogOptions {
fn include_systemd_level(&self) -> bool {
false
}
fn target_filter(&self) -> Vec<String>;
fn max_log_level(&self) -> log::LevelFilter;
}
impl<'a> LogOptions for &'a LogOptions {
fn include_systemd_level(&self) -> bool {
(*self).include_systemd_level()
}
fn target_filter(&self) -> Vec<String> {
(*self).target_filter()
}
fn max_log_level(&self) -> log::LevelFilter {
(*self).max_log_level()
}
}
pub struct Logger<T> {
level: log::LevelFilter,
output: sync::Mutex<T>,
target_filter: Vec<String>,
include_systemd_level: bool,
}
impl<T: Send + io::Write> Logger<T> {
pub fn new<O: LogOptions>(
output: T,
options: &O,
) -> Logger<io::LineWriter<T>> {
let level = options.max_log_level();
log::set_max_level(level);
Logger {
level: level,
output: sync::Mutex::new(io::LineWriter::new(output)),
target_filter: options.target_filter(),
include_systemd_level: options.include_systemd_level(),
}
}
fn systemd_level(&self, record: &log::Record) -> &'static str {
use ::log::Level::*;
if self.include_systemd_level {
match record.level() {
Error => "<3> ",
Warn => "<4> ",
Info => "<5> ",
Debug => "<7> ",
Trace => "<7> ",
}
} else {
""
}
}
}
impl<T: Send + io::Write> log::Log for Logger<T> {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.level() <= self.level
}
fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) &&
self.target_filter.iter().any(|t| record.target().starts_with(t))
{
let prefix = self.systemd_level(record);
if let Ok(ref mut writer) = self.output.lock() {
let _ = writeln!(writer, "{}{}", prefix, record.args());
}
}
}
fn flush(&self) {
if let Ok(ref mut output) = self.output.lock() {
let _ = output.flush();
}
}
}
pub fn init<O: LogOptions>(options: &LogOptions) -> Result<(), log::SetLoggerError> {
if ::std::env::var("RUST_LOG").is_ok() {
::env_logger::try_init()
} else {
log::set_boxed_logger(Box::new(Logger::new(io::stdout(), &options)))
}
}