logging-subscriber 0.2.0

simple logging subscriber which can be silenced
Documentation
use console::Style;
use std::fmt::Write as FmtWrite;
use std::io;
use std::io::Write;
use std::ops::DerefMut;

use log::Record;
use tracing_log::AsLog;
use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::fmt::MakeWriter;

use crate::{BlockingWriter, LevelOutput, LoggingWriter, LOGGING_WRITER};

impl Default for LoggingWriter {
	fn default() -> Self {
		LoggingWriter {
			enabled: true,
			level: LevelFilter::DEBUG,
			default_style: Style::new().white(),
			date_time_style: Style::default().dim(),
			level_style_error: Style::new().red().bold(),
			level_style_warn: Style::new().magenta().bold().bright(),
			level_style_debug: Style::new().blue().bold(),
			level_style_trace: Style::new().black().bold(),
			level_style_info: Style::new().green().bright().bold(),

			style_error: None,
			style_warn: None,
			style_info: None,
			style_debug: None,
			style_trace: None,

			timestamp_format: "%Y-%m-%dT%H:%M:%S%.3f".to_string(),
			separator: String::from(" "),
			format_level: LevelOutput::Abbreviated,
			display_level: true,
			display_time: true,
			display_target: false,
			display_filename: false,
			display_line_number: false,
		}
	}
}

impl Write for LoggingWriter {
	fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
		if self.enabled {
			io::stdout().write(buf)
		} else {
			Ok(0)
		}
	}

	fn flush(&mut self) -> io::Result<()> {
		io::stdout().flush()
	}
}

impl LoggingWriter {
	pub fn log(&mut self, record: &Record) -> io::Result<usize> {
		if self.level.as_log() >= record.level() {
			self.write(self.format_event(record).as_bytes())
		} else {
			Ok(0)
		}
	}

	fn format_event(&self, evt: &Record) -> String {
		let mut output = String::new();
		let mut default_style = self.default_style.clone();

		let (col_style, lev_long, lev_abbr) = match evt.level() {
			log::Level::Error => {
				default_style = self.style_error.clone().unwrap_or(default_style);
				(self.level_style_error.clone(), "ERROR", "E")
			}

			log::Level::Warn => {
				default_style = self.style_warn.clone().unwrap_or(default_style);
				(self.level_style_warn.clone(), "WARN ", "W")
			}
			log::Level::Info => {
				default_style = self.style_info.clone().unwrap_or(default_style);
				(self.level_style_info.clone(), "INFO ", "I")
			}
			log::Level::Debug => {
				default_style = self.style_debug.clone().unwrap_or(default_style);
				(self.level_style_debug.clone(), "DEBUG", "D")
			}
			log::Level::Trace => {
				default_style = self.style_trace.clone().unwrap_or(default_style);
				(self.level_style_trace.clone(), "TRACE", "T")
			}
		};

		if self.display_time {
			let _ = write!(
				&mut output,
				"{}",
				self.date_time_style
					.apply_to(chrono::Local::now().format(&self.timestamp_format).to_string())
			);
			let _ = write!(&mut output, "{}", self.default_style.apply_to(&self.separator));
		}

		match self.format_level {
			LevelOutput::Abbreviated => {
				let s = format!("{: ^3}", lev_abbr);
				let _ = write!(&mut output, "{}", col_style.apply_to(s));
				let _ = write!(&mut output, "{}", self.default_style.apply_to(&self.separator));
			}
			LevelOutput::Long => {
				let _ = write!(&mut output, "{}", col_style.apply_to(lev_long));
				let _ = write!(&mut output, "{}", self.default_style.apply_to(&self.separator));
			}
			_ => {}
		}

		let mut target_written = false;
		let mut file_written: bool = false;
		let mut line_written: bool = false;

		if self.display_target {
			let _ = write!(&mut output, "{}", self.default_style.apply_to(evt.target()));
			target_written = true;
		}

		if self.display_filename {
			if target_written {
				let _ = write!(&mut output, "{}", self.default_style.apply_to(&self.separator));
			}

			let _ = write!(&mut output, "{}", self.default_style.apply_to("<"));
			let _ = write!(&mut output, "{}", self.default_style.apply_to(evt.file().unwrap_or("?")));
			file_written = true;
		}

		if self.display_line_number {
			if file_written {
				let _ = write!(&mut output, "{}", self.default_style.apply_to(":"));
			}
			let _ = write!(
				&mut output,
				"{}",
				self.default_style.apply_to(evt.line().unwrap_or(0).to_string())
			);
			let _ = write!(&mut output, "{}", self.default_style.apply_to(">"));
			file_written = true;
			line_written = true;
		}

		if file_written && !line_written {
			let _ = write!(&mut output, "{}", self.default_style.apply_to(">"));
		}

		if file_written || target_written {
			let _ = write!(&mut output, "{}", self.default_style.apply_to(": "));
		}

		let _ = write!(&mut output, "{}\n", default_style.apply_to(format!("{}", evt.args())));
		output
	}
}

impl Write for BlockingWriter {
	fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
		LOGGING_WRITER.lock().unwrap().deref_mut().write(buf)
	}

	fn flush(&mut self) -> io::Result<()> {
		LOGGING_WRITER.lock().unwrap().deref_mut().flush()
	}
}

impl<'a> MakeWriter<'a> for BlockingWriter {
	type Writer = BlockingWriter;

	fn make_writer(&'a self) -> Self::Writer {
		self.clone()
	}
}