1use 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
13struct 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
36struct 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)]
73pub struct TuiSlogDrain;
87
88impl Drain for TuiSlogDrain {
89 type Ok = ();
90 type Err = io::Error;
91 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}