1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#[macro_use]
extern crate slog;
extern crate slog_async;

use std::{fs, io};
use std::cell::RefCell;
use std::io::Write as IoWrite;

use slog::{Drain, Record, OwnedKVList};

const KMSG_MAX: usize = 1024 - 32;
const BUFFER_SIZE: usize = 4096;

pub struct Kmsg {
    fd: RefCell<fs::File>,
    buffer: RefCell<[u8; BUFFER_SIZE]>,
}

impl Kmsg {
    pub fn new() -> Result<Kmsg, io::Error> {
        let kmsg = fs::OpenOptions::new().write(true).open("/dev/kmsg")?;

        Ok(Kmsg {
               fd: RefCell::new(kmsg),
               buffer: RefCell::new([0; BUFFER_SIZE]),
           })
    }
}

fn level_to_kern_level(l: slog::Level) -> u8 {
    match l {
        slog::Level::Critical => 2,
        slog::Level::Error => 3,
        slog::Level::Warning => 4,
        slog::Level::Info => 6,
        slog::Level::Debug => 7,
        slog::Level::Trace => 7,
    }
}

impl Drain for Kmsg {
    type Ok = ();
    type Err = io::Error;

    fn log(&self, record: &Record, values: &OwnedKVList) -> Result<Self::Ok, Self::Err> {
        let mut len = {
            let mut buf = self.buffer.borrow_mut();
            let mut cursor = io::Cursor::new(&mut buf[..]);
            let klevel = level_to_kern_level(record.level());
            write!(&mut cursor,
                   "<{}>{}: {}\n",
                   klevel,
                   record.module(),
                   record.msg())?;
            cursor.position() as usize
        };
        if len > KMSG_MAX {
            len = KMSG_MAX;
        }
        self.fd
            .borrow_mut()
            .write_all(&self.buffer.borrow()[..len])?;
        self.fd
            .borrow_mut()
            .flush()?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::Kmsg;

    use slog;
    use slog::Drain;

    use slog_async;

    #[test]
    fn it_works() {
        let drain = Kmsg::new().unwrap().fuse();
        let drain = slog_async::Async::new(drain).build().fuse();
        let root = slog::Logger::root(drain, o!());
        error!(root, "test 123");
    }
}