logging_subscriber/
logging_writer.rs1use console::Style;
2use std::fmt::Write as FmtWrite;
3use std::io;
4use std::io::Write;
5use std::ops::DerefMut;
6
7use log::Record;
8use tracing_log::AsLog;
9use tracing_subscriber::filter::LevelFilter;
10use tracing_subscriber::fmt::MakeWriter;
11
12use crate::{BlockingWriter, LevelOutput, LoggingWriter, LOGGING_WRITER};
13
14impl Default for LoggingWriter {
15 fn default() -> Self {
16 LoggingWriter {
17 enabled: true,
18 level: LevelFilter::DEBUG,
19 default_style: Style::new().white(),
20 date_time_style: Style::default().dim(),
21 level_style_error: Style::new().red().bold(),
22 level_style_warn: Style::new().magenta().bold().bright(),
23 level_style_debug: Style::new().blue().bold(),
24 level_style_trace: Style::new().black().bold(),
25 level_style_info: Style::new().green().bright().bold(),
26
27 style_error: None,
28 style_warn: None,
29 style_info: None,
30 style_debug: None,
31 style_trace: None,
32
33 timestamp_format: "%Y-%m-%dT%H:%M:%S%.3f".to_string(),
34 separator: String::from(" "),
35 format_level: LevelOutput::Abbreviated,
36 display_level: true,
37 display_time: true,
38 display_target: false,
39 display_filename: false,
40 display_line_number: false,
41 }
42 }
43}
44
45impl Write for LoggingWriter {
46 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
47 if self.enabled {
48 io::stdout().write(buf)
49 } else {
50 Ok(0)
51 }
52 }
53
54 fn flush(&mut self) -> io::Result<()> {
55 io::stdout().flush()
56 }
57}
58
59impl LoggingWriter {
60 pub fn log(&mut self, record: &Record) -> io::Result<usize> {
61 if self.level.as_log() >= record.level() {
62 self.write(self.format_event(record).as_bytes())
63 } else {
64 Ok(0)
65 }
66 }
67
68 fn format_event(&self, evt: &Record) -> String {
69 let mut output = String::new();
70 let mut default_style = self.default_style.clone();
71
72 let (col_style, lev_long, lev_abbr) = match evt.level() {
73 log::Level::Error => {
74 default_style = self.style_error.clone().unwrap_or(default_style);
75 (self.level_style_error.clone(), "ERROR", "E")
76 }
77
78 log::Level::Warn => {
79 default_style = self.style_warn.clone().unwrap_or(default_style);
80 (self.level_style_warn.clone(), "WARN ", "W")
81 }
82 log::Level::Info => {
83 default_style = self.style_info.clone().unwrap_or(default_style);
84 (self.level_style_info.clone(), "INFO ", "I")
85 }
86 log::Level::Debug => {
87 default_style = self.style_debug.clone().unwrap_or(default_style);
88 (self.level_style_debug.clone(), "DEBUG", "D")
89 }
90 log::Level::Trace => {
91 default_style = self.style_trace.clone().unwrap_or(default_style);
92 (self.level_style_trace.clone(), "TRACE", "T")
93 }
94 };
95
96 if self.display_time {
97 let _ = write!(
98 &mut output,
99 "{}",
100 self.date_time_style
101 .apply_to(chrono::Local::now().format(&self.timestamp_format).to_string())
102 );
103 let _ = write!(&mut output, "{}", self.default_style.apply_to(&self.separator));
104 }
105
106 match self.format_level {
107 LevelOutput::Abbreviated => {
108 let s = format!("{: ^3}", lev_abbr);
109 let _ = write!(&mut output, "{}", col_style.apply_to(s));
110 let _ = write!(&mut output, "{}", self.default_style.apply_to(&self.separator));
111 }
112 LevelOutput::Long => {
113 let _ = write!(&mut output, "{}", col_style.apply_to(lev_long));
114 let _ = write!(&mut output, "{}", self.default_style.apply_to(&self.separator));
115 }
116 _ => {}
117 }
118
119 let mut target_written = false;
120 let mut file_written: bool = false;
121 let mut line_written: bool = false;
122
123 if self.display_target {
124 let _ = write!(&mut output, "{}", self.default_style.apply_to(evt.target()));
125 target_written = true;
126 }
127
128 if self.display_filename {
129 if target_written {
130 let _ = write!(&mut output, "{}", self.default_style.apply_to(&self.separator));
131 }
132
133 let _ = write!(&mut output, "{}", self.default_style.apply_to("<"));
134 let _ = write!(&mut output, "{}", self.default_style.apply_to(evt.file().unwrap_or("?")));
135 file_written = true;
136 }
137
138 if self.display_line_number {
139 if file_written {
140 let _ = write!(&mut output, "{}", self.default_style.apply_to(":"));
141 }
142 let _ = write!(
143 &mut output,
144 "{}",
145 self.default_style.apply_to(evt.line().unwrap_or(0).to_string())
146 );
147 let _ = write!(&mut output, "{}", self.default_style.apply_to(">"));
148 file_written = true;
149 line_written = true;
150 }
151
152 if file_written && !line_written {
153 let _ = write!(&mut output, "{}", self.default_style.apply_to(">"));
154 }
155
156 if file_written || target_written {
157 let _ = write!(&mut output, "{}", self.default_style.apply_to(": "));
158 }
159
160 let _ = write!(&mut output, "{}\n", default_style.apply_to(format!("{}", evt.args())));
161 output
162 }
163}
164
165impl Write for BlockingWriter {
166 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
167 LOGGING_WRITER.lock().unwrap().deref_mut().write(buf)
168 }
169
170 fn flush(&mut self) -> io::Result<()> {
171 LOGGING_WRITER.lock().unwrap().deref_mut().flush()
172 }
173}
174
175impl<'a> MakeWriter<'a> for BlockingWriter {
176 type Writer = BlockingWriter;
177
178 fn make_writer(&'a self) -> Self::Writer {
179 self.clone()
180 }
181}