From 1f76fd5a5bddc242eabf98c074a206bca0eff17e Mon Sep 17 00:00:00 2001 From: Mariusz Bialonczyk Date: Tue, 9 Nov 2021 09:44:33 +0100 Subject: [PATCH 1/4] introduce colored log levels using ansi_term This commit adds a possibility to color the log levels using an ansi_term crate for this purpose. The change was intended for WriteLogger in mind, but as this feature will be configurable and put in generic logging code, then other loggers can benefit as well (if desired). This way one can easily create a logfile with a similar colored look as it is printed real-time on a terminal/console. Tip: To view such a logfile with colors using 'less' you can use: less -R /path/to/logfile --- Cargo.toml | 1 + src/loggers/logging.rs | 41 +++++++++++++++++++++++++++++++++++++---- src/loggers/termlog.rs | 9 ++++++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7d79968a..027a1a1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,4 +26,5 @@ default = ["termcolor"] log = { version = "0.4.*", features = ["std"] } termcolor = { version = "1.1.*", optional = true } paris = { version = "1.5.7", optional = true } +ansi_term = { version = "0.12", optional = true } chrono = "0.4.1" diff --git a/src/loggers/logging.rs b/src/loggers/logging.rs index 9eefeab6..1eee30ec 100644 --- a/src/loggers/logging.rs +++ b/src/loggers/logging.rs @@ -3,6 +3,23 @@ use crate::{Config, LevelPadding, ThreadLogMode, ThreadPadding}; use log::{LevelFilter, Record}; use std::io::{Error, Write}; use std::thread; +#[cfg(all(feature = "termcolor", feature = "ansi_term"))] +use termcolor::Color; + +#[cfg(all(feature = "termcolor", feature = "ansi_term"))] +pub fn termcolor_to_ansiterm(color: &Color) -> Option { + match color { + Color::Black => Some(ansi_term::Color::Black), + Color::Red => Some(ansi_term::Color::Red), + Color::Green => Some(ansi_term::Color::Green), + Color::Yellow => Some(ansi_term::Color::Yellow), + Color::Blue => Some(ansi_term::Color::Blue), + Color::Magenta => Some(ansi_term::Color::Purple), + Color::Cyan => Some(ansi_term::Color::Cyan), + Color::White => Some(ansi_term::Color::White), + _ => None, + } +} #[inline(always)] pub fn try_log(config: &Config, record: &Record<'_>, write: &mut W) -> Result<(), Error> @@ -63,11 +80,27 @@ pub fn write_level(record: &Record<'_>, write: &mut W, config: &Config) -> Re where W: Write + Sized, { - match config.level_padding { - LevelPadding::Left => write!(write, "[{: >5}] ", record.level())?, - LevelPadding::Right => write!(write, "[{: <5}] ", record.level())?, - LevelPadding::Off => write!(write, "[{}] ", record.level())?, + #[cfg(all(feature = "termcolor", feature = "ansi_term"))] + let color = match &config.level_color[record.level() as usize] { + Some(termcolor) => termcolor_to_ansiterm(termcolor), + None => None, + }; + + let level = match config.level_padding { + LevelPadding::Left => format!("[{: >5}]", record.level()), + LevelPadding::Right => format!("[{: <5}]", record.level()), + LevelPadding::Off => format!("[{}]", record.level()), }; + + #[cfg(all(feature = "termcolor", feature = "ansi_term"))] + match color { + Some(c) => write!(write, "{} ", c.paint(level))?, + None => write!(write, "{} ", level)?, + }; + + #[cfg(not(feature = "ansi_term"))] + write!(write, "{} ", level)?; + Ok(()) } diff --git a/src/loggers/termlog.rs b/src/loggers/termlog.rs index 930592e8..bf7cb988 100644 --- a/src/loggers/termlog.rs +++ b/src/loggers/termlog.rs @@ -5,7 +5,9 @@ use log::{ }; use std::io::{Error, Write}; use std::sync::Mutex; -use termcolor::{BufferedStandardStream, ColorChoice, ColorSpec, WriteColor}; +use termcolor::{BufferedStandardStream, ColorChoice}; +#[cfg(not(feature = "ansi_term"))] +use termcolor::{ColorSpec, WriteColor}; use super::logging::*; @@ -128,6 +130,7 @@ impl TermLogger { record: &Record<'_>, term_lock: &mut BufferedStandardStream, ) -> Result<(), Error> { + #[cfg(not(feature = "ansi_term"))] let color = self.config.level_color[record.level() as usize]; if self.config.time <= record.level() && self.config.time != LevelFilter::Off { @@ -135,8 +138,12 @@ impl TermLogger { } if self.config.level <= record.level() && self.config.level != LevelFilter::Off { + #[cfg(not(feature = "ansi_term"))] term_lock.set_color(ColorSpec::new().set_fg(color))?; + write_level(record, term_lock, &self.config)?; + + #[cfg(not(feature = "ansi_term"))] term_lock.reset()?; } From feb3458fb455f357e7fbcd108d022eb7f712977f Mon Sep 17 00:00:00 2001 From: Mariusz Bialonczyk Date: Tue, 9 Nov 2021 11:51:19 +0100 Subject: [PATCH 2/4] Add a write_log_enable_colors configuration switch This flags controls writing log levels colored in the log. --- src/config.rs | 8 ++++++++ src/loggers/logging.rs | 8 +++++++- src/loggers/termlog.rs | 8 ++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/config.rs b/src/config.rs index 97281ec4..a53a2be6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -79,6 +79,7 @@ pub struct Config { pub(crate) filter_ignore: Cow<'static, [Cow<'static, str>]>, #[cfg(feature = "termcolor")] pub(crate) level_color: [Option; 6], + pub(crate) write_log_enable_colors: bool, } /// Builder for the Logger Configurations (`Config`) @@ -194,6 +195,12 @@ impl ConfigBuilder { self } + /// set if you want to write colors in the logfile (default is Off) + pub fn set_write_log_enable_colors(&mut self, local: bool) -> &mut ConfigBuilder { + self.0.write_log_enable_colors = local; + self + } + /// Add allowed module filters. /// If any are specified, only records from modules starting with one of these entries will be printed /// @@ -281,6 +288,7 @@ impl Default for Config { time_local: false, filter_allow: Cow::Borrowed(&[]), filter_ignore: Cow::Borrowed(&[]), + write_log_enable_colors: false, #[cfg(feature = "termcolor")] level_color: [ diff --git a/src/loggers/logging.rs b/src/loggers/logging.rs index 1eee30ec..a1049369 100644 --- a/src/loggers/logging.rs +++ b/src/loggers/logging.rs @@ -82,7 +82,13 @@ where { #[cfg(all(feature = "termcolor", feature = "ansi_term"))] let color = match &config.level_color[record.level() as usize] { - Some(termcolor) => termcolor_to_ansiterm(termcolor), + Some(termcolor) => { + if config.write_log_enable_colors { + termcolor_to_ansiterm(termcolor) + } else { + None + } + } None => None, }; diff --git a/src/loggers/termlog.rs b/src/loggers/termlog.rs index bf7cb988..f2a17e44 100644 --- a/src/loggers/termlog.rs +++ b/src/loggers/termlog.rs @@ -139,12 +139,16 @@ impl TermLogger { if self.config.level <= record.level() && self.config.level != LevelFilter::Off { #[cfg(not(feature = "ansi_term"))] - term_lock.set_color(ColorSpec::new().set_fg(color))?; + if !self.config.write_log_enable_colors { + term_lock.set_color(ColorSpec::new().set_fg(color))?; + } write_level(record, term_lock, &self.config)?; #[cfg(not(feature = "ansi_term"))] - term_lock.reset()?; + if !self.config.write_log_enable_colors { + term_lock.reset()?; + } } if self.config.thread <= record.level() && self.config.thread != LevelFilter::Off { From 3e0b33649dc9b3bfb6f01b724c9e3c5cfadaba45 Mon Sep 17 00:00:00 2001 From: Mariusz Bialonczyk Date: Wed, 10 Nov 2021 11:39:28 +0100 Subject: [PATCH 3/4] paris_macros: fix `this URL is not a hyperlink` warnings --- src/paris_macros/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/paris_macros/mod.rs b/src/paris_macros/mod.rs index 3baebcfb..4e361d2e 100644 --- a/src/paris_macros/mod.rs +++ b/src/paris_macros/mod.rs @@ -2,7 +2,7 @@ /// /// Passed data uses a colorize_string formatter from a `paris` crate, so it can /// contains special tags for controlling ANSI colors and styles -/// More info: https://docs.rs/paris/1.5.7/paris/formatter/fn.colorize_string.html +/// More info: /// /// # Examples /// @@ -29,7 +29,7 @@ macro_rules! info { /// /// Passed data uses a colorize_string formatter from a `paris` crate, so it can /// contains special tags for controlling ANSI colors and styles -/// More info: https://docs.rs/paris/1.5.7/paris/formatter/fn.colorize_string.html +/// More info: /// /// # Examples /// @@ -55,7 +55,7 @@ macro_rules! debug { /// /// Passed data uses a colorize_string formatter from a `paris` crate, so it can /// contains special tags for controlling ANSI colors and styles -/// More info: https://docs.rs/paris/1.5.7/paris/formatter/fn.colorize_string.html +/// More info: /// /// # Examples /// @@ -83,7 +83,7 @@ macro_rules! trace { /// /// Passed data uses a colorize_string formatter from a `paris` crate, so it can /// contains special tags for controlling ANSI colors and styles -/// More info: https://docs.rs/paris/1.5.7/paris/formatter/fn.colorize_string.html +/// More info: /// /// # Examples /// @@ -108,7 +108,7 @@ macro_rules! warn { /// /// Passed data uses a colorize_string formatter from a `paris` crate, so it can /// contains special tags for controlling ANSI colors and styles -/// More info: https://docs.rs/paris/1.5.7/paris/formatter/fn.colorize_string.html +/// More info: /// /// # Examples /// From cda775724849ff11ac2549723496b1afa7b8a737 Mon Sep 17 00:00:00 2001 From: Mariusz Bialonczyk Date: Thu, 11 Nov 2021 05:43:43 +0100 Subject: [PATCH 4/4] config: make set_write_log_enable_colors() an ansi_term feature dependant --- src/config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config.rs b/src/config.rs index a53a2be6..be3a79c7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -196,6 +196,7 @@ impl ConfigBuilder { } /// set if you want to write colors in the logfile (default is Off) + #[cfg(feature = "ansi_term")] pub fn set_write_log_enable_colors(&mut self, local: bool) -> &mut ConfigBuilder { self.0.write_log_enable_colors = local; self