kv_log_macro/
lib.rs

1//! Log macro for log's kv-unstable backend.
2//!
3//! ## Example
4//!
5//! ```rust
6//! use kv_log_macro::info;
7//!
8//! femme::start(log::LevelFilter::Info).unwrap();
9//!
10//! info!("hello");
11//! info!("hello",);
12//! info!("hello {}", "cats");
13//! info!("hello {}", "cats",);
14//! info!("hello {}", "cats", {
15//!     cat_1: "chashu",
16//!     cat_2: "nori",
17//! });
18//! ```
19
20#![forbid(unsafe_code, future_incompatible, rust_2018_idioms)]
21#![deny(missing_debug_implementations, nonstandard_style)]
22#![warn(missing_docs, missing_doc_code_examples, unreachable_pub)]
23// #![cfg_attr(test, deny(warnings))]
24
25use log::{logger, LevelFilter, Record};
26
27use std::fmt;
28
29// publicly exporting so $crate::Level works.
30pub use log::Level;
31
32/// The statically resolved maximum log level.
33pub const STATIC_MAX_LEVEL: LevelFilter = log::STATIC_MAX_LEVEL;
34
35/// Returns the current maximum log level.
36#[inline]
37pub fn max_level() -> LevelFilter {
38    log::max_level()
39}
40
41/// The standard logging macro.
42///
43/// ```
44/// use kv_log_macro::info;
45///
46/// info!("hello");
47/// info!("hello",);
48/// info!("hello {}", "cats");
49/// info!("hello {}", "cats",);
50/// info!("hello {}", "cats", {
51///     cat_1: "chashu",
52///     cat_2: "nori",
53/// });
54/// ```
55#[macro_export(local_inner_macros)]
56macro_rules! log {
57    // log!(target: "...", "...")
58    (target: $target:expr, $lvl:expr, $e:expr) => {
59        $crate::log_impl!(target: $target, $lvl, ($e));
60    };
61
62    // log!(target: "...", "...", args...)
63    (target: $target:expr, $lvl:expr, $e:expr, $($rest:tt)*) => {
64        $crate::log_impl!(target: $target, $lvl, ($e) $($rest)*);
65    };
66
67    // log!("...", args...)
68    ($lvl:expr, $($arg:tt)+) => ($crate::log!(target: __log_module_path!(), $lvl, $($arg)+))
69}
70
71#[macro_export(local_inner_macros)]
72#[doc(hidden)]
73macro_rules! log_impl {
74    // End of macro input
75    (target: $target:expr, $lvl:expr, ($($arg:expr),*)) => {{
76        let lvl = $lvl;
77        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
78            $crate::__private_api_log(
79                __log_format_args!($($arg),*),
80                lvl,
81                &($target, __log_module_path!(), __log_file!(), __log_line!()),
82                None,
83            );
84        }
85    }};
86
87    // // Trailing k-v pairs containing no trailing comma
88    (target: $target:expr, $lvl:expr, ($($arg:expr),*) { $($key:ident : $value:expr),* }) => {{
89        if $lvl <= $crate::STATIC_MAX_LEVEL && $lvl <= $crate::max_level() {
90            $crate::__private_api_log(
91                __log_format_args!($($arg),*),
92                $lvl,
93                &(__log_module_path!(), __log_module_path!(), __log_file!(), __log_line!()),
94                Some(&[$((__log_stringify!($key), &$value)),*])
95            );
96        }
97    }};
98
99    // Trailing k-v pairs with trailing comma
100    (target: $target:expr, $lvl:expr, ($($e:expr),*) { $($key:ident : $value:expr,)* }) => {
101        $crate::log_impl!(target: $target, $lvl, ($($e),*) { $($key : $value),* });
102    };
103
104    // Last expression arg with no trailing comma
105    (target: $target:expr, $lvl:expr, ($($e:expr),*) $arg:expr) => {
106        $crate::log_impl!(target: $target, $lvl, ($($e,)* $arg));
107    };
108
109    // Expression arg
110    (target: $target:expr, $lvl:expr, ($($e:expr),*) $arg:expr, $($rest:tt)*) => {
111        $crate::log_impl!(target: $target, $lvl, ($($e,)* $arg) $($rest)*);
112    };
113}
114
115/// Logs a message at the trace level.
116#[macro_export(local_inner_macros)]
117macro_rules! trace {
118    (target: $target:expr, $($arg:tt)+) => (
119        log!(target: $target, $crate::Level::Trace, $($arg)+);
120    );
121    ($($arg:tt)+) => (
122        log!($crate::Level::Trace, $($arg)+);
123    )
124}
125
126/// Logs a message at the debug level.
127#[macro_export(local_inner_macros)]
128macro_rules! debug {
129    (target: $target:expr, $($arg:tt)+) => (
130        log!(target: $target, $crate::Level::Debug, $($arg)+);
131    );
132    ($($arg:tt)+) => (
133        log!($crate::Level::Debug, $($arg)+);
134    )
135}
136
137/// Logs a message at the info level.
138#[macro_export(local_inner_macros)]
139macro_rules! info {
140    (target: $target:expr, $($arg:tt)+) => (
141        log!(target: $target, $crate::Level::Info, $($arg)+);
142    );
143    ($($arg:tt)+) => (
144        log!($crate::Level::Info, $($arg)+);
145    )
146}
147
148/// Logs a message at the warn level.
149#[macro_export(local_inner_macros)]
150macro_rules! warn {
151    (target: $target:expr, $($arg:tt)+) => (
152        log!(target: $target, $crate::Level::Warn, $($arg)+);
153    );
154    ($($arg:tt)+) => (
155        log!($crate::Level::Warn, $($arg)+);
156    )
157}
158
159/// Logs a message at the error level.
160#[macro_export(local_inner_macros)]
161macro_rules! error {
162    (target: $target:expr, $($arg:tt)+) => (
163        log!(target: $target, $crate::Level::Error, $($arg)+);
164    );
165    ($($arg:tt)+) => (
166        log!($crate::Level::Error, $($arg)+);
167    )
168}
169
170/// Determines if a message logged at the specified level in that module will
171/// be logged.
172#[macro_export(local_inner_macros)]
173macro_rules! log_enabled {
174    (target: $target:expr, $lvl:expr) => {{
175        let lvl = $lvl;
176        lvl <= $crate::STATIC_MAX_LEVEL
177            && lvl <= $crate::max_level()
178            && $crate::__private_api_enabled(lvl, $target)
179    }};
180    ($lvl:expr) => {
181        log_enabled!(target: __log_module_path!(), $lvl)
182    };
183}
184
185#[doc(hidden)]
186#[macro_export]
187macro_rules! __log_format_args {
188    ($($args:tt)*) => {
189        format_args!($($args)*)
190    };
191}
192
193#[doc(hidden)]
194#[macro_export]
195macro_rules! __log_module_path {
196    () => {
197        module_path!()
198    };
199}
200
201#[doc(hidden)]
202#[macro_export]
203macro_rules! __log_file {
204    () => {
205        file!()
206    };
207}
208
209#[doc(hidden)]
210#[macro_export]
211macro_rules! __log_line {
212    () => {
213        line!()
214    };
215}
216
217#[doc(hidden)]
218#[macro_export]
219macro_rules! __log_stringify {
220    ($($args:tt)*) => {
221        stringify!($($args)*)
222    };
223}
224
225// WARNING: this is not part of the crate's public API and is subject to change at any time
226#[doc(hidden)]
227pub fn __private_api_log(
228    args: fmt::Arguments<'_>,
229    level: Level,
230    &(target, module_path, file, line): &(&str, &'static str, &'static str, u32),
231    kvs: Option<&[(&str, &dyn log::kv::ToValue)]>,
232) {
233    logger().log(
234        &Record::builder()
235            .args(args)
236            .level(level)
237            .target(target)
238            .module_path_static(Some(module_path))
239            .file_static(Some(file))
240            .line(Some(line))
241            .key_values(&kvs)
242            .build(),
243    );
244}