slog_json_concur/
lib.rs

1// {{{ Crate docs
2//! JSON `Drain` for `slog-rs` - with concurrency
3//!
4//! ```
5//! #[macro_use]
6//! extern crate slog;
7//!
8//! use slog::Drain;
9//!
10//! fn main() {
11//!     let root = slog::Logger::root(
12//!         slog_json_concur::Json::default(std::io::stderr()).map(slog::Fuse),
13//!         o!("version" => env!("CARGO_PKG_VERSION"))
14//!     );
15//! }
16//! ```
17// }}}
18
19// {{{ Imports & meta
20#![warn(missing_docs)]
21#[macro_use]
22extern crate slog;
23
24use serde::ser::SerializeMap;
25use serde::serde_if_integer128;
26use slog::Key;
27use slog::Record;
28use slog::{FnValue, PushFnValue};
29use slog::{OwnedKVList, SendSyncRefUnwindSafeKV, KV};
30use std::{fmt, io, result};
31
32use std::cell::RefCell;
33use std::fmt::Write;
34use std::sync::{Arc, Mutex};
35
36// }}}
37
38// {{{ Serialize
39thread_local! {
40    static TL_BUF: RefCell<String> = RefCell::new(String::with_capacity(128));
41    static OUT_BUF: RefCell<Vec<u8>> = RefCell::new(Vec::with_capacity(512));
42}
43
44/// `slog::Serializer` adapter for `serde::Serializer`
45///
46/// Newtype to wrap serde Serializer, so that `Serialize` can be implemented
47/// for it
48struct SerdeSerializer<S: serde::Serializer> {
49    /// Current state of map serializing: `serde::Serializer::MapState`
50    ser_map: S::SerializeMap,
51}
52
53impl<S: serde::Serializer> SerdeSerializer<S> {
54    /// Start serializing map of values
55    fn start(ser: S, len: Option<usize>) -> result::Result<Self, slog::Error> {
56        let ser_map = ser.serialize_map(len).map_err(|e| {
57            io::Error::new(
58                io::ErrorKind::Other,
59                format!("serde serialization error: {}", e),
60            )
61        })?;
62        Ok(SerdeSerializer { ser_map })
63    }
64
65    /// Finish serialization, and return the serializer
66    fn end(self) -> result::Result<S::Ok, S::Error> {
67        self.ser_map.end()
68    }
69}
70
71macro_rules! impl_m(
72    ($s:expr, $key:expr, $val:expr) => ({
73        let k_s:  &str = $key.as_ref();
74        $s.ser_map.serialize_entry(k_s, $val)
75             .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("serde serialization error: {}", e)))?;
76        Ok(())
77    });
78);
79
80impl<S> slog::Serializer for SerdeSerializer<S>
81where
82    S: serde::Serializer,
83{
84    fn emit_bool(&mut self, key: Key, val: bool) -> slog::Result {
85        impl_m!(self, key, &val)
86    }
87
88    fn emit_unit(&mut self, key: Key) -> slog::Result {
89        impl_m!(self, key, &())
90    }
91
92    fn emit_char(&mut self, key: Key, val: char) -> slog::Result {
93        impl_m!(self, key, &val)
94    }
95
96    fn emit_none(&mut self, key: Key) -> slog::Result {
97        let val: Option<()> = None;
98        impl_m!(self, key, &val)
99    }
100    fn emit_u8(&mut self, key: Key, val: u8) -> slog::Result {
101        impl_m!(self, key, &val)
102    }
103    fn emit_i8(&mut self, key: Key, val: i8) -> slog::Result {
104        impl_m!(self, key, &val)
105    }
106    fn emit_u16(&mut self, key: Key, val: u16) -> slog::Result {
107        impl_m!(self, key, &val)
108    }
109    fn emit_i16(&mut self, key: Key, val: i16) -> slog::Result {
110        impl_m!(self, key, &val)
111    }
112    fn emit_usize(&mut self, key: Key, val: usize) -> slog::Result {
113        impl_m!(self, key, &val)
114    }
115    fn emit_isize(&mut self, key: Key, val: isize) -> slog::Result {
116        impl_m!(self, key, &val)
117    }
118    fn emit_u32(&mut self, key: Key, val: u32) -> slog::Result {
119        impl_m!(self, key, &val)
120    }
121    fn emit_i32(&mut self, key: Key, val: i32) -> slog::Result {
122        impl_m!(self, key, &val)
123    }
124    fn emit_f32(&mut self, key: Key, val: f32) -> slog::Result {
125        impl_m!(self, key, &val)
126    }
127    fn emit_u64(&mut self, key: Key, val: u64) -> slog::Result {
128        impl_m!(self, key, &val)
129    }
130    fn emit_i64(&mut self, key: Key, val: i64) -> slog::Result {
131        impl_m!(self, key, &val)
132    }
133    fn emit_f64(&mut self, key: Key, val: f64) -> slog::Result {
134        impl_m!(self, key, &val)
135    }
136    serde_if_integer128! {
137        fn emit_u128(&mut self, key: Key, val: u128) -> slog::Result {
138            impl_m!(self, key, &val)
139        }
140        fn emit_i128(&mut self, key: Key, val: i128) -> slog::Result {
141            impl_m!(self, key, &val)
142        }
143    }
144    fn emit_str(&mut self, key: Key, val: &str) -> slog::Result {
145        impl_m!(self, key, &val)
146    }
147    fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments) -> slog::Result {
148        TL_BUF.with(|buf| {
149            let mut buf = buf.borrow_mut();
150
151            buf.write_fmt(*val).unwrap();
152
153            let res = { || impl_m!(self, key, &*buf) }();
154            buf.clear();
155            res
156        })
157    }
158
159    #[cfg(feature = "nested-values")]
160    fn emit_serde(&mut self, key: Key, value: &dyn slog::SerdeValue) -> slog::Result {
161        impl_m!(self, key, value.as_serde())
162    }
163}
164// }}}
165
166// {{{ Json
167/// Json `Drain`
168///
169/// Each record will be printed as a Json map
170/// to a given `io`
171pub struct Json<W: io::Write> {
172    newlines: bool,
173    flush: bool,
174    values: Vec<OwnedKVList>,
175    io: Arc<Mutex<W>>,
176    pretty: bool,
177}
178
179impl<W> Json<W>
180where
181    W: io::Write,
182{
183    /// New `Json` `Drain` with default key-value pairs added
184    pub fn default(io: W) -> Json<W> {
185        JsonBuilder::new(io).add_default_keys().build()
186    }
187
188    /// Build custom `Json` `Drain`
189    #[cfg_attr(feature = "cargo-clippy", allow(clippy::new_ret_no_self))]
190    pub fn new(io: W) -> JsonBuilder<W> {
191        JsonBuilder::new(io)
192    }
193
194    fn log_impl<F>(
195        &self,
196        serializer: &mut serde_json::ser::Serializer<&mut Vec<u8>, F>,
197        rinfo: &Record,
198        logger_values: &OwnedKVList,
199    ) -> io::Result<()>
200    where
201        F: serde_json::ser::Formatter,
202    {
203        let mut serializer = SerdeSerializer::start(&mut *serializer, None)?;
204
205        for kv in &self.values {
206            kv.serialize(rinfo, &mut serializer)?;
207        }
208
209        logger_values.serialize(rinfo, &mut serializer)?;
210
211        rinfo.kv().serialize(rinfo, &mut serializer)?;
212
213        let res = serializer.end();
214
215        res.map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
216
217        Ok(())
218    }
219}
220
221impl<W> slog::Drain for Json<W>
222where
223    W: io::Write,
224{
225    type Ok = ();
226    type Err = io::Error;
227    fn log(&self, rinfo: &Record, logger_values: &OwnedKVList) -> io::Result<()> {
228        OUT_BUF.with(|out_buf| {
229            let mut io = out_buf.borrow_mut();
230            io.clear();
231            let io = if self.pretty {
232                let mut serializer = serde_json::Serializer::pretty(&mut *io);
233                self.log_impl(&mut serializer, rinfo, logger_values)?;
234                serializer.into_inner()
235            } else {
236                let mut serializer = serde_json::Serializer::new(&mut *io);
237                self.log_impl(&mut serializer, rinfo, logger_values)?;
238                serializer.into_inner()
239            };
240            if self.newlines {
241                use std::io::Write;
242                io.write_all("\n".as_bytes())?;
243            }
244
245            let mut w = self
246                .io
247                .lock()
248                .map_err(|e| io::Error::new(io::ErrorKind::Interrupted, e.to_string()))?;
249            w.write_all(&io)?;
250            if self.flush {
251                w.flush()?;
252            }
253            Ok(())
254        })
255    }
256}
257
258// }}}
259
260// {{{ JsonBuilder
261/// Json `Drain` builder
262///
263/// Create with `Json::new`.
264pub struct JsonBuilder<W: io::Write> {
265    newlines: bool,
266    flush: bool,
267    values: Vec<OwnedKVList>,
268    io: W,
269    pretty: bool,
270}
271
272impl<W> JsonBuilder<W>
273where
274    W: io::Write,
275{
276    fn new(io: W) -> Self {
277        JsonBuilder {
278            newlines: true,
279            flush: false,
280            values: vec![],
281            io,
282            pretty: false,
283        }
284    }
285
286    /// Build `Json` `Drain`
287    ///
288    /// This consumes the builder.
289    pub fn build(self) -> Json<W> {
290        Json {
291            values: self.values,
292            newlines: self.newlines,
293            flush: self.flush,
294            io: Arc::new(Mutex::new(self.io)),
295            pretty: self.pretty,
296        }
297    }
298
299    /// Set writing a newline after every log record
300    pub fn set_newlines(mut self, enabled: bool) -> Self {
301        self.newlines = enabled;
302        self
303    }
304
305    /// Enable flushing of the `io::Write` after every log record
306    pub fn set_flush(mut self, enabled: bool) -> Self {
307        self.flush = enabled;
308        self
309    }
310
311    /// Set whether or not pretty formatted logging should be used
312    pub fn set_pretty(mut self, enabled: bool) -> Self {
313        self.pretty = enabled;
314        self
315    }
316
317    /// Add custom values to be printed with this formatter
318    pub fn add_key_value<T>(mut self, value: slog::OwnedKV<T>) -> Self
319    where
320        T: SendSyncRefUnwindSafeKV + 'static,
321    {
322        self.values.push(value.into());
323        self
324    }
325
326    /// Add default key-values:
327    ///
328    /// * `ts` - timestamp
329    /// * `level` - record logging level name
330    /// * `msg` - msg - formatted logging message
331    pub fn add_default_keys(self) -> Self {
332        self.add_key_value(o!(
333            "ts" => FnValue(move |_ : &Record| {
334                    time::OffsetDateTime::now_utc()
335                    .format(&time::format_description::well_known::Rfc3339)
336                    .ok()
337            }),
338            "level" => FnValue(move |rinfo : &Record| {
339                rinfo.level().as_short_str()
340            }),
341            "msg" => PushFnValue(move |record : &Record, ser| {
342                ser.emit(record.msg())
343            }),
344        ))
345    }
346}
347// }}}
348// vim: foldmethod=marker foldmarker={{{,}}}