tui_logger/
slog.rs

1//! `slog` support for `tui-logger`
2
3use super::TUI_LOGGER;
4use log::{self, Log, Record};
5use slog::{self, Drain, KV};
6use std::{fmt, io};
7
8#[cfg_attr(docsrs, doc(cfg(feature = "slog-support")))]
9pub fn slog_drain() -> TuiSlogDrain {
10    TuiSlogDrain
11}
12
13/// Key-Separator-Value serializer
14// Copied from `slog-stdlog`
15struct Ksv<W: io::Write> {
16    io: W,
17}
18
19impl<W: io::Write> Ksv<W> {
20    fn new(io: W) -> Self {
21        Ksv { io }
22    }
23
24    fn into_inner(self) -> W {
25        self.io
26    }
27}
28
29impl<W: io::Write> slog::Serializer for Ksv<W> {
30    fn emit_arguments(&mut self, key: slog::Key, val: &fmt::Arguments) -> slog::Result {
31        write!(self.io, ", {}: {}", key, val)?;
32        Ok(())
33    }
34}
35
36// Copied from `slog-stdlog`
37struct LazyLogString<'a> {
38    info: &'a slog::Record<'a>,
39    logger_values: &'a slog::OwnedKVList,
40}
41
42impl<'a> LazyLogString<'a> {
43    fn new(info: &'a slog::Record, logger_values: &'a slog::OwnedKVList) -> Self {
44        LazyLogString {
45            info,
46            logger_values,
47        }
48    }
49}
50
51impl<'a> fmt::Display for LazyLogString<'a> {
52    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53        write!(f, "{}", self.info.msg())?;
54
55        let io = io::Cursor::new(Vec::new());
56        let mut ser = Ksv::new(io);
57
58        self.logger_values
59            .serialize(self.info, &mut ser)
60            .map_err(|_| fmt::Error)?;
61        self.info
62            .kv()
63            .serialize(self.info, &mut ser)
64            .map_err(|_| fmt::Error)?;
65
66        let values = ser.into_inner().into_inner();
67
68        write!(f, "{}", String::from_utf8_lossy(&values))
69    }
70}
71
72#[allow(clippy::needless_doctest_main)]
73///  slog-compatible Drain that feeds messages to `tui-logger`.
74///
75///  ## Basic usage:
76///  ```
77///  use slog::{self, o, Drain, info};
78///  //use tui_logger;
79///  
80///  fn main() {
81///     let drain = tui_logger::slog_drain().fuse();
82///     let log = slog::Logger::root(drain, o!());
83///     info!(log, "Logging via slog works!");
84///
85///  }
86pub struct TuiSlogDrain;
87
88impl Drain for TuiSlogDrain {
89    type Ok = ();
90    type Err = io::Error;
91    // Copied from `slog-stdlog`
92    fn log(&self, info: &slog::Record, logger_values: &slog::OwnedKVList) -> io::Result<()> {
93        let level = match info.level() {
94            slog::Level::Critical | slog::Level::Error => log::Level::Error,
95            slog::Level::Warning => log::Level::Warn,
96            slog::Level::Info => log::Level::Info,
97            slog::Level::Debug => log::Level::Debug,
98            slog::Level::Trace => log::Level::Trace,
99        };
100
101        let mut target = info.tag();
102        if target.is_empty() {
103            target = info.module();
104        }
105
106        let lazy = LazyLogString::new(info, logger_values);
107        TUI_LOGGER.log(
108            &Record::builder()
109                .args(format_args!("{}", lazy))
110                .level(level)
111                .target(target)
112                .file(Some(info.file()))
113                .line(Some(info.line()))
114                .build(),
115        );
116
117        Ok(())
118    }
119}