rs_utils/log/kv/
format.rs1use std::{io, thread};
4use env_logger;
5use log;
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub struct EnvLoggerFormatConfig {
9 pub thread : bool,
10 pub target : bool,
11 pub file : bool
12}
13
14pub fn env_logger_json_formatter (config : EnvLoggerFormatConfig)
16 -> impl Fn(&mut env_logger::fmt::Formatter, &log::Record<'_>) -> io::Result<()>
17{
18 use io::Write;
19 #[derive(Default)]
20 struct KVVisitor(pub String);
21 impl <'kvs> log::kv::VisitSource <'kvs> for KVVisitor {
22 fn visit_pair (&mut self, key : log::kv::Key <'kvs>, value : log::kv::Value <'kvs>)
23 -> Result <(), log::kv::Error>
24 {
25 self.0 += format!(",\"{}\":{}", key, serde_json::to_string (&value).unwrap())
26 .as_str();
27 Ok(())
28 }
29 }
30 move |buf : &mut env_logger::fmt::Formatter, record : &log::Record|{
31 let thread_string = if config.thread {
32 thread::current().name().map_or_else (
33 || format!(",\"thread\":\"{:?}\"", thread::current().id())
34 .replace ("ThreadId", "unnamed"),
35 |name| format!(",\"thread\":\"{name}\""))
36 } else {
37 "".to_string()
38 };
39 let target_string = if config.target {
40 format!(",\"target\":\"{}\"", record.target())
41 } else {
42 "".to_string()
43 };
44 let file_string = if config.file {
45 format!(",\"file\":\"{}:{}\"",
46 record.file().unwrap_or ("<unknown>"), record.line().unwrap_or (0))
47 } else {
48 "".to_string()
49 };
50 let mut kvv = KVVisitor::default();
51 record.key_values().visit (&mut kvv).unwrap();
52 writeln!(buf, "{{\"ts\":\"{}\",\"level\":\"{}\"{}{}{},\"msg\":\"{}\"{}}}",
53 buf.timestamp(), record.level(), thread_string, target_string,
54 file_string, record.args(), kvv.0
55 )
56 }
57}
58
59pub fn env_logger_custom_formatter (config : EnvLoggerFormatConfig)
64 -> impl Fn(&mut env_logger::fmt::Formatter, &log::Record<'_>) -> io::Result<()>
65{
66 use io::Write;
67 #[derive(Default)]
68 struct KVVisitor(pub String);
69 impl <'kvs> log::kv::VisitSource <'kvs> for KVVisitor {
70 fn visit_pair (&mut self, key : log::kv::Key <'kvs>, value : log::kv::Value <'kvs>)
71 -> Result <(), log::kv::Error>
72 {
73 let mut value_string = serde_json::to_string (&value).unwrap();
74 let mut value_str = value_string.as_str();
75 if !value_str.contains (char::is_whitespace) {
76 value_string = value_str.replace ("\\\"", "\"");
79 value_str = if value_string.starts_with ('"') {
80 &value_string[1..value_string.len()-1]
81 } else {
82 &value_string[..]
83 };
84 }
85 self.0 += format!(" {key}={value_str}").as_str();
86 Ok(())
87 }
88 }
89 move |buf : &mut env_logger::fmt::Formatter, record : &log::Record|{
90 let mut kvv = KVVisitor::default();
91 record.key_values().visit (&mut kvv).unwrap();
92 let kvs = if kvv.0.is_empty() {
93 "".to_string()
94 } else {
95 format!(" {}", kvv.0)
96 };
97 if !config.file && !config.thread && !config.target {
98 let level_string = format!("{}:", record.level());
99 writeln!(buf, "{} {:6} {}{}", buf.timestamp(), level_string, record.args(), kvs)
100 } else {
101 let thread_string = if config.thread {
102 thread::current().name().map_or_else (
103 || format!(" {:?}", thread::current().id())
104 .replace ("ThreadId", "unnamed"),
105 |name| format!(" {name}"))
106 } else {
107 "".to_string()
108 };
109 let target_string = if config.target {
110 format!(" {}", record.target())
111 } else {
112 "".to_string()
113 };
114 let file_string = if config.file {
115 format!(" {}:{}",
116 record.file().unwrap_or ("<unknown>"), record.line().unwrap_or (0))
117 } else {
118 "".to_string()
119 };
120 writeln!(buf, "{} {:5}{}{}{}: {}{}",
121 buf.timestamp(), record.level(), thread_string, target_string, file_string,
122 record.args(), kvs)
123 }
124 }
125}
126
127impl Default for EnvLoggerFormatConfig {
128 fn default() -> Self {
129 EnvLoggerFormatConfig {
130 thread: true,
131 target: true,
132 file: true
133 }
134 }
135}