slog_scope_stdlog/
lib.rs

1//! Standard Rust log crate adapter to slog-rs based on slog-scope.
2//!
3//! Note: this is a fork of a `slog-stdlog` that unlike original does
4//! share logging scopes with `slog-scope` crate. It is currently advised
5//! to prefer `slog-scope-stdlog`.
6//!
7//! This crate provides two way compatibility with legacy `log` crate logging.
8//!
9//! ### `log` -> `slog`
10//!
11//! After calling `init` legacy `log` crate logging statements (eg. `debug!(...)`) will
12//! be redirected just like they originated from the logger returned by `slog_scope::logger()`.
13//! See documentation of `slog-scope` for examples of logging scope usage.
14//!
15//! ### `slog` -> `log`
16//!
17//! `StdLog` is a `slog::Drain` implementation that will log logging `Record`s just like
18//! they were created using legacy `log` statements.
19//!
20//! ### Warning
21//!
22//! Be careful when using both methods at the same time, as a loop can be easily created:
23//! `log` -> `slog` -> `log` -> ...
24//!
25#![warn(missing_docs)]
26
27#[macro_use]
28extern crate slog;
29extern crate slog_term;
30extern crate slog_scope;
31extern crate log;
32
33use slog::ser;
34
35use log::LogMetadata;
36use std::{io, fmt};
37use std::io::Write;
38
39use slog::Level;
40
41struct Logger;
42
43fn log_to_slog_level(level: log::LogLevel) -> Level {
44    match level {
45        log::LogLevel::Trace => Level::Trace,
46        log::LogLevel::Debug => Level::Debug,
47        log::LogLevel::Info => Level::Info,
48        log::LogLevel::Warn => Level::Warning,
49        log::LogLevel::Error => Level::Error,
50    }
51}
52
53impl log::Log for Logger {
54    fn enabled(&self, _: &LogMetadata) -> bool {
55        true
56    }
57
58    fn log(&self, r: &log::LogRecord) {
59        let level = log_to_slog_level(r.metadata().level());
60
61        let args = r.args();
62        let target = r.target();
63        let module = r.location().__module_path;
64        let file = r.location().__file;
65        let line = r.location().line();
66
67        let s = slog::RecordStatic {
68            level: level,
69            file: file,
70            line: line,
71            column: 0,
72            function: "",
73            module: module,
74            target: target,
75        };
76        slog_scope::logger().log(&slog::Record::new(&s, *args, &[]))
77    }
78}
79
80/// Minimal initialization with default drain
81///
82/// The exact default drain is unspecified and will
83/// change in future versions! Use `set_logger` instead
84/// to build customized drain.
85///
86/// ```
87/// #[macro_use]
88/// extern crate log;
89/// extern crate slog_scope_stdlog;
90///
91/// fn main() {
92///     slog_scope_stdlog::init().unwrap();
93///     // Note: this `info!(...)` macro comes from `log` crate
94///     info!("standard logging redirected to slog");
95/// }
96/// ```
97pub fn init() -> Result<(), log::SetLoggerError> {
98    log::set_logger(|max_log_level| {
99        max_log_level.set(log::LogLevelFilter::max());
100        Box::new(Logger)
101    })
102}
103
104/// Drain logging `Record`s into `log` crate
105///
106/// Using `StdLog` is effectively the same as using `log::info!(...)` and
107/// other standard logging statements.
108///
109/// Caution needs to be taken to prevent circular loop where `Logger`
110/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
111/// drain, which would again log things to the global `Logger` and so on
112/// leading to an infinite recursion.
113pub struct StdLog;
114
115struct LazyLogString<'a> {
116    info: &'a slog::Record<'a>,
117    logger_values: &'a slog::OwnedKeyValueList,
118}
119
120impl<'a> LazyLogString<'a> {
121    fn new(info: &'a slog::Record, logger_values: &'a slog::OwnedKeyValueList) -> Self {
122
123        LazyLogString {
124            info: info,
125            logger_values: logger_values,
126        }
127    }
128}
129
130impl<'a> fmt::Display for LazyLogString<'a> {
131    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132
133        try!(write!(f, "{}", self.info.msg()));
134
135        let io = io::Cursor::new(Vec::new());
136        let mut ser = KSV::new(io, ": ".into());
137
138        let res = {
139                || -> io::Result<()> {
140
141                    for (k, v) in self.logger_values.iter() {
142                        try!(ser.io().write_all(", ".as_bytes()));
143                        try!(v.serialize(self.info, k, &mut ser));
144                    }
145
146                    for &(k, v) in self.info.values().iter() {
147                        try!(ser.io().write_all(", ".as_bytes()));
148                        try!(v.serialize(self.info, k, &mut ser));
149                    }
150                    Ok(())
151                }
152            }()
153            .map_err(|_| fmt::Error);
154
155        try!(res);
156
157        let values = ser.into_inner().into_inner();
158
159
160        write!(f, "{}", String::from_utf8_lossy(&values))
161
162    }
163}
164
165impl slog::Drain for StdLog {
166    type Error = io::Error;
167    fn log(&self, info: &slog::Record, logger_values: &slog::OwnedKeyValueList) -> io::Result<()> {
168
169        let level = match info.level() {
170            slog::Level::Critical | slog::Level::Error => log::LogLevel::Error,
171            slog::Level::Warning => log::LogLevel::Warn,
172            slog::Level::Info => log::LogLevel::Info,
173            slog::Level::Debug => log::LogLevel::Debug,
174            slog::Level::Trace => log::LogLevel::Trace,
175        };
176
177        let target = info.target();
178
179        let location = log::LogLocation {
180            __module_path: info.module(),
181            __file: info.file(),
182            __line: info.line(),
183        };
184
185        let lazy = LazyLogString::new(info, logger_values);
186        // Please don't yell at me for this! :D
187        // https://github.com/rust-lang-nursery/log/issues/95
188        log::__log(level, target, &location, format_args!("{}", lazy));
189
190        Ok(())
191    }
192}
193
194/// Key-Separator-Value serializer
195struct KSV<W: io::Write> {
196    separator: String,
197    io: W,
198}
199
200impl<W: io::Write> KSV<W> {
201    fn new(io: W, separator: String) -> Self {
202        KSV {
203            io: io,
204            separator: separator,
205        }
206    }
207
208    fn io(&mut self) -> &mut W {
209        &mut self.io
210    }
211
212    fn into_inner(self) -> W {
213        self.io
214    }
215}
216
217impl<W: io::Write> ser::Serializer for KSV<W> {
218    fn emit_none(&mut self, key: &str) -> ser::Result {
219        try!(write!(self.io, "{}{}{}", key, self.separator, "None"));
220        Ok(())
221    }
222    fn emit_unit(&mut self, key: &str) -> ser::Result {
223        try!(write!(self.io, "{}", key));
224        Ok(())
225    }
226
227    fn emit_bool(&mut self, key: &str, val: bool) -> ser::Result {
228        try!(write!(self.io, "{}{}{}", key, self.separator, val));
229        Ok(())
230    }
231
232    fn emit_char(&mut self, key: &str, val: char) -> ser::Result {
233        try!(write!(self.io, "{}{}{}", key, self.separator, val));
234        Ok(())
235    }
236
237    fn emit_usize(&mut self, key: &str, val: usize) -> ser::Result {
238        try!(write!(self.io, "{}{}{}", key, self.separator, val));
239        Ok(())
240    }
241    fn emit_isize(&mut self, key: &str, val: isize) -> ser::Result {
242        try!(write!(self.io, "{}{}{}", key, self.separator, val));
243        Ok(())
244    }
245
246    fn emit_u8(&mut self, key: &str, val: u8) -> ser::Result {
247        try!(write!(self.io, "{}{}{}", key, self.separator, val));
248        Ok(())
249    }
250    fn emit_i8(&mut self, key: &str, val: i8) -> ser::Result {
251        try!(write!(self.io, "{}{}{}", key, self.separator, val));
252        Ok(())
253    }
254    fn emit_u16(&mut self, key: &str, val: u16) -> ser::Result {
255        try!(write!(self.io, "{}{}{}", key, self.separator, val));
256        Ok(())
257    }
258    fn emit_i16(&mut self, key: &str, val: i16) -> ser::Result {
259        try!(write!(self.io, "{}{}{}", key, self.separator, val));
260        Ok(())
261    }
262    fn emit_u32(&mut self, key: &str, val: u32) -> ser::Result {
263        try!(write!(self.io, "{}{}{}", key, self.separator, val));
264        Ok(())
265    }
266    fn emit_i32(&mut self, key: &str, val: i32) -> ser::Result {
267        try!(write!(self.io, "{}{}{}", key, self.separator, val));
268        Ok(())
269    }
270    fn emit_f32(&mut self, key: &str, val: f32) -> ser::Result {
271        try!(write!(self.io, "{}{}{}", key, self.separator, val));
272        Ok(())
273    }
274    fn emit_u64(&mut self, key: &str, val: u64) -> ser::Result {
275        try!(write!(self.io, "{}{}{}", key, self.separator, val));
276        Ok(())
277    }
278    fn emit_i64(&mut self, key: &str, val: i64) -> ser::Result {
279        try!(write!(self.io, "{}{}{}", key, self.separator, val));
280        Ok(())
281    }
282    fn emit_f64(&mut self, key: &str, val: f64) -> ser::Result {
283        try!(write!(self.io, "{}{}{}", key, self.separator, val));
284        Ok(())
285    }
286    fn emit_str(&mut self, key: &str, val: &str) -> ser::Result {
287        try!(write!(self.io, "{}{}{}", key, self.separator, val));
288        Ok(())
289    }
290    fn emit_arguments(&mut self, key: &str, val: &fmt::Arguments) -> ser::Result {
291        try!(write!(self.io, "{}{}{}", key, self.separator, val));
292        Ok(())
293    }
294}