stakker_log/
macros.rs

1// TODO: Add #[cfg] options to disable levels completely, eliminating
2// all the code associated with logging those levels completely from
3// the executable
4
5// TODO: Switch to proc macros to allow us to automatically access
6// `cx` without mentioning it explicitly.
7
8/// Log an error with context info
9///
10/// See [top-level docs](index.html) for details.
11#[macro_export]
12macro_rules! error {
13    ( $($x:tt)+ ) => {{
14        $crate::log!(Error $($x)+);
15    }}
16}
17
18/// Log a warning with context info
19///
20/// See [top-level docs](index.html) for details.
21#[macro_export]
22macro_rules! warn {
23    ( $($x:tt)+ ) => {{
24        $crate::log!(Warn $($x)+);
25    }}
26}
27
28/// Log information with context info
29///
30/// See [top-level docs](index.html) for details.
31#[macro_export]
32macro_rules! info {
33    ( $($x:tt)+ ) => {{
34        $crate::log!(Info $($x)+);
35    }}
36}
37
38/// Log debugging with context info
39///
40/// See [top-level docs](index.html) for details.
41#[macro_export]
42macro_rules! debug {
43    ( $($x:tt)+ ) => {{
44        $crate::log!(Debug $($x)+);
45    }}
46}
47
48/// Log tracing with context info
49///
50/// See [top-level docs](index.html) for details.
51#[macro_export]
52macro_rules! trace {
53    ( $($x:tt)+ ) => {{
54        $crate::log!(Trace $($x)+);
55    }}
56}
57
58/// Log an audit record
59///
60/// See [top-level docs](index.html) for details.
61#[macro_export]
62macro_rules! audit {
63    ( [$($cx:tt)+], $tag:ident $(, $($tail:tt)+)? ) => {{
64        $crate::log!(Audit [$($cx)+] $(, $($tail)+)? , "{}", ::std::stringify!($tag));
65    }};
66    ( [$($cx:tt)+], $tag:literal $(, $($tail:tt)+)? ) => {{
67        $crate::log!(Audit [$($cx)+] $(, $($tail)+)? , "{}", $tag);
68    }};
69    ( [$($cx:tt)+], ($tag:expr) $(, $($tail:tt)+)? ) => {{
70        $crate::log!(Audit [$($cx)+] $(, $($tail)+)? , "{}", $tag);
71    }};
72}
73
74#[macro_export]
75#[doc(hidden)]
76macro_rules! log_key_string {
77    ($key:ident) => {
78        ::std::stringify!($key)
79    };
80    ($base:ident . $($tail:tt)+) => {
81        $crate::log_key_string!($($tail)+)
82    };
83}
84
85/// Internal macro which handles translation to a log call
86//
87// Called with: `(level [cx] kv-args fmt fmt-args)`
88#[macro_export]
89macro_rules! log {
90    // Initial part
91    ($level:ident $fmt:literal $($tail:tt)*) => {{
92        ::std::compile_error!("Stakker logging macros need `[cx]` or `[core]` or `[actor, core]` as first argument");
93    }};
94    ($level:ident [$cx:expr] $(, $($tail:tt)+)?) => {{
95        $crate::log!($level [$cx, $cx] $(, $($tail)+)?)
96    }};
97    ($level:ident [$src:expr, $core:expr], target: $target:literal $(, $($tail:tt)+)?) => {{
98        $crate::log!([$src.access_log_id(), $core, $level, $target] $($($tail)+)?)
99    }};
100    ($level:ident [$src:expr, $core:expr] $(, $($tail:tt)+)?) => {{
101        $crate::log!([$src.access_log_id(), $core, $level, ""] $($($tail)+)?)
102    }};
103    ($level:ident $($tail:tt)*) => {{
104        ::std::compile_error!("Stakker logging macros need `[cx]` or `[core]` or `[actor, core]` as first argument");
105    }};
106    // Primitive values (no % or ?)
107    ([$($a:tt)*] $key1:ident $(. $key2:ident)*  $(, $($tail:tt)*)?) => {
108        $crate::log!([$($a)* ($crate::log_key_string!($key1$(.$key2)*), $key1$(.$key2)*)] $($($tail)*)?)
109    };
110    ([$($a:tt)*] $key:ident : $value:expr $(, $($tail:tt)*)?) => {
111        $crate::log!([$($a)* (::std::stringify!($key), $value)] $($($tail)*)?)
112    };
113    ([$($a:tt)*] $key:literal : $value:expr $(, $($tail:tt)*)?) => {
114        $crate::log!([$($a)* ($key, $value)] $($($tail)*)?)
115    };
116    // Display-formatted values (with %)
117    ([$($a:tt)*] % $key1:ident $(. $key2:ident)* $(, $($tail:tt)*)?) => {{
118        let v = &($key1$(.$key2)*); // Do borrow outside of closure
119        $crate::log!([$($a)* ($crate::log_key_string!($key1$(.$key2)*), format_args!("{}", v))] $($($tail)*)?)
120    }};
121    ([$($a:tt)*] $key:ident : % $value:expr $(, $($tail:tt)*)?) => {{
122        let v = &$value; // Do borrow outside of closure
123        $crate::log!([$($a)* (::std::stringify!($key), format_args!("{}", v))] $($($tail)*)?)
124    }};
125    ([$($a:tt)*] $key:literal : % $value:expr $(, $($tail:tt)*)?) => {{
126        let v = &$value; // Do borrow outside of closure
127        $crate::log!([$($a)* ($key, format_args!("{}", v))] $($($tail)*)?)
128    }};
129    // Debug-formatted values (with ?)
130    ([$($a:tt)*] ? $key1:ident $(. $key2:ident)* $(, $($tail:tt)*)?) => {{
131        let v = &($key1$(.$key2)*); // Do borrow outside of closure
132        $crate::log!([$($a)* ($crate::log_key_string!($key1$(.$key2)*), format_args!("{:?}", v))] $($($tail)*)?)
133    }};
134    ([$($a:tt)*] $key:ident : ? $value:expr $(, $($tail:tt)*)?) => {{
135        let v = &$value; // Do borrow outside of closure
136        $crate::log!([$($a)* (::std::stringify!($key), format_args!("{:?}", v))] $($($tail)*)?)
137    }};
138    ([$($a:tt)*] $key:literal : ? $value:expr $(, $($tail:tt)*)?) => {
139        let v = &$value; // Do borrow outside of closure
140        $crate::log!([$($a)* ($key, format_args!("{:?}", v))] $($($tail)*)?)
141    };
142    // Final output
143    ([$logid:expr, $core:expr, $level:ident, $target:literal $( ($key:expr, $val:expr) )*] $fmt:literal $(, $($tail:tt)*)?) => {{
144        use $crate::Visitable;
145        let id = $logid;
146        let core = $core.access_core();
147        core.log(
148            id,
149            $crate::stakker::LogLevel::$level,
150            $target,
151            ::std::format_args!( $fmt $(, $($tail)*)? ),
152            |output| {
153                $( $val.visit(Some($key), output); )*
154            });
155    }};
156}