| //! Log macro for log's kv-unstable backend. |
| //! |
| //! ## Example |
| //! |
| //! ```rust |
| //! use kv_log_macro::info; |
| //! |
| //! femme::start(log::LevelFilter::Info).unwrap(); |
| //! |
| //! info!("hello"); |
| //! info!("hello",); |
| //! info!("hello {}", "cats"); |
| //! info!("hello {}", "cats",); |
| //! info!("hello {}", "cats", { |
| //! cat_1: "chashu", |
| //! cat_2: "nori", |
| //! }); |
| //! ``` |
| |
| #![forbid(unsafe_code, future_incompatible, rust_2018_idioms)] |
| #![deny(missing_debug_implementations, nonstandard_style)] |
| #![warn(missing_docs, missing_doc_code_examples, unreachable_pub)] |
| // #![cfg_attr(test, deny(warnings))] |
| |
| use log::{logger, LevelFilter, Record}; |
| |
| use std::fmt; |
| |
| // publicly exporting so $crate::Level works. |
| pub use log::Level; |
| |
| /// The statically resolved maximum log level. |
| pub const STATIC_MAX_LEVEL: LevelFilter = LevelFilter::Debug; |
| |
| /// Returns the current maximum log level. |
| #[inline] |
| pub fn max_level() -> LevelFilter { |
| log::max_level() |
| } |
| |
| /// The standard logging macro. |
| /// |
| /// ``` |
| /// use kv_log_macro::info; |
| /// |
| /// info!("hello"); |
| /// info!("hello",); |
| /// info!("hello {}", "cats"); |
| /// info!("hello {}", "cats",); |
| /// info!("hello {}", "cats", { |
| /// cat_1: "chashu", |
| /// cat_2: "nori", |
| /// }); |
| /// ``` |
| #[macro_export(local_inner_macros)] |
| macro_rules! log { |
| // log!(target: "...", "...") |
| (target: $target:expr, $lvl:expr, $e:expr) => { |
| $crate::log_impl!(target: $target, $lvl, ($e)); |
| }; |
| |
| // log!(target: "...", "...", args...) |
| (target: $target:expr, $lvl:expr, $e:expr, $($rest:tt)*) => { |
| $crate::log_impl!(target: $target, $lvl, ($e) $($rest)*); |
| }; |
| |
| // log!("...", args...) |
| ($lvl:expr, $($arg:tt)+) => ($crate::log!(target: __log_module_path!(), $lvl, $($arg)+)) |
| } |
| |
| #[macro_export(local_inner_macros)] |
| #[doc(hidden)] |
| macro_rules! log_impl { |
| // End of macro input |
| (target: $target:expr, $lvl:expr, ($($arg:expr),*)) => { |
| let lvl = $lvl; |
| if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { |
| $crate::__private_api_log( |
| __log_format_args!($($arg),*), |
| lvl, |
| &($target, __log_module_path!(), __log_file!(), __log_line!()), |
| None, |
| ); |
| } |
| }; |
| |
| // // Trailing k-v pairs containing no trailing comma |
| (target: $target:expr, $lvl:expr, ($($arg:expr),*) { $($key:ident : $value:expr),* }) => { |
| let lvl = log::Level::Info; |
| if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() { |
| $crate::__private_api_log( |
| __log_format_args!($($arg),*), |
| lvl, |
| &(__log_module_path!(), __log_module_path!(), __log_file!(), __log_line!()), |
| Some(&[$((__log_stringify!($key), &$value)),*]) |
| ); |
| } |
| }; |
| |
| // Trailing k-v pairs with trailing comma |
| (target: $target:expr, $lvl:expr, ($($e:expr),*) { $($key:ident : $value:expr,)* }) => { |
| $crate::log_impl!(target: $target, $lvl, ($($e),*) { $($key : $value),* }); |
| }; |
| |
| // Last expression arg with no trailing comma |
| (target: $target:expr, $lvl:expr, ($($e:expr),*) $arg:expr) => { |
| $crate::log_impl!(target: $target, $lvl, ($($e,)* $arg)); |
| }; |
| |
| // Expression arg |
| (target: $target:expr, $lvl:expr, ($($e:expr),*) $arg:expr, $($rest:tt)*) => { |
| $crate::log_impl!(target: $target, $lvl, ($($e,)* $arg) $($rest)*); |
| }; |
| } |
| |
| /// Logs a message at the trace level. |
| #[macro_export(local_inner_macros)] |
| macro_rules! trace { |
| (target: $target:expr, $($arg:tt)+) => ( |
| log!(target: $target, $crate::Level::Trace, $($arg)+); |
| ); |
| ($($arg:tt)+) => ( |
| log!($crate::Level::Trace, $($arg)+); |
| ) |
| } |
| |
| /// Logs a message at the debug level. |
| #[macro_export(local_inner_macros)] |
| macro_rules! debug { |
| (target: $target:expr, $($arg:tt)+) => ( |
| log!(target: $target, $crate::Level::Debug, $($arg)+); |
| ); |
| ($($arg:tt)+) => ( |
| log!($crate::Level::Debug, $($arg)+); |
| ) |
| } |
| |
| /// Logs a message at the info level. |
| #[macro_export(local_inner_macros)] |
| macro_rules! info { |
| (target: $target:expr, $($arg:tt)+) => ( |
| log!(target: $target, $crate::Level::Info, $($arg)+); |
| ); |
| ($($arg:tt)+) => ( |
| log!($crate::Level::Info, $($arg)+); |
| ) |
| } |
| |
| /// Logs a message at the warn level. |
| #[macro_export(local_inner_macros)] |
| macro_rules! warn { |
| (target: $target:expr, $($arg:tt)+) => ( |
| log!(target: $target, $crate::Level::Warn, $($arg)+); |
| ); |
| ($($arg:tt)+) => ( |
| log!($crate::Level::Warn, $($arg)+); |
| ) |
| } |
| |
| /// Logs a message at the error level. |
| #[macro_export(local_inner_macros)] |
| macro_rules! error { |
| (target: $target:expr, $($arg:tt)+) => ( |
| log!(target: $target, $crate::Level::Error, $($arg)+); |
| ); |
| ($($arg:tt)+) => ( |
| log!($crate::Level::Error, $($arg)+); |
| ) |
| } |
| |
| /// Determines if a message logged at the specified level in that module will |
| /// be logged. |
| #[macro_export(local_inner_macros)] |
| macro_rules! log_enabled { |
| (target: $target:expr, $lvl:expr) => {{ |
| let lvl = $lvl; |
| lvl <= $crate::STATIC_MAX_LEVEL |
| && lvl <= $crate::max_level() |
| && $crate::__private_api_enabled(lvl, $target) |
| }}; |
| ($lvl:expr) => { |
| log_enabled!(target: __log_module_path!(), $lvl) |
| }; |
| } |
| |
| #[doc(hidden)] |
| #[macro_export] |
| macro_rules! __log_format_args { |
| ($($args:tt)*) => { |
| format_args!($($args)*) |
| }; |
| } |
| |
| #[doc(hidden)] |
| #[macro_export] |
| macro_rules! __log_module_path { |
| () => { |
| module_path!() |
| }; |
| } |
| |
| #[doc(hidden)] |
| #[macro_export] |
| macro_rules! __log_file { |
| () => { |
| file!() |
| }; |
| } |
| |
| #[doc(hidden)] |
| #[macro_export] |
| macro_rules! __log_line { |
| () => { |
| line!() |
| }; |
| } |
| |
| #[doc(hidden)] |
| #[macro_export] |
| macro_rules! __log_stringify { |
| ($($args:tt)*) => { |
| stringify!($($args)*) |
| }; |
| } |
| |
| // WARNING: this is not part of the crate's public API and is subject to change at any time |
| #[doc(hidden)] |
| pub fn __private_api_log( |
| args: fmt::Arguments<'_>, |
| level: Level, |
| &(target, module_path, file, line): &(&str, &'static str, &'static str, u32), |
| kvs: Option<&[(&str, &dyn log::kv::ToValue)]>, |
| ) { |
| logger().log( |
| &Record::builder() |
| .args(args) |
| .level(level) |
| .target(target) |
| .module_path_static(Some(module_path)) |
| .file_static(Some(file)) |
| .line(Some(line)) |
| .key_values(&kvs) |
| .build(), |
| ); |
| } |