spdlog/
log_macros.rs

1/// Logs a message at the specified level.
2///
3/// This macro will generically log with the specified [`Level`] and `format!`
4/// based argument list.
5#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
6/// # Examples
7///
8/// ```
9/// use spdlog::{log, Level};
10///
11/// # let app_events = spdlog::default_logger();
12/// let data = (42, "Forty-two");
13///
14/// // Using the global default logger
15/// log!(Level::Info, "received data: {}, {}", data.0, data.1);
16///
17/// // Or using the specified logger, and structured logging
18/// log!(logger: app_events, Level::Info, "received data", kv: { data:? });
19/// ```
20///
21/// [`Level`]: crate::Level
22#[macro_export]
23macro_rules! log {
24    ($($input:tt)+) => {
25        $crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}], $($input)+)
26    };
27}
28
29#[doc(hidden)]
30#[macro_export]
31macro_rules! __log_impl {
32    (logger: $logger:expr, kv: $kv:tt, $level:expr, $($arg:tt)+) => ({
33        let logger = &$logger;
34        if $crate::STATIC_LEVEL_FILTER.__test_const($level) && logger.should_log($level) {
35            $crate::__log(logger, $level, $crate::source_location_current!(), $crate::__kv!($kv), format_args!($($arg)+));
36        }
37    });
38}
39
40/// Logs a message at the critical level.
41#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
42/// # Examples
43///
44/// ```
45/// use spdlog::critical;
46///
47/// # let app_events = spdlog::default_logger();
48/// let (left, right) = (true, false);
49///
50/// // Using the global default logger
51/// critical!("runtime assertion failed. Left: `{}`, Right: `{}`", left, right);
52///
53/// // Or using the specified logger, and structured logging
54/// critical!(logger: app_events, "runtime assertion failed.", kv: { left, right });
55/// ```
56#[macro_export]
57macro_rules! critical {
58    ($($input:tt)+) => {
59        $crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Critical], $($input)+)
60    };
61}
62
63/// Logs a message at the error level.
64#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
65/// # Examples
66///
67/// ```
68/// use spdlog::error;
69///
70/// # let app_events = spdlog::default_logger();
71/// let (err_info, port) = ("No connection", 22);
72///
73/// // Using the global default logger
74/// error!("error: {} on port {}", err_info, port);
75///
76/// // Or using the specified logger, and structured logging
77/// error!(logger: app_events, "app error", kv: { reason = err_info, port });
78/// ```
79#[macro_export]
80macro_rules! error {
81    ($($input:tt)+) => {
82        $crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Error], $($input)+)
83    };
84}
85
86/// Logs a message at the warn level.
87#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
88/// # Examples
89///
90/// ```
91/// use spdlog::warn;
92///
93/// # let input_events = spdlog::default_logger();
94/// let warn_description = "Invalid Input";
95///
96/// // Using the global default logger
97/// warn!("warning! {}!", warn_description);
98///
99/// // Or using the specified logger, and structured logging
100/// warn!(logger: input_events, "app received warning", kv: { reason = warn_description });
101/// ```
102#[macro_export]
103macro_rules! warn {
104    ($($input:tt)+) => {
105        $crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Warn], $($input)+)
106    };
107}
108
109/// Logs a message at the info level.
110#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
111/// # Examples
112///
113/// ```
114/// use spdlog::info;
115///
116/// # struct Connection { port: u32, speed: f32 }
117/// # let conn_events = spdlog::default_logger();
118/// let conn_info = Connection { port: 40, speed: 3.20 };
119///
120/// // Using the global default logger
121/// info!("connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
122///
123/// // Or using the specified logger, and structured logging
124/// info!(logger: conn_events, "successfull connection", kv: { port = conn_info.port, speed = conn_info.speed });
125/// ```
126#[macro_export]
127macro_rules! info {
128    ($($input:tt)+) => {
129        $crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Info], $($input)+)
130    };
131}
132
133/// Logs a message at the debug level.
134#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
135/// # Examples
136///
137/// ```
138/// use spdlog::debug;
139///
140/// # struct Position { x: f32, y: f32 }
141/// # let app_events = spdlog::default_logger();
142/// let pos = Position { x: 3.234, y: -1.223 };
143///
144/// // Using the global default logger
145/// debug!("new position: x: {}, y: {}", pos.x, pos.y);
146///
147/// // Or using the specified logger, and structured logging
148/// debug!(logger: app_events, "new position", kv: { x = pos.x, y = pos.y });
149/// ```
150#[macro_export]
151macro_rules! debug {
152    ($($input:tt)+) => {
153        $crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Debug], $($input)+)
154    };
155}
156
157/// Logs a message at the trace level.
158#[doc = include_str!("./include/doc/log-macro-named-opt-params.md")]
159/// # Examples
160///
161/// ```
162/// use spdlog::trace;
163///
164/// # struct Position { x: f32, y: f32 }
165/// # let app_events = spdlog::default_logger();
166/// let pos = Position { x: 3.234, y: -1.223 };
167///
168/// // Using the global default logger
169/// trace!("position is: x: {}, y: {}", pos.x, pos.y);
170///
171/// // Or using the specified logger, and structured logging
172/// trace!(logger: app_events, "position updated", kv: { x = pos.x, y = pos.y });
173/// ```
174#[macro_export]
175macro_rules! trace {
176    ($($input:tt)+) => {
177        $crate::__normalize_forward!(__log_impl => default[logger: $crate::default_logger(), kv: {}, $crate::Level::Trace], $($input)+)
178    };
179}
180
181#[doc(hidden)]
182#[macro_export]
183macro_rules! __kv {
184    ({}) => (&[]);
185    ({ $($ttm:tt)+ }) => {
186        $crate::__kv!(@{} $($ttm)+)
187    };
188
189    (@{$($done:tt)*} $k:ident    $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [  ] $(= $v)?,} $($($rest)*)?));
190    (@{$($done:tt)*} $k:ident :  $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [: ] $(= $v)?,} $($($rest)*)?));
191    (@{$($done:tt)*} $k:ident :? $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [:?] $(= $v)?,} $($($rest)*)?));
192    (@{$($done:tt)*} $k:ident :sval $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [:sval] $(= $v)?,} $($($rest)*)?));
193    (@{$($done:tt)*} $k:ident :serde $(= $v:expr)? $(,$($rest:tt)*)?) => ($crate::__kv!(@{$($done)* $k [:serde] $(= $v)?,} $($($rest)*)?));
194    (@{$( $k:ident [$($modifier:tt)*] $(= $v:expr)? ),+ $(,)?}) => {
195        &[$(($crate::kv::Key::__from_static_str(stringify!($k)), $crate::__kv_value!($k [$($modifier)*] $(= $v)?))),+]
196    };
197}
198
199#[doc(hidden)]
200#[macro_export]
201macro_rules! __kv_value {
202    ($k:ident [$($modifier:tt)*]) => { $crate::__kv_value!($k [$($modifier)*] = $k) };
203    ($k:ident [  ] = $v:expr) => { $crate::kv::Value::from(&$v) };
204    ($k:ident [: ] = $v:expr) => { $crate::kv::Value::capture_display(&$v) };
205    ($k:ident [:?] = $v:expr) => { $crate::kv::Value::capture_debug(&$v) };
206    ($k:ident [:sval] = $v:expr) => { $crate::kv::Value::capture_sval2(&$v) };
207    ($k:ident [:serde] = $v:expr) => { $crate::kv::Value::capture_serde1(&$v) };
208}
209
210#[cfg(test)]
211mod tests {
212    use std::{
213        fmt::{self, Debug, Display},
214        sync::Arc,
215        vec,
216    };
217
218    use crate::{
219        kv::Key,
220        prelude::*,
221        sink::{GetSinkProp, Sink, SinkProp},
222        test_utils::{self, *},
223        utils::RefStr,
224        Record,
225    };
226
227    #[test]
228    fn syntax_and_records() {
229        let test_sink = Arc::new(TestSink::new());
230        let test = Arc::new(build_test_logger(|b| {
231            b.sink(test_sink.clone()).level_filter(LevelFilter::All)
232        }));
233
234        struct Mods;
235        impl Debug for Mods {
236            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237                write!(f, "debug")
238            }
239        }
240        impl Display for Mods {
241            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242                write!(f, "display")
243            }
244        }
245        let (int, mod1, mod2) = (114514, Mods, Mods);
246
247        const LEVEL_ARG: Level = Level::Info;
248
249        let assert_records = |kv: &[(&'static str, &str)], payload| {
250            let records = test_sink.records();
251            assert_eq!(records.len(), Level::count() + 1);
252            test_sink.clear();
253
254            records
255                .into_iter()
256                .zip([
257                    LEVEL_ARG,
258                    Level::Trace,
259                    Level::Debug,
260                    Level::Info,
261                    Level::Warn,
262                    Level::Error,
263                    Level::Critical,
264                ])
265                .for_each(|(record, expected_level)| {
266                    assert_eq!(record.level(), expected_level);
267                    assert_eq!(
268                        record
269                            .key_values()
270                            .into_iter()
271                            .map(|(k, v)| (k.inner(), v.to_string()))
272                            .collect::<Vec<_>>(),
273                        kv.iter()
274                            .map(|(k, v)| (RefStr::new_ref(k), v.to_string()))
275                            .collect::<Vec<_>>()
276                    );
277                    assert_eq!(record.payload(), payload);
278                });
279        };
280
281        log!(logger: test, LEVEL_ARG, "logger param only");
282        trace!(logger: test, "logger param only");
283        debug!(logger: test, "logger param only");
284        info!(logger: test, "logger param only");
285        warn!(logger: test, "logger param only");
286        error!(logger: test, "logger param only");
287        critical!(logger: test, "logger param only");
288        assert_records(&[], "logger param only");
289
290        log!(logger: test, kv: {}, LEVEL_ARG, "empty kv param");
291        trace!(logger: test, kv: {}, "empty kv param");
292        debug!(logger: test, kv: {}, "empty kv param");
293        info!(logger: test, kv: {}, "empty kv param");
294        warn!(logger: test, kv: {}, "empty kv param");
295        error!(logger: test, kv: {}, "empty kv param");
296        critical!(logger: test, kv: {}, "empty kv param");
297        assert_records(&[], "empty kv param");
298
299        log!(logger: test, kv: { int = 114514 }, LEVEL_ARG, "kv capture value directly");
300        trace!(logger: test, kv: { int = 114514 }, "kv capture value directly");
301        debug!(logger: test, kv: { int = 114514 }, "kv capture value directly");
302        info!(logger: test, kv: { int = 114514 }, "kv capture value directly");
303        warn!(logger: test, kv: { int = 114514 }, "kv capture value directly");
304        error!(logger: test, kv: { int = 114514 }, "kv capture value directly");
305        critical!(logger: test, kv: { int = 114514 }, "kv capture value directly");
306        assert_records(&[("int", "114514")], "kv capture value directly");
307
308        log!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, LEVEL_ARG, "kv capture value using modifiers");
309        trace!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
310        debug!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
311        info!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
312        warn!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
313        error!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
314        critical!(logger: test, kv: { int = 114514, mod1: = Mods, mod2:? = Mods }, "kv capture value using modifiers");
315        assert_records(
316            &[("int", "114514"), ("mod1", "display"), ("mod2", "debug")],
317            "kv capture value using modifiers",
318        );
319
320        log!(logger: test, kv: { int }, LEVEL_ARG, "kv shorthand");
321        trace!(logger: test, kv: { int }, "kv shorthand");
322        debug!(logger: test, kv: { int }, "kv shorthand");
323        info!(logger: test, kv: { int }, "kv shorthand");
324        warn!(logger: test, kv: { int }, "kv shorthand");
325        error!(logger: test, kv: { int }, "kv shorthand");
326        critical!(logger: test, kv: { int }, "kv shorthand");
327        assert_records(&[("int", "114514")], "kv shorthand");
328
329        log!(logger: test, kv: { int, mod1:, mod2:? }, LEVEL_ARG, "kv shorthand modifiers");
330        trace!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
331        debug!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
332        info!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
333        warn!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
334        error!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
335        critical!(logger: test, kv: { int, mod1:, mod2:? }, "kv shorthand modifiers");
336        assert_records(
337            &[("int", "114514"), ("mod1", "display"), ("mod2", "debug")],
338            "kv shorthand modifiers",
339        );
340
341        log!(logger: test, LEVEL_ARG, "params arbitrary order: logger, format, kv", kv: { mod1: });
342        trace!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
343        debug!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
344        info!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
345        warn!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
346        error!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
347        critical!(logger: test, "params arbitrary order: logger, format, kv", kv: { mod1: });
348        assert_records(
349            &[("mod1", "display")],
350            "params arbitrary order: logger, format, kv",
351        );
352
353        log!(LEVEL_ARG, "params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
354        trace!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
355        debug!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
356        info!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
357        warn!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
358        error!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
359        critical!("params arbitrary order = format, kv, logger", kv: { mod1:? }, logger: test);
360        assert_records(
361            &[("mod1", "debug")],
362            "params arbitrary order = format, kv, logger",
363        );
364
365        let runtime_level = Level::Info;
366        log!(logger: test, runtime_level, "runtime level");
367    }
368
369    #[test]
370    fn kv_types() {
371        struct Asserter {
372            prop: SinkProp,
373        }
374
375        impl GetSinkProp for Asserter {
376            fn prop(&self) -> &SinkProp {
377                &self.prop
378            }
379        }
380
381        impl Sink for Asserter {
382            fn should_log(&self, _: Level) -> bool {
383                true
384            }
385            fn flush(&self) -> crate::Result<()> {
386                Ok(())
387            }
388
389            fn log(&self, record: &Record) -> crate::Result<()> {
390                let kvs = record.key_values();
391                let value = kvs.get(Key::from_str("v")).unwrap();
392                assert_eq!(kvs.len(), 1);
393
394                match record.payload() {
395                    "1" => assert!(value.to_i64().is_some()),
396                    "2" => assert!(value.to_str().is_some()),
397                    "3" => assert!(value.to_i64().is_some()),
398                    "4" => assert!(value.to_i64().is_some()),
399                    "5" => assert!(value.is::<Vec<i32>>()),
400                    "6" => assert!(value.is::<Data>()),
401                    "7" => assert!(value.is::<Data>()),
402                    _ => panic!(),
403                }
404                Ok(())
405            }
406        }
407
408        let asserter = test_utils::build_test_logger(|b| {
409            b.sink(Arc::new(Asserter {
410                prop: SinkProp::default(),
411            }))
412        });
413
414        #[cfg_attr(feature = "sval", derive(sval_derive::Value))]
415        #[cfg_attr(feature = "serde", derive(serde::Serialize))]
416        struct Data {
417            i: i32,
418            v: Vec<i32>,
419        }
420        let data = Data {
421            i: 1,
422            v: vec![1, 2],
423        };
424
425        info!(logger: asserter, "1", kv: { v = 1 });
426        info!(logger: asserter, "2", kv: { v = "string" });
427        info!(logger: asserter, "3", kv: { v: = 1 });
428        info!(logger: asserter, "4", kv: { v:? = 1 });
429        #[cfg(feature = "sval")]
430        info!(logger: asserter, "5", kv: { v:sval = vec![1, 2] });
431        #[cfg(feature = "sval")]
432        info!(logger: asserter, "6", kv: { v:sval = data });
433        #[cfg(feature = "serde")]
434        info!(logger: asserter, "7", kv: { v:serde = data });
435    }
436}