#![deny(missing_docs)]
#![cfg_attr(feature="nightly", feature(libc))]
#[macro_use]
extern crate log;
#[cfg(feature="nightly")]
extern crate libc;
use std::fs::{OpenOptions, File};
use std::io::Write;
use std::sync::Mutex;
use std::env;
use log::{Log, LogMetadata, LogRecord, LogLevel, MaxLogLevelFilter, LogLevelFilter, SetLoggerError};
pub struct KernelLog {
kmsg: Mutex<File>,
maxlevel: LogLevelFilter
}
impl KernelLog {
pub fn new() -> KernelLog {
KernelLog::with_level(LogLevelFilter::Trace)
}
pub fn with_level(filter: LogLevelFilter) -> KernelLog {
KernelLog {
kmsg: Mutex::new(OpenOptions::new().write(true).open("/dev/kmsg").unwrap()),
maxlevel: filter
}
}
pub fn init(filter: MaxLogLevelFilter) -> Box<Log> {
let logger = KernelLog::new();
filter.set(logger.maxlevel);
Box::new(logger)
}
pub fn init_env(filter: MaxLogLevelFilter) -> Box<Log> {
match env::var("KERNLOG_LEVEL") {
Err(_) => KernelLog::init(filter),
Ok(s) => match s.parse() {
Ok(level) => KernelLog::init_level(level, filter),
Err(_) => KernelLog::init(filter)
}
}
}
pub fn init_level(level: LogLevelFilter, filter: MaxLogLevelFilter) -> Box<Log> {
filter.set(level);
Box::new(KernelLog::with_level(level))
}
}
impl Log for KernelLog {
fn enabled(&self, meta: &LogMetadata) -> bool {
meta.level() <= self.maxlevel
}
#[cfg(feature="nightly")]
fn log(&self, record: &LogRecord) {
if record.level() > self.maxlevel {
return;
}
let level: u8 = match record.level() {
LogLevel::Error => 3,
LogLevel::Warn => 4,
LogLevel::Info => 5,
LogLevel::Debug => 6,
LogLevel::Trace => 7,
};
let mut buf = Vec::new();
writeln!(buf, "<{}>{}[{}]: {}", level, record.target(),
unsafe { ::libc::funcs::posix88::unistd::getpid() },
record.args()).unwrap();
if let Ok(mut kmsg) = self.kmsg.lock() {
let _ = kmsg.write(&buf);
let _ = kmsg.flush();
}
}
#[cfg(not(feature="nightly"))]
fn log(&self, record: &LogRecord) {
if record.level() > self.maxlevel {
return;
}
let level: u8 = match record.level() {
LogLevel::Error => 3,
LogLevel::Warn => 4,
LogLevel::Info => 5,
LogLevel::Debug => 6,
LogLevel::Trace => 7,
};
let mut buf = Vec::new();
writeln!(buf, "<{}>{}: {}", level, record.target(), record.args()).unwrap();
if let Ok(mut kmsg) = self.kmsg.lock() {
let _ = kmsg.write(&buf);
let _ = kmsg.flush();
}
}
}
pub fn init() -> Result<(), SetLoggerError> {
log::set_logger(KernelLog::init)
}
#[cfg(test)]
mod tests {
use super::{KernelLog, init};
#[test]
fn log_to_kernel() {
init().unwrap();
debug!("hello, world!");
}
}