logging_subscriber/
logging_writer.rs

1use 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}