micromegas_tracing/
macros.rs

1//! Internal macros for tracing functionality (logging, spans, metrics)
2
3#[macro_export]
4macro_rules! static_span_desc {
5    ($var_name:ident, $name:expr) => {
6        static $var_name: $crate::spans::SpanMetadata = $crate::spans::SpanMetadata {
7            name: $name,
8            location: $crate::spans::SpanLocation {
9                lod: $crate::levels::Verbosity::Max,
10                target: module_path!(),
11                module_path: module_path!(),
12                file: file!(),
13                line: line!(),
14            },
15        };
16    };
17}
18
19/// Records a sync span as two thread events
20///
21/// # Examples
22///
23/// ```
24/// use micromegas_tracing::span_scope;
25///
26/// # fn main() {
27/// span_scope!("scope");
28/// # }
29/// ```
30#[macro_export]
31macro_rules! span_scope {
32    ($static_var_name:ident, $name:expr) => {
33        $crate::static_span_desc!($static_var_name, $name);
34        let guard_named = $crate::guards::ThreadSpanGuard::new(&$static_var_name);
35    };
36    ($name:expr) => {
37        $crate::span_scope!(_METADATA_NAMED, $name);
38    };
39}
40
41/// Records a span with a name that is determined at runtime.
42/// The span name still needs to be statically allocated.
43///
44/// # Examples
45///
46/// ```
47/// use micromegas_tracing::span_scope_named;
48///
49/// # fn get_name() -> &'static str {
50/// #   return "name";
51/// # }
52/// #
53/// # fn main() {
54/// span_scope_named!(get_name());
55/// # }
56/// ```
57#[macro_export]
58macro_rules! span_scope_named {
59    ($static_var_name:ident, $name:expr) => {
60        static $static_var_name: $crate::spans::SpanLocation = $crate::spans::SpanLocation {
61            lod: $crate::levels::Verbosity::Max,
62            target: module_path!(),
63            module_path: module_path!(),
64            file: file!(),
65            line: line!(),
66        };
67        let guard_named = $crate::guards::ThreadNamedSpanGuard::new(&$static_var_name, $name);
68    };
69    ($name:expr) => {
70        $crate::span_scope_named!(_METADATA_NAMED, $name);
71    };
72}
73
74/// Creates a static SpanLocation for use with named async spans.
75/// This is an internal implementation detail - users should use `instrument_named!` instead.
76///
77/// # Examples
78///
79/// ```
80/// use micromegas_tracing::prelude::*;
81///
82/// # #[tokio::main]
83/// # async fn main() {
84/// // Don't use this directly - use instrument_named! instead
85/// static_span_location!(LOCATION);
86/// // Users should prefer: instrument_named!(future, "name")
87/// # }
88/// ```
89#[macro_export]
90macro_rules! static_span_location {
91    ($var_name:ident) => {
92        static $var_name: $crate::spans::SpanLocation = $crate::spans::SpanLocation {
93            lod: $crate::levels::Verbosity::Max,
94            target: module_path!(),
95            module_path: module_path!(),
96            file: file!(),
97            line: line!(),
98        };
99    };
100}
101
102/// Instruments an async block with a named span using a static string.
103/// This creates both the SpanLocation and instruments the future in one macro call.
104///
105/// # Examples
106///
107/// ```
108/// use micromegas_tracing::prelude::*;
109///
110/// # #[tokio::main]
111/// # async fn main() {
112/// let result = span_async_named!("database_query", async {
113///     // async work here
114///     42
115/// }).await;
116/// # }
117/// ```
118#[macro_export]
119macro_rules! span_async_named {
120    ($name:expr, $async_block:expr) => {{
121        use $crate::spans::InstrumentFuture as _;
122        $crate::static_span_location!(_ASYNC_LOCATION);
123        $async_block.__instrument_named_internal(&_ASYNC_LOCATION, $name)
124    }};
125}
126
127/// Instruments a future with a named span.
128/// Usage: `instrument_named!(future, "span_name")`
129///
130/// # Examples
131///
132/// ```
133/// use micromegas_tracing::prelude::*;
134///
135/// # #[tokio::main]
136/// # async fn main() {
137/// let future = async { 42 };
138/// let result = instrument_named!(future, "operation_name").await;
139/// # }
140/// ```
141#[macro_export]
142macro_rules! instrument_named {
143    ($future:expr, $name:expr) => {{
144        use $crate::spans::InstrumentFuture as _;
145        $crate::static_span_location!(_INSTRUMENT_LOCATION);
146        $future.__instrument_named_internal(&_INSTRUMENT_LOCATION, $name)
147    }};
148}
149
150/// Records a integer metric.
151///
152/// # Examples
153///
154/// ```
155/// use micromegas_tracing::imetric;
156///
157/// # fn main() {
158/// #
159/// imetric!("Frame Time", "ticks", 1000);
160/// # }
161/// ```
162#[macro_export]
163macro_rules! imetric {
164    ($name:expr, $unit:expr, $value:expr) => {{
165        static METRIC_METADATA: $crate::metrics::StaticMetricMetadata =
166            $crate::metrics::StaticMetricMetadata {
167                lod: $crate::levels::Verbosity::Max,
168                name: $name,
169                unit: $unit,
170                target: module_path!(),
171                file: file!(),
172                line: line!(),
173            };
174        $crate::dispatch::int_metric(&METRIC_METADATA, $value);
175    }};
176    ($name:expr, $unit:expr, $properties:expr, $value:expr) => {{
177        static METRIC_METADATA: $crate::metrics::StaticMetricMetadata =
178            $crate::metrics::StaticMetricMetadata {
179                lod: $crate::levels::Verbosity::Max,
180                name: $name,
181                unit: $unit,
182                target: module_path!(),
183                file: file!(),
184                line: line!(),
185            };
186        $crate::dispatch::tagged_integer_metric(&METRIC_METADATA, $properties, $value);
187    }};
188}
189
190/// Records a float metric.
191///
192/// # Examples
193///
194/// ```
195/// use micromegas_tracing::fmetric;
196///
197/// # fn main() {
198/// #
199/// fmetric!("Frame Time", "ticks", 1000.0);
200/// # }
201/// ```
202#[macro_export]
203macro_rules! fmetric {
204    ($name:expr, $unit:expr, $value:expr) => {{
205        static METRIC_METADATA: $crate::metrics::StaticMetricMetadata =
206            $crate::metrics::StaticMetricMetadata {
207                lod: $crate::levels::Verbosity::Max,
208                name: $name,
209                unit: $unit,
210                target: module_path!(),
211                file: file!(),
212                line: line!(),
213            };
214        $crate::dispatch::float_metric(&METRIC_METADATA, $value);
215    }};
216
217    ($name:expr, $unit:expr, $properties:expr, $value:expr) => {{
218        static METRIC_METADATA: $crate::metrics::StaticMetricMetadata =
219            $crate::metrics::StaticMetricMetadata {
220                lod: $crate::levels::Verbosity::Max,
221                name: $name,
222                unit: $unit,
223                target: module_path!(),
224                file: file!(),
225                line: line!(),
226            };
227        $crate::dispatch::tagged_float_metric(&METRIC_METADATA, $properties, $value);
228    }};
229}
230
231/// The standard logging macro.
232///
233/// This macro will generically log with the specified `Level` and `format!`
234/// based argument list.
235///
236/// # Examples
237///
238/// ```
239/// use micromegas_tracing::prelude::*;
240///
241/// # fn main() {
242/// let data = (42, "Forty-two");
243/// let private_data = "private";
244///
245/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
246/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
247///     data.0, data.1, private_data);
248/// # }
249/// ```
250#[macro_export]
251macro_rules! log {
252    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
253        static LOG_DESC: $crate::logs::LogMetadata = $crate::logs::LogMetadata {
254            level: $lvl,
255            level_filter: std::sync::atomic::AtomicU32::new($crate::logs::FILTER_LEVEL_UNSET_VALUE),
256            fmt_str: $crate::__first_arg!($($arg)+),
257            target: $target,
258            module_path: $crate::__log_module_path!(),
259            file: file!(),
260            line: line!(),
261        };
262        if $lvl <= $crate::levels::STATIC_MAX_LEVEL && $lvl <= $crate::levels::max_level() {
263            $crate::dispatch::log(&LOG_DESC, format_args!($($arg)+));
264        }
265    });
266    ($lvl:expr, properties: $properties:expr, $($arg:tt)+) => ({
267        static LOG_DESC: $crate::logs::LogMetadata = $crate::logs::LogMetadata {
268            level: $lvl,
269            level_filter: std::sync::atomic::AtomicU32::new($crate::logs::FILTER_LEVEL_UNSET_VALUE),
270            fmt_str: $crate::__first_arg!($($arg)+),
271            target: $crate::__log_module_path!(),
272            module_path: $crate::__log_module_path!(),
273            file: file!(),
274            line: line!(),
275        };
276        if $lvl <= $crate::levels::STATIC_MAX_LEVEL && $lvl <= $crate::levels::max_level() {
277            $crate::dispatch::log_tagged(&LOG_DESC, $properties, format_args!($($arg)+));
278        }
279    });
280    ($lvl:expr, $($arg:tt)+) => ($crate::log!(target: $crate::__log_module_path!(), $lvl, $($arg)+));
281}
282/// Logs a message at the error level.
283///
284/// # Examples
285///
286/// ```
287/// use micromegas_tracing::prelude::*;
288///
289/// # fn main() {
290/// let (err_info, port) = ("No connection", 22);
291///
292/// error!("Error: {} on port {}", err_info, port);
293/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
294/// # }
295/// ```
296#[macro_export]
297macro_rules! error {
298    (target: $target:expr, $($arg:tt)+) => (
299        $crate::log!(target: $target, $crate::levels::Level::Error, $($arg)+)
300    );
301    ($($arg:tt)+) => (
302        $crate::log!($crate::levels::Level::Error, $($arg)+)
303    )
304}
305
306/// Logs a message representing a crash or panic
307#[macro_export]
308macro_rules! fatal {
309    (target: $target:expr, $($arg:tt)+) => (
310        $crate::log!(target: $target, $crate::levels::Level::Fatal, $($arg)+)
311    );
312    ($($arg:tt)+) => (
313        $crate::log!($crate::levels::Level::Fatal, $($arg)+)
314    )
315}
316
317/// Logs a message at the warn level.
318///
319/// # Examples
320///
321/// ```
322/// use micromegas_tracing::prelude::*;
323///
324/// # fn main() {
325/// let warn_description = "Invalid Input";
326///
327/// warn!("Warning! {}!", warn_description);
328/// warn!(target: "input_events", "App received warning: {}", warn_description);
329/// # }
330/// ```
331#[macro_export]
332macro_rules! warn {
333    (target: $target:expr, $($arg:tt)+) => (
334        $crate::log!(target: $target, $crate::levels::Level::Warn, $($arg)+)
335    );
336    ($($arg:tt)+) => (
337        $crate::log!($crate::levels::Level::Warn, $($arg)+)
338    )
339}
340
341/// Logs a message at the info level.
342///
343/// # Examples
344///
345/// ```
346/// use micromegas_tracing::prelude::*;
347///
348/// # fn main() {
349/// # struct Connection { port: u32, speed: f32 }
350/// let conn_info = Connection { port: 40, speed: 3.20 };
351///
352/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
353/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}",
354///       conn_info.port, conn_info.speed);
355/// # }
356/// ```
357#[macro_export]
358macro_rules! info {
359    (target: $target:expr, $($arg:tt)+) => (
360        $crate::log!(target: $target, $crate::levels::Level::Info, $($arg)+)
361    );
362    ($($arg:tt)+) => (
363        $crate::log!($crate::levels::Level::Info, $($arg)+)
364    )
365}
366
367/// Logs a message at the debug level.
368///
369/// # Examples
370///
371/// ```
372/// use micromegas_tracing::debug;
373///
374/// # fn main() {
375/// # struct Position { x: f32, y: f32 }
376/// let pos = Position { x: 3.234, y: -1.223 };
377///
378/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
379/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
380/// # }
381/// ```
382#[macro_export]
383macro_rules! debug {
384    (target: $target:expr, $($arg:tt)+) => (
385        $crate::log!(target: $target, $crate::levels::Level::Debug, $($arg)+)
386    );
387    ($($arg:tt)+) => (
388        $crate::log!($crate::levels::Level::Debug, $($arg)+)
389    )
390}
391
392/// Logs a message at the trace level.
393///
394/// # Examples
395///
396/// ```
397/// use micromegas_tracing::trace;
398///
399/// # fn main() {
400/// # struct Position { x: f32, y: f32 }
401/// let pos = Position { x: 3.234, y: -1.223 };
402///
403/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
404/// trace!(target: "app_events", "x is {} and y is {}",
405///        if pos.x >= 0.0 { "positive" } else { "negative" },
406///        if pos.y >= 0.0 { "positive" } else { "negative" });
407/// # }
408/// ```
409#[macro_export]
410macro_rules! trace {
411    (target: $target:expr, $($arg:tt)+) => (
412        $crate::log!(target: $target, $crate::levels::Level::Trace, $($arg)+)
413    );
414    ($($arg:tt)+) => (
415        $crate::log!($crate::levels::Level::Trace, $($arg)+)
416    )
417}
418
419/// Determines if a message logged at the specified level in that module will
420/// be logged.
421///
422/// This can be used to avoid expensive computation of log message arguments if
423/// the message would be ignored anyway.
424///
425/// # Examples
426///
427/// ```
428/// use micromegas_tracing::prelude::*;
429///
430/// # fn foo() {
431/// if log_enabled!(Level::Debug) {
432///     let data = expensive_call();
433///     debug!("expensive debug data: {} {}", data.x, data.y);
434/// }
435/// if log_enabled!(target: "Global", Level::Debug) {
436///    let data = expensive_call();
437///    debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
438/// }
439/// # }
440/// # struct Data { x: u32, y: u32 }
441/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
442/// # fn main() {}
443/// ```
444#[macro_export(local_inner_macros)]
445macro_rules! log_enabled {
446    (target: $target:expr, $lvl:expr) => {{
447        let lvl = $lvl;
448        static LOG_ENABLED_METADATA: $crate::logs::LogMetadata = $crate::logs::LogMetadata {
449            level: $lvl,
450            level_filter: std::sync::atomic::AtomicU32::new($crate::logs::FILTER_LEVEL_UNSET_VALUE),
451            fmt_str: "",
452            target: $target,
453            module_path: $crate::__log_module_path!(),
454            file: $crate::__log_file!(),
455            line: $crate::__log_line!(),
456        };
457        lvl <= $crate::levels::STATIC_MAX_LEVEL
458            && lvl <= $crate::levels::max_level()
459            && $crate::dispatch::log_enabled(&LOG_ENABLED_METADATA)
460    }};
461    ($lvl:expr) => {
462        $crate::log_enabled!(target: $crate::__log_module_path!(), $lvl)
463    };
464}
465
466//pub const fn type_name_of<T>(_: &T) -> &'static str {
467//    //until type_name_of_val is out of nightly-only
468//    std::any::type_name::<T>()
469//}
470
471#[doc(hidden)]
472#[macro_export]
473macro_rules! __function_name {
474    () => {{
475        // Okay, this is ugly, I get it. However, this is the best we can get on a stable rust.
476        fn f() {}
477        fn type_name_of<T>(_: T) -> &'static str {
478            std::any::type_name::<T>()
479        }
480        let name = type_name_of(f);
481        // `3` is the length of the `::f`.
482        &name[..name.len() - 3]
483    }};
484}
485
486#[doc(hidden)]
487#[macro_export]
488macro_rules! __first_arg {
489    ($first:tt) => {
490        $first
491    };
492    ($first:tt, $($args:tt)*) => {
493        $crate::__first_arg!($first)
494    };
495}
496
497#[doc(hidden)]
498#[macro_export]
499macro_rules! __log_format_args {
500    ($($args:tt)*) => {
501        format_args!($($args)*)
502    };
503}
504
505#[doc(hidden)]
506#[macro_export]
507macro_rules! __log_module_path {
508    () => {
509        module_path!()
510    };
511}
512
513#[doc(hidden)]
514#[macro_export]
515macro_rules! __log_file {
516    () => {
517        file!()
518    };
519}
520
521#[doc(hidden)]
522#[macro_export]
523macro_rules! __log_line {
524    () => {
525        line!()
526    };
527}