1
use std::io;
2
use std::io::Write;
3

            
4
use env_logger::fmt::Formatter;
5
use log::kv::Key;
6
use log::kv::Source;
7
use log::kv::Value;
8
use log::kv::VisitSource;
9

            
10
/// Formats key-value pairs from the given source as a JSON object.
11
///
12
/// # Details
13
///
14
/// Can be used to configure `env_logger` to format log key-values as JSON.
15
///
16
/// ```rust
17
/// use merc_tools::format_key_values_json;
18
///
19
/// env_logger::Builder::new()
20
///     .format_key_values(|formatter, source| {
21
///         Ok(format_key_values_json(formatter, source)?)
22
///     })
23
///     .init();
24
///
25
/// ```
26
pub fn format_key_values_json(formatter: &mut Formatter, source: &dyn Source) -> io::Result<()> {
27
    if source.count() > 0 {
28
        // If there are key-values, format them as a JSON object.
29
        formatter.write_all("\n{ ".as_bytes())?;
30
        let mut json_printer = JsonPrinter { formatter };
31
        if let Err(e) = source.visit(&mut json_printer) {
32
            return Err(io::Error::new(io::ErrorKind::InvalidData, e));
33
        }
34
        formatter.write_all(" }".as_bytes())?;
35
    }
36

            
37
    Ok(())
38
}
39

            
40
/// A visitor that formats key-value pairs as JSON on a single line.
41
struct JsonPrinter<'a> {
42
    formatter: &'a mut Formatter,
43
}
44

            
45
impl<'a, 'kvs> VisitSource<'kvs> for JsonPrinter<'a> {
46
    fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), log::kv::Error> {
47
        self.formatter.write_fmt(format_args!(r#""{}": {}"#, key, value))?;
48
        Ok(())
49
    }
50
}