diff --git a/CHANGELOG.md b/CHANGELOG.md index 53323cac..a94ea55c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## Unreleased - The `new` method of loggers are now `#[must_use]` to prevent confusion when `new` is used called instead of `init` ## v0.12.0 - - Replaces the semingly unmainted chrono library with the time crate. + - Replaces the semingly unmaintained chrono library with the time crate. - Addresses through this update - RUSTSEC-2020-0159 (chrono) - RUSTSEC-2020-0071 (time) @@ -45,7 +45,7 @@ ## v0.8.0 - Switch from `term` to `termcolor` (PR #59. credits to @raybritton) - Fix typo in docs (PR #58, credits to @anthonyjmartinez) - - Switch default padding to `Off`. Padding is annoyingly controversal, just set it to whatever you prefer, if you want it. + - Switch default padding to `Off`. Padding is annoyingly controversial, just set it to whatever you prefer, if you want it. ## v0.7.6 - Derive `Clone`,`Copy`,`PartialEq`,`Eq`,`Debug` and `Hash` for `TerminalMode`. (PR #56, credits to @panhania) @@ -98,7 +98,7 @@ - Fixed building non-default feature sets ## v0.4.3 - - Publically export TermLogger Error type + - Publicly export TermLogger Error type ## v0.4.2 - Removed a debug println! statement @@ -131,7 +131,7 @@ - Removed some internal code duplication ## v0.2.0 - - Local changes that (accidentially) made it to crates.io, but not git + - Local changes that (accidentally) made it to crates.io, but not git - Basically a worse version of *Antoni Boucher* 0.3.0 changes - Got noticed, when he made a Pull Request diff --git a/Cargo.toml b/Cargo.toml index 2895974f..32ca8f2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ local-offset = ["time/local-offset"] [dependencies] log = { version = "0.4.*", features = ["std"] } termcolor = { version = "1.1.*", optional = true } -paris = { version = "~1.5", optional = true } +paris = { version = "~1.5.12", optional = true } ansi_term = { version = "0.12", optional = true } -time = { version = "0.3.7", features = ["formatting", "macros"] } +time = { version = "0.3.11", optional = true, features = ["formatting", "macros"] } +chrono = { version = "0.4.26", optional = true } diff --git a/examples/custom_colors.rs b/examples/custom_colors.rs index 8d45a501..f3c1a0ea 100644 --- a/examples/custom_colors.rs +++ b/examples/custom_colors.rs @@ -1,4 +1,4 @@ -#[cfg(all(feature = "termcolor", not(feature = "paris")))] +#[cfg(feature = "termcolor")] use log::*; #[cfg(feature = "termcolor")] use simplelog::*; diff --git a/examples/default_colors.rs b/examples/default_colors.rs index 1d8d141b..3c6984ce 100644 --- a/examples/default_colors.rs +++ b/examples/default_colors.rs @@ -1,4 +1,4 @@ -#[cfg(all(feature = "termcolor", not(feature = "paris")))] +#[cfg(feature = "termcolor")] use log::*; #[cfg(feature = "termcolor")] use simplelog::*; diff --git a/examples/rgb_colors.rs b/examples/rgb_colors.rs index 8fc1c15a..6cffa9cc 100644 --- a/examples/rgb_colors.rs +++ b/examples/rgb_colors.rs @@ -1,8 +1,4 @@ -#[cfg(all( - not(target_family = "windows"), - feature = "termcolor", - not(feature = "paris") -))] +#[cfg(all(not(target_family = "windows"), feature = "termcolor"))] use log::*; #[cfg(all(not(target_family = "windows"), feature = "termcolor"))] use simplelog::*; diff --git a/examples/usage.rs b/examples/usage.rs index 8d4959c3..7e17295c 100644 --- a/examples/usage.rs +++ b/examples/usage.rs @@ -1,4 +1,3 @@ -#[cfg(not(feature = "paris"))] use log::*; use simplelog::*; diff --git a/src/config.rs b/src/config.rs index e18ccb37..f7db9292 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,9 +2,15 @@ use log::Level; use log::LevelFilter; +#[cfg(feature = "chrono")] +pub use chrono::{ + offset::{FixedOffset, Local, Offset, TimeZone, Utc}, + DateTime, +}; use std::borrow::Cow; #[cfg(feature = "termcolor")] use termcolor::Color; +#[cfg(not(feature = "chrono"))] pub use time::{format_description::FormatItem, macros::format_description, UtcOffset}; #[derive(Debug, Clone, Copy)] @@ -52,12 +58,23 @@ pub enum ThreadLogMode { } #[derive(Debug, Clone)] -pub(crate) enum TimeFormat { +pub enum TimeFormat { Rfc2822, Rfc3339, + #[cfg(feature = "chrono")] + Custom(Cow<'static, str>), + #[cfg(not(feature = "chrono"))] Custom(&'static [time::format_description::FormatItem<'static>]), } +#[derive(Debug, Clone)] +pub enum TimeOffset { + #[cfg(feature = "chrono")] + Chrono(chrono::offset::FixedOffset), + #[cfg(not(feature = "chrono"))] + Time(time::UtcOffset), +} + /// Configuration for the Loggers /// /// All loggers print the message in the following form: @@ -79,13 +96,18 @@ pub struct Config { pub(crate) target: LevelFilter, pub(crate) target_padding: TargetPadding, pub(crate) location: LevelFilter, + pub(crate) module: LevelFilter, + #[cfg(feature = "chrono")] + pub(crate) time_local: bool, pub(crate) time_format: TimeFormat, - pub(crate) time_offset: UtcOffset, + pub(crate) time_offset: TimeOffset, pub(crate) filter_allow: Cow<'static, [Cow<'static, str>]>, 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, + #[cfg(feature = "paris")] + pub(crate) enable_paris_formatting: bool, } /// Builder for the Logger Configurations (`Config`) @@ -147,6 +169,12 @@ impl ConfigBuilder { self } + /// Set at which level and above (more verbose) a module shall be logged (default is Off) + pub fn set_module_level(&mut self, module: LevelFilter) -> &mut ConfigBuilder { + self.0.module = module; + self + } + /// Set how the levels should be padded, when logging (default is Off) pub fn set_level_padding(&mut self, padding: LevelPadding) -> &mut ConfigBuilder { self.0.level_padding = padding; @@ -173,6 +201,27 @@ impl ConfigBuilder { self } + /// Set time chrono [strftime] format string. + /// + /// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers + + + + // #[cfg(feature = "chrono")] + // pub fn set_time_format_str(&mut self, time_format: &'static str) -> &mut ConfigBuilder { + // self.0.time_format = TimeFormat::Custom(Cow::Borrowed(time_format)); + // self + // } + + // /// Set time chrono [strftime] format string. + // /// + // /// [strftime]: https://docs.rs/chrono/0.4.0/chrono/format/strftime/index.html#specifiers + // #[cfg(feature = "chrono")] + // pub fn set_time_format(&mut self, time_format: String) -> &mut ConfigBuilder { + // self.0.time_format = TimeFormat::Custom(Cow::Owned(time_format)); + // self + // } + /// Sets the time format to a custom representation. /// /// The easiest way to satisfy the static lifetime of the argument is to directly use the @@ -191,6 +240,16 @@ impl ConfigBuilder { /// .set_time_format_custom(format_description!("[hour]:[minute]:[second].[subsecond]")) /// .build(); /// ``` + #[cfg(feature = "chrono")] + pub fn set_time_format_custom( + &mut self, + time_format: Cow<'static, str>, + ) -> &mut ConfigBuilder { + self.0.time_format = TimeFormat::Custom(time_format); + self + } + + #[cfg(not(feature = "chrono"))] pub fn set_time_format_custom( &mut self, time_format: &'static [FormatItem<'static>], @@ -212,8 +271,15 @@ impl ConfigBuilder { } /// Set offset used for logging time (default is UTC) - pub fn set_time_offset(&mut self, offset: UtcOffset) -> &mut ConfigBuilder { - self.0.time_offset = offset; + pub fn set_time_offset(&mut self, time_offset: TimeOffset) -> &mut ConfigBuilder { + self.0.time_offset = time_offset; + self + } + + /// set if you log in local timezone or UTC (default is UTC) + #[cfg(feature = "chrono")] + pub fn set_time_to_local(&mut self, local: bool) -> &mut ConfigBuilder { + self.0.time_local = local; self } @@ -224,6 +290,7 @@ impl ConfigBuilder { /// This may be the case, when the program is multi-threaded by the time of calling this function. /// One can opt-out of this behavior by setting `RUSTFLAGS="--cfg unsound_local_offset"`. /// Doing so is not recommended, completely untested and may cause unexpected segfaults. + #[cfg(not(feature = "chrono"))] #[cfg(feature = "local-offset")] pub fn set_time_offset_to_local(&mut self) -> Result<&mut ConfigBuilder, &mut ConfigBuilder> { match UtcOffset::current_local_offset() { @@ -242,8 +309,17 @@ impl ConfigBuilder { self } - /// Add allowed module filters. - /// If any are specified, only records from modules starting with one of these entries will be printed + /// set if you want paris formatting to be applied to this logger (default is On) + /// + /// If disabled, paris markup and formatting will be stripped. + #[cfg(feature = "paris")] + pub fn set_enable_paris_formatting(&mut self, enable_formatting: bool) -> &mut ConfigBuilder { + self.0.enable_paris_formatting = enable_formatting; + self + } + + /// Add allowed target filters. + /// If any are specified, only records from targets matching one of these entries will be printed /// /// For example, `add_filter_allow_str("tokio::uds")` would allow only logging from the `tokio` crates `uds` module. pub fn add_filter_allow_str(&mut self, filter_allow: &'static str) -> &mut ConfigBuilder { @@ -253,10 +329,10 @@ impl ConfigBuilder { self } - /// Add allowed module filters. - /// If any are specified, only records from modules starting with one of these entries will be printed + /// Add allowed target filters. + /// If any are specified, only records from targets matching one of these entries will be printed /// - /// For example, `add_filter_allow(format!("{}{}","tokio", "uds"))` would allow only logging from the `tokio` crates `uds` module. + /// For example, `add_filter_allow(format!("{}::{}","tokio", "uds"))` would allow only logging from the `tokio` crates `uds` module. pub fn add_filter_allow(&mut self, filter_allow: String) -> &mut ConfigBuilder { let mut list = Vec::from(&*self.0.filter_allow); list.push(Cow::Owned(filter_allow)); @@ -264,15 +340,15 @@ impl ConfigBuilder { self } - /// Clear allowed module filters. + /// Clear allowed target filters. /// If none are specified, nothing is filtered out pub fn clear_filter_allow(&mut self) -> &mut ConfigBuilder { self.0.filter_allow = Cow::Borrowed(&[]); self } - /// Add denied module filters. - /// If any are specified, records from modules starting with one of these entries will be ignored + /// Add denied target filters. + /// If any are specified, records from targets matching one of these entries will be ignored /// /// For example, `add_filter_ignore_str("tokio::uds")` would deny logging from the `tokio` crates `uds` module. pub fn add_filter_ignore_str(&mut self, filter_ignore: &'static str) -> &mut ConfigBuilder { @@ -282,10 +358,10 @@ impl ConfigBuilder { self } - /// Add denied module filters. - /// If any are specified, records from modules starting with one of these entries will be ignored + /// Add denied target filters. + /// If any are specified, records from targets matching one of these entries will be ignored /// - /// For example, `add_filter_ignore(format!("{}{}","tokio", "uds"))` would deny logging from the `tokio` crates `uds` module. + /// For example, `add_filter_ignore(format!("{}::{}","tokio", "uds"))` would deny logging from the `tokio` crates `uds` module. pub fn add_filter_ignore(&mut self, filter_ignore: String) -> &mut ConfigBuilder { let mut list = Vec::from(&*self.0.filter_ignore); list.push(Cow::Owned(filter_ignore)); @@ -293,7 +369,7 @@ impl ConfigBuilder { self } - /// Clear ignore module filters. + /// Clear ignore target filters. /// If none are specified, nothing is filtered pub fn clear_filter_ignore(&mut self) -> &mut ConfigBuilder { self.0.filter_ignore = Cow::Borrowed(&[]); @@ -324,8 +400,17 @@ impl Default for Config { target: LevelFilter::Debug, target_padding: TargetPadding::Off, location: LevelFilter::Trace, + module: LevelFilter::Off, + #[cfg(feature = "chrono")] + time_local: false, + #[cfg(feature = "chrono")] + time_format: TimeFormat::Custom(Cow::Borrowed("%H:%M:%S")), + #[cfg(not(feature = "chrono"))] time_format: TimeFormat::Custom(format_description!("[hour]:[minute]:[second]")), - time_offset: UtcOffset::UTC, + #[cfg(feature = "chrono")] + time_offset: TimeOffset::Chrono(FixedOffset::east_opt(0).unwrap()), + #[cfg(not(feature = "chrono"))] + time_offset: TimeOffset::Time(UtcOffset::UTC), filter_allow: Cow::Borrowed(&[]), filter_ignore: Cow::Borrowed(&[]), write_log_enable_colors: false, @@ -339,6 +424,9 @@ impl Default for Config { Some(Color::Cyan), // Debug Some(Color::White), // Trace ], + + #[cfg(feature = "paris")] + enable_paris_formatting: true, } } } diff --git a/src/lib.rs b/src/lib.rs index 51c38787..39a13098 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,12 @@ mod config; mod loggers; +#[cfg(feature = "chrono")] +pub use self::config::{ + Config, ConfigBuilder, LevelPadding, TargetPadding, ThreadLogMode, ThreadPadding, +}; + +#[cfg(not(feature = "chrono"))] pub use self::config::{ format_description, Config, ConfigBuilder, FormatItem, LevelPadding, TargetPadding, ThreadLogMode, ThreadPadding, @@ -39,15 +45,12 @@ pub use termcolor::{Color, ColorChoice}; pub use log::{Level, LevelFilter}; use log::Log; -#[cfg(all(test, not(feature = "paris")))] +#[cfg(test)] use log::*; -#[cfg(feature = "paris")] -pub(crate) mod paris_macros; #[cfg(feature = "paris")] #[doc(hidden)] pub mod __private { - pub use log; pub use paris; } @@ -118,7 +121,7 @@ mod tests { File::create("thread_naming.log").unwrap(), ) as Box); - for elem in vec![ + for elem in [ LevelFilter::Off, LevelFilter::Trace, LevelFilter::Debug, diff --git a/src/loggers/logging.rs b/src/loggers/logging.rs index a09bff3d..3ed7433d 100644 --- a/src/loggers/logging.rs +++ b/src/loggers/logging.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "chrono")] +use crate::config::TargetPadding; +#[cfg(not(feature = "chrono"))] use crate::config::{TargetPadding, TimeFormat}; use crate::{Config, LevelPadding, ThreadLogMode, ThreadPadding}; use log::{LevelFilter, Record}; @@ -57,9 +60,33 @@ where write_location(record, write)?; } - write_args(record, write) + if config.module <= record.level() && config.module != LevelFilter::Off { + write_module(record, write)?; + } + + #[cfg(feature = "paris")] + return write_args(record, write, config.enable_paris_formatting); + #[cfg(not(feature = "paris"))] + return write_args(record, write); +} + +#[cfg(feature = "chrono")] +#[inline(always)] +pub fn write_time(write: &mut W, config: &Config) -> Result<(), Error> +where + W: Write + Sized, +{ + let cur_time = if config.time_local { + (chrono::Local::now() + config.time_offset).format(&*config.time_format) + } else { + (chrono::Utc::now() + config.time_offset).format(&*config.time_format) + }; + + write!(write, "{} ", cur_time)?; + Ok(()) } +#[cfg(not(feature = "chrono"))] #[inline(always)] pub fn write_time(write: &mut W, config: &Config) -> Result<(), Error> where @@ -164,6 +191,16 @@ where Ok(()) } +#[inline(always)] +pub fn write_module(record: &Record<'_>, write: &mut W) -> Result<(), Error> +where + W: Write + Sized, +{ + let module = record.module_path().unwrap_or(""); + write!(write, "[{}] ", module)?; + Ok(()) +} + pub fn write_thread_name(write: &mut W, config: &Config) -> Result<(), Error> where W: Write + Sized, @@ -193,7 +230,7 @@ where { let id = format!("{:?}", thread::current().id()); let id = id.replace("ThreadId(", ""); - let id = id.replace(")", ""); + let id = id.replace(')', ""); match config.thread_padding { ThreadPadding::Left { 0: qty } => { write!(write, "({id:>0$}) ", qty, id = id)?; @@ -209,6 +246,24 @@ where } #[inline(always)] +#[cfg(feature = "paris")] +pub fn write_args(record: &Record<'_>, write: &mut W, with_colors: bool) -> Result<(), Error> +where + W: Write + Sized, +{ + writeln!( + write, + "{}", + crate::__private::paris::formatter::format_string( + format!("{}", record.args()), + with_colors + ) + )?; + Ok(()) +} + +#[inline(always)] +#[cfg(not(feature = "paris"))] pub fn write_args(record: &Record<'_>, write: &mut W) -> Result<(), Error> where W: Write + Sized, diff --git a/src/loggers/termlog.rs b/src/loggers/termlog.rs index 9bf13f9a..3931a960 100644 --- a/src/loggers/termlog.rs +++ b/src/loggers/termlog.rs @@ -19,22 +19,17 @@ struct OutputStreams { } /// Specifies which streams should be used when logging -#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Default)] pub enum TerminalMode { /// Only use Stdout Stdout, /// Only use Stderr Stderr, /// Use Stderr for Errors and Stdout otherwise + #[default] Mixed, } -impl Default for TerminalMode { - fn default() -> TerminalMode { - TerminalMode::Mixed - } -} - /// The TermLogger struct. Provides a stderr/out based Logger implementation /// /// Supports colored output @@ -171,6 +166,13 @@ impl TermLogger { write_location(record, term_lock)?; } + if self.config.module <= record.level() && self.config.module != LevelFilter::Off { + write_module(record, term_lock)?; + } + + #[cfg(feature = "paris")] + write_args(record, term_lock, self.config.enable_paris_formatting)?; + #[cfg(not(feature = "paris"))] write_args(record, term_lock)?; // The log crate holds the logger as a `static mut`, which isn't dropped diff --git a/src/loggers/testlog.rs b/src/loggers/testlog.rs index 29660e27..68fcbd46 100644 --- a/src/loggers/testlog.rs +++ b/src/loggers/testlog.rs @@ -8,7 +8,10 @@ //! Module providing the TestLogger Implementation use super::logging::should_skip; +#[cfg(not(feature = "chrono"))] use crate::{config::TimeFormat, Config, LevelPadding, SharedLogger}; +#[cfg(feature = "chrono")] +use crate::{Config, LevelPadding, SharedLogger}; use log::{set_boxed_logger, set_max_level, LevelFilter, Log, Metadata, Record, SetLoggerError}; use std::thread; @@ -77,7 +80,7 @@ impl Log for TestLogger { fn log(&self, record: &Record<'_>) { if self.enabled(record.metadata()) { - let _ = log(&self.config, record); + log(&self.config, record); } } @@ -100,7 +103,7 @@ impl SharedLogger for TestLogger { #[inline(always)] pub fn log(config: &Config, record: &Record<'_>) { - if should_skip(&config, &record) { + if should_skip(config, record) { return; } @@ -124,9 +127,25 @@ pub fn log(config: &Config, record: &Record<'_>) { write_location(record); } + if config.module <= record.level() && config.module != LevelFilter::Off { + write_module(record); + } + write_args(record); } +#[cfg(feature = "chrono")] +#[inline(always)] +pub fn write_time(config: &Config) { + let cur_time = if config.time_local { + chrono::Local::now().naive_local() + config.time_offset + } else { + chrono::Utc::now().naive_utc() + config.time_offset + }; + print!("{} ", cur_time.format(&*config.time_format)); +} + +#[cfg(not(feature = "chrono"))] #[inline(always)] pub fn write_time(config: &Config) { use time::format_description::well_known::*; @@ -156,7 +175,7 @@ pub fn write_level(record: &Record<'_>, config: &Config) { pub fn write_thread_id() { let id = format!("{:?}", thread::current().id()); let id = id.replace("ThreadId(", ""); - let id = id.replace(")", ""); + let id = id.replace(')', ""); print!("({}) ", id); } @@ -175,6 +194,12 @@ pub fn write_location(record: &Record<'_>) { } } +#[inline(always)] +pub fn write_module(record: &Record<'_>) { + let module = record.module_path().unwrap_or(""); + print!("[{}] ", module); +} + #[inline(always)] pub fn write_args(record: &Record<'_>) { println!("{}", record.args()); diff --git a/src/paris_macros/mod.rs b/src/paris_macros/mod.rs deleted file mode 100644 index 4c8da020..00000000 --- a/src/paris_macros/mod.rs +++ /dev/null @@ -1,130 +0,0 @@ -/// Logs a message at the info level. -/// -/// 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: -/// -/// # Examples -/// -/// ```edition2018 -/// use log::info; -/// -/// # fn main() { -/// # struct Connection { port: u32, speed: f32 } -/// let conn_info = Connection { port: 40, speed: 3.20 }; -/// -/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed); -/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}", -/// conn_info.port, conn_info.speed); -/// # } -/// ``` -#[macro_export] -macro_rules! info { - ($($args:tt)+) => { - $crate::__private::log::info!("{}", $crate::__private::paris::formatter::colorize_string(format!($($args)*))); - }; -} - -/// Logs a message at the debug level. -/// -/// 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: -/// -/// # Examples -/// -/// ```edition2018 -/// use log::debug; -/// -/// # fn main() { -/// # struct Position { x: f32, y: f32 } -/// let pos = Position { x: 3.234, y: -1.223 }; -/// -/// debug!("New position: x: {}, y: {}", pos.x, pos.y); -/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y); -/// # } -/// ``` -#[macro_export] -macro_rules! debug { - ($($args:tt)+) => { - $crate::__private::log::debug!("{}", $crate::__private::paris::formatter::colorize_string(format!($($args)*))); - }; -} - -/// Logs a message at the trace level. -/// -/// 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: -/// -/// # Examples -/// -/// ```edition2018 -/// use log::trace; -/// -/// # fn main() { -/// # struct Position { x: f32, y: f32 } -/// let pos = Position { x: 3.234, y: -1.223 }; -/// -/// trace!("Position is: x: {}, y: {}", pos.x, pos.y); -/// trace!(target: "app_events", "x is {} and y is {}", -/// if pos.x >= 0.0 { "positive" } else { "negative" }, -/// if pos.y >= 0.0 { "positive" } else { "negative" }); -/// # } -/// ``` -#[macro_export] -macro_rules! trace { - ($($args:tt)+) => { - $crate::__private::log::trace!("{}", $crate::__private::paris::formatter::colorize_string(format!($($args)*))); - }; -} - -/// Logs a message at the warn level. -/// -/// 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: -/// -/// # Examples -/// -/// ```edition2018 -/// use log::warn; -/// -/// # fn main() { -/// let warn_description = "Invalid Input"; -/// -/// warn!("Warning! {}!", warn_description); -/// warn!(target: "input_events", "App received warning: {}", warn_description); -/// # } -/// ``` -#[macro_export] -macro_rules! warn { - ($($args:tt)+) => { - $crate::__private::log::warn!("{}", $crate::__private::paris::formatter::colorize_string(format!($($args)*))); - }; -} - -/// Logs a message at the error level. -/// -/// 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: -/// -/// # Examples -/// -/// ```edition2018 -/// use log::error; -/// -/// # fn main() { -/// let (err_info, port) = ("No connection", 22); -/// -/// error!("Error: {} on port {}", err_info, port); -/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22); -/// # } -/// ``` -#[macro_export] -macro_rules! error { - ($($args:tt)+) => { - $crate::__private::log::error!("{}", $crate::__private::paris::formatter::colorize_string(format!($($args)*))); - }; -}