Skip to main content

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 needs to be statically allocated; use `span_scope_named_dyn!` for a name built
43/// at runtime.
44///
45/// # Examples
46///
47/// ```
48/// use micromegas_tracing::span_scope_named;
49///
50/// # fn get_name() -> &'static str {
51/// #   return "name";
52/// # }
53/// #
54/// # fn main() {
55/// span_scope_named!(get_name());
56/// # }
57/// ```
58#[macro_export]
59macro_rules! span_scope_named {
60    ($static_var_name:ident, $name:expr) => {
61        static $static_var_name: $crate::spans::SpanLocation = $crate::spans::SpanLocation {
62            lod: $crate::levels::Verbosity::Max,
63            target: module_path!(),
64            module_path: module_path!(),
65            file: file!(),
66            line: line!(),
67        };
68        let guard_named = $crate::guards::ThreadNamedSpanGuard::new(&$static_var_name, $name);
69    };
70    ($name:expr) => {
71        $crate::span_scope_named!(_METADATA_NAMED, $name);
72    };
73}
74
75/// Records a span whose name is built at runtime, such as `format!(..)` or a `&String`.
76/// The name is copied into each block that records one of the span's events, so a high
77/// number of distinct names does not accumulate in memory.
78/// The guard owns the name, which is kept alive until the end of the scope.
79///
80/// # Examples
81///
82/// ```
83/// use micromegas_tracing::span_scope_named_dyn;
84///
85/// # fn main() {
86/// let asset = String::from("hero.png");
87/// span_scope_named_dyn!(format!("load {asset}"));
88/// # }
89/// ```
90#[macro_export]
91macro_rules! span_scope_named_dyn {
92    ($static_var_name:ident, $name:expr) => {
93        static $static_var_name: $crate::spans::SpanLocation = $crate::spans::SpanLocation {
94            lod: $crate::levels::Verbosity::Max,
95            target: module_path!(),
96            module_path: module_path!(),
97            file: file!(),
98            line: line!(),
99        };
100        let guard_named = $crate::guards::ThreadNamedSpanGuard::with_name(
101            &$static_var_name,
102            $crate::spans::DynSpanName($name),
103        );
104    };
105    ($name:expr) => {
106        $crate::span_scope_named_dyn!(_METADATA_NAMED, $name);
107    };
108}
109
110/// Creates a static SpanLocation for use with named async spans.
111/// This is an internal implementation detail - users should use `instrument_named!` instead.
112///
113/// # Examples
114///
115/// ```
116/// use micromegas_tracing::prelude::*;
117///
118/// # #[tokio::main]
119/// # async fn main() {
120/// // Don't use this directly - use instrument_named! instead
121/// static_span_location!(LOCATION);
122/// // Users should prefer: instrument_named!(future, "name")
123/// # }
124/// ```
125#[macro_export]
126macro_rules! static_span_location {
127    ($var_name:ident) => {
128        static $var_name: $crate::spans::SpanLocation = $crate::spans::SpanLocation {
129            lod: $crate::levels::Verbosity::Max,
130            target: module_path!(),
131            module_path: module_path!(),
132            file: file!(),
133            line: line!(),
134        };
135    };
136}
137
138/// Instruments an async block with a named span using a static string.
139/// This creates both the SpanLocation and instruments the future in one macro call.
140///
141/// # Examples
142///
143/// ```
144/// use micromegas_tracing::prelude::*;
145///
146/// # #[tokio::main]
147/// # async fn main() {
148/// let result = span_async_named!("database_query", async {
149///     // async work here
150///     42
151/// }).await;
152/// # }
153/// ```
154#[macro_export]
155macro_rules! span_async_named {
156    ($name:expr, $async_block:expr) => {{
157        use $crate::spans::InstrumentFuture as _;
158        $crate::static_span_location!(_ASYNC_LOCATION);
159        $async_block.__instrument_named_internal(&_ASYNC_LOCATION, $name)
160    }};
161}
162
163/// Instruments a future with a named span.
164/// Usage: `instrument_named!(future, "span_name")`
165///
166/// # Examples
167///
168/// ```
169/// use micromegas_tracing::prelude::*;
170///
171/// # #[tokio::main]
172/// # async fn main() {
173/// let future = async { 42 };
174/// let result = instrument_named!(future, "operation_name").await;
175/// # }
176/// ```
177#[macro_export]
178macro_rules! instrument_named {
179    ($future:expr, $name:expr) => {{
180        use $crate::spans::InstrumentFuture as _;
181        $crate::static_span_location!(_INSTRUMENT_LOCATION);
182        $future.__instrument_named_internal(&_INSTRUMENT_LOCATION, $name)
183    }};
184}
185
186/// Instruments an async block with a named span whose name is built at runtime.
187/// The future owns the name: pass a `String` or `Arc<str>` to keep the future `'static`.
188///
189/// # Examples
190///
191/// ```
192/// use micromegas_tracing::prelude::*;
193///
194/// # #[tokio::main]
195/// # async fn main() {
196/// let id = 7;
197/// let result = span_async_named_dyn!(format!("query {id}"), async {
198///     42
199/// }).await;
200/// # }
201/// ```
202#[macro_export]
203macro_rules! span_async_named_dyn {
204    ($name:expr, $async_block:expr) => {{
205        use $crate::spans::InstrumentFuture as _;
206        $crate::static_span_location!(_ASYNC_LOCATION);
207        $async_block.__instrument_named_dyn_internal(&_ASYNC_LOCATION, $name)
208    }};
209}
210
211/// Instruments a future with a named span whose name is built at runtime.
212/// The future owns the name: pass a `String` or `Arc<str>` to keep the future `'static`.
213/// Usage: `instrument_named_dyn!(future, format!("op {id}"))`
214///
215/// # Examples
216///
217/// ```
218/// use micromegas_tracing::prelude::*;
219///
220/// # #[tokio::main]
221/// # async fn main() {
222/// let future = async { 42 };
223/// let result = instrument_named_dyn!(future, format!("operation {}", 1)).await;
224/// # }
225/// ```
226#[macro_export]
227macro_rules! instrument_named_dyn {
228    ($future:expr, $name:expr) => {{
229        use $crate::spans::InstrumentFuture as _;
230        $crate::static_span_location!(_INSTRUMENT_LOCATION);
231        $future.__instrument_named_dyn_internal(&_INSTRUMENT_LOCATION, $name)
232    }};
233}
234
235/// Records a integer metric. Use [`imetric_dyn!`] when the name or unit is built at run time.
236///
237/// # Examples
238///
239/// ```
240/// use micromegas_tracing::imetric;
241///
242/// # fn main() {
243/// #
244/// imetric!("Frame Time", "ticks", 1000);
245/// # }
246/// ```
247///
248/// Properties go between the unit and the value, as `key = value` pairs. A key is an
249/// identifier or a string literal. Literal values are interned once per callsite, unless a `..set`
250/// is spread without a `static` value, in which case the literals are copied into the block
251/// (the spread set's own values are not); any other value is attached to the measure and copied
252/// into the current block. A
253/// bare value must implement [`PropertyValue`](crate::property_value::PropertyValue) (strings
254/// do); use `%value` (`Display`) or `?value` (`Debug`) for the rest, at the cost of one `String`
255/// allocation.
256///
257/// ```
258/// use micromegas_tracing::prelude::*;
259///
260/// # fn main() {
261/// let correlation_id = String::from("c0ffee");
262/// let rows = 3;
263/// imetric!("rows_fetched", "count", correlation_id = correlation_id, region = "eu", rows = %rows, 3);
264/// imetric!("rows_fetched", "count", "http.method" = "GET", 3);
265/// # }
266/// ```
267///
268/// A precomputed `&'static PropertySet` is spread with `..set`. It must come last in the
269/// property list, and `key = value` pairs override its entries:
270///
271/// ```
272/// use micromegas_tracing::prelude::*;
273/// use micromegas_tracing::property_set::{Property, PropertySet};
274///
275/// # fn main() {
276/// let set = PropertySet::find_or_create(vec![Property::new("region", "eu")]);
277/// imetric!("rows_fetched", "count", ..set, 3);
278/// imetric!("rows_fetched", "count", correlation_id = "c0ffee", ..set, 3);
279/// # }
280/// ```
281///
282/// `target: "name"` replaces the module path as the target of the metric:
283///
284/// ```
285/// use micromegas_tracing::prelude::*;
286///
287/// # fn main() {
288/// imetric!(target: "my_crate::cache", "hits", "count", kind = "disk", 1);
289/// # }
290/// ```
291///
292/// `key = static expr` takes a `&'static str` chosen at runtime, from a small closed set (a
293/// label or an enum variant name, for example). Each distinct tuple of static values is interned
294/// once per callsite and then looked up, a few nanoseconds more than a `..set` spread and far
295/// cheaper than a dynamic value. Every distinct value is kept forever, so the cardinality
296/// contract of `PropertySet` applies: never use it for ids. It mixes freely with literals,
297/// dynamic values and a trailing `..set`. Among literals and static values the last one wins
298/// (case-insensitive), a dynamic value beats both, and any pair overrides a `..set` entry. With
299/// `..set` and a static value in the same call, literals and static values are interned over the
300/// set, so dynamic values beat them whatever the order.
301///
302/// ```
303/// use micromegas_tracing::prelude::*;
304///
305/// # fn main() {
306/// let label: &'static str = "alpha";
307/// imetric!("rows_fetched", "count", prefix = static label, tier = "ram", 3);
308/// fmetric!("fetch_ms", "ms", prefix = static label, 1.5);
309/// # }
310/// ```
311///
312/// The value must be `'static`; a borrowed string is a compile error:
313///
314/// ```compile_fail
315/// use micromegas_tracing::prelude::*;
316///
317/// let s = String::from("alpha");
318/// imetric!("rows_fetched", "count", prefix = static s.as_str(), 3);
319/// ```
320///
321/// `static` doesn't combine with `%` or `?`:
322///
323/// ```compile_fail
324/// use micromegas_tracing::prelude::*;
325///
326/// imetric!("rows_fetched", "count", prefix = static %"x", 3);
327/// ```
328///
329/// `target`, `name` and `unit` are reserved keys, because analytics treats them as column
330/// overrides. They can still be set through a `..set` spread:
331///
332/// ```compile_fail
333/// use micromegas_tracing::prelude::*;
334///
335/// imetric!("rows_fetched", "count", unit = "rows", 3);
336/// ```
337///
338/// A literal value goes through `concat!`, so `1_000` is recorded as "1000" and `0x10` as "16",
339/// while a float keeps its spelling (`0.50` stays "0.50"); `%value` uses `Display` instead.
340///
341/// A bare integer needs `%`:
342///
343/// ```compile_fail
344/// use micromegas_tracing::prelude::*;
345///
346/// let n = 3_u32;
347/// imetric!("rows_fetched", "count", rows = n, 3);
348/// ```
349///
350/// A bare negated expression has no `PropertyValue` impl either:
351///
352/// ```compile_fail
353/// use micromegas_tracing::prelude::*;
354///
355/// let n = 3_i32;
356/// imetric!("rows_fetched", "count", delta = -n, 3);
357/// ```
358///
359/// `..set` can't be followed by other entries, and appears at most once:
360///
361/// ```compile_fail
362/// use micromegas_tracing::prelude::*;
363/// use micromegas_tracing::property_set::PropertySet;
364///
365/// let set = PropertySet::empty();
366/// imetric!("rows_fetched", "count", ..set, kind = "a", 3);
367/// ```
368///
369/// ```compile_fail
370/// use micromegas_tracing::prelude::*;
371/// use micromegas_tracing::property_set::PropertySet;
372///
373/// let set = PropertySet::empty();
374/// imetric!("rows_fetched", "count", ..set, ..set, 3);
375/// ```
376#[macro_export]
377macro_rules! imetric {
378    (target: $target:expr, $name:expr, $unit:expr, $($rest:tt)+) => {
379        $crate::__props!(@m metric
380            [$name, $unit, $target, int_metric, tagged_integer_metric_dyn]
381            [] [] [] [] [] $($rest)+)
382    };
383    ($name:expr, $unit:expr, $($rest:tt)+) => {
384        $crate::__props!(@m metric
385            [$name, $unit, module_path!(), int_metric, tagged_integer_metric_dyn]
386            [] [] [] [] [] $($rest)+)
387    };
388}
389
390/// Records a float metric.
391///
392/// # Examples
393///
394/// ```
395/// use micromegas_tracing::fmetric;
396///
397/// # fn main() {
398/// #
399/// fmetric!("Frame Time", "ticks", 1000.0);
400/// # }
401/// ```
402///
403/// Properties are `key = value` pairs between the unit and the value, as with [`imetric!`]:
404///
405/// ```
406/// use micromegas_tracing::prelude::*;
407///
408/// # fn main() {
409/// let elapsed_ms = 12.5;
410/// fmetric!("fetch_ms", "ms", "http.method" = "GET", elapsed_ms);
411/// fmetric!("delta", "ms", -elapsed_ms);
412/// # }
413/// ```
414#[macro_export]
415macro_rules! fmetric {
416    (target: $target:expr, $name:expr, $unit:expr, $($rest:tt)+) => {
417        $crate::__props!(@m metric
418            [$name, $unit, $target, float_metric, tagged_float_metric_dyn]
419            [] [] [] [] [] $($rest)+)
420    };
421    ($name:expr, $unit:expr, $($rest:tt)+) => {
422        $crate::__props!(@m metric
423            [$name, $unit, module_path!(), float_metric, tagged_float_metric_dyn]
424            [] [] [] [] [] $($rest)+)
425    };
426}
427
428/// Records an integer metric whose name or unit is only known at run time.
429///
430/// `name` and `unit` can be anything that implements `AsRef<str>`: a literal, a `&String`,
431/// `format!(..)` or an `Arc<str>`. They are copied into the current block once per distinct
432/// value, so nothing is retained for the life of the process. The rest of the grammar is the
433/// one of [`imetric!`].
434///
435/// Every distinct name is a distinct series for queries and materialized views, so the names
436/// should still come from a bounded set: deduplication within a block only bounds the cost on
437/// the wire. `name` and `unit` also appear in the `properties` column of the measure.
438///
439/// ```
440/// use micromegas_tracing::prelude::*;
441///
442/// # fn main() {
443/// let queue = "render";
444/// let depth = 3;
445/// imetric_dyn!(format!("queue.{queue}.depth"), "count", depth);
446/// imetric_dyn!(target: "my_crate::io", String::from("bytes_read"), "bytes", "http.method" = "GET", 512);
447/// # }
448/// ```
449///
450/// `name` and `unit` are reserved keys, as with [`imetric!`]:
451///
452/// ```compile_fail
453/// use micromegas_tracing::prelude::*;
454///
455/// imetric_dyn!("rows_fetched", "count", name = "other", 3);
456/// ```
457///
458/// `..set` must be the last property:
459///
460/// ```compile_fail
461/// use micromegas_tracing::prelude::*;
462/// use micromegas_tracing::property_set::PropertySet;
463///
464/// let set = PropertySet::empty();
465/// imetric_dyn!("rows_fetched", "count", ..set, kind = "a", 3);
466/// ```
467#[macro_export]
468macro_rules! imetric_dyn {
469    (target: $target:expr, $name:expr, $unit:expr, $($rest:tt)+) => {
470        $crate::__props!(@m metric
471            [$name, $unit, $target, int_metric, tagged_integer_metric_dyn, dynamic]
472            [] [] [] [] [] $($rest)+)
473    };
474    ($name:expr, $unit:expr, $($rest:tt)+) => {
475        $crate::__props!(@m metric
476            [$name, $unit, module_path!(), int_metric, tagged_integer_metric_dyn, dynamic]
477            [] [] [] [] [] $($rest)+)
478    };
479}
480
481/// Records a float metric whose name or unit is only known at run time.
482///
483/// Same as [`imetric_dyn!`], including the cardinality caveat, for a floating-point value.
484///
485/// ```
486/// use micromegas_tracing::prelude::*;
487///
488/// # fn main() {
489/// let (name, unit) = (String::from("http.latency"), "ms");
490/// let elapsed = 12.5;
491/// fmetric_dyn!(target: "my_crate::io", &name, unit, "http.method" = "GET", elapsed);
492/// # }
493/// ```
494///
495/// `name` and `unit` are reserved keys, as with [`fmetric!`]:
496///
497/// ```compile_fail
498/// use micromegas_tracing::prelude::*;
499///
500/// fmetric_dyn!("latency", "ms", unit = "s", 1.0);
501/// ```
502#[macro_export]
503macro_rules! fmetric_dyn {
504    (target: $target:expr, $name:expr, $unit:expr, $($rest:tt)+) => {
505        $crate::__props!(@m metric
506            [$name, $unit, $target, float_metric, tagged_float_metric_dyn, dynamic]
507            [] [] [] [] [] $($rest)+)
508    };
509    ($name:expr, $unit:expr, $($rest:tt)+) => {
510        $crate::__props!(@m metric
511            [$name, $unit, module_path!(), float_metric, tagged_float_metric_dyn, dynamic]
512            [] [] [] [] [] $($rest)+)
513    };
514}
515
516/// The standard logging macro.
517///
518/// This macro will generically log with the specified `Level` and `format!`
519/// based argument list.
520///
521/// # Examples
522///
523/// ```
524/// use micromegas_tracing::prelude::*;
525///
526/// # fn main() {
527/// let data = (42, "Forty-two");
528/// let private_data = "private";
529///
530/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
531/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
532///     data.0, data.1, private_data);
533/// # }
534/// ```
535///
536/// Properties go before the format string, as `key = value` pairs. A key is an identifier or a
537/// string literal. A literal value is interned once per callsite, unless a `..set` is spread
538/// without a `static` value, in which case the literals are copied into the block (the spread
539/// set's own values are not). Any other value (a request or correlation id, for example) is
540/// copied into the current block, so nothing leaks. A bare value must implement
541/// [`PropertyValue`](crate::property_value::PropertyValue) (strings do); use
542/// `%value` (`Display`) or `?value` (`Debug`) for the rest, at the cost of one `String`
543/// allocation. Dynamic values are only evaluated when the entry is enabled.
544///
545/// ```
546/// use micromegas_tracing::prelude::*;
547///
548/// # fn main() {
549/// let correlation_id = String::from("c0ffee");
550/// let rows = 3;
551/// info!(correlation_id = correlation_id, region = "eu", rows = %rows, "fetched {} rows", rows);
552/// info!(target: "app_events", "http.method" = "GET", "request done");
553/// # }
554/// ```
555///
556/// A precomputed `&'static PropertySet` is spread with `..set`. It must come last in the
557/// property list, and `key = value` pairs override its entries:
558///
559/// ```
560/// use micromegas_tracing::prelude::*;
561/// use micromegas_tracing::property_set::{Property, PropertySet};
562///
563/// # fn main() {
564/// let set = PropertySet::find_or_create(vec![Property::new("region", "eu")]);
565/// info!(..set, "from a set");
566/// info!(correlation_id = "c0ffee", ..set, "from a set and a pair");
567/// # }
568/// ```
569///
570/// `key = static expr` takes a `&'static str` chosen at runtime, from a small closed set (a
571/// label or an enum variant name, for example). Each distinct tuple of static values is interned
572/// once per callsite and then looked up, a few nanoseconds more than a `..set` spread and far
573/// cheaper than a dynamic value. Every distinct value is kept forever, so the cardinality
574/// contract of `PropertySet` applies: never use it for ids. It mixes freely with literals,
575/// dynamic values and a trailing `..set`. Among literals and static values the last one wins
576/// (case-insensitive), a dynamic value beats both, and any pair overrides a `..set` entry. With
577/// `..set` and a static value in the same call, literals and static values are interned over the
578/// set, so dynamic values beat them whatever the order. A static expression is only evaluated
579/// when the entry is enabled.
580///
581/// ```
582/// use micromegas_tracing::prelude::*;
583///
584/// # fn main() {
585/// let label: &'static str = "alpha";
586/// info!(prefix = static label, request = %"id", "fetched");
587/// # use micromegas_tracing::property_set::PropertySet;
588/// info!(prefix = static label, kind = "a", ..PropertySet::empty(), "with a set");
589/// # }
590/// ```
591///
592/// The value must be `'static`; a borrowed string is a compile error:
593///
594/// ```compile_fail
595/// use micromegas_tracing::prelude::*;
596///
597/// let s = String::from("alpha");
598/// info!(prefix = static s.as_str(), "fetched");
599/// ```
600///
601/// `static` doesn't combine with `%` or `?`:
602///
603/// ```compile_fail
604/// use micromegas_tracing::prelude::*;
605///
606/// info!(prefix = static %"x", "fetched");
607/// ```
608///
609/// `level` and `target` are reserved keys, because analytics treats them as column overrides.
610/// They can still be set through a `..set` spread:
611///
612/// ```compile_fail
613/// use micromegas_tracing::prelude::*;
614///
615/// info!(level = "debug", "message");
616/// ```
617///
618/// A literal value goes through `concat!`, so `1_000` is recorded as "1000" and `0x10` as "16",
619/// while a float keeps its spelling (`0.50` stays "0.50"); `%value` uses `Display` instead.
620///
621/// A bare integer needs `%`:
622///
623/// ```compile_fail
624/// use micromegas_tracing::prelude::*;
625///
626/// let n = 3_u32;
627/// info!(rows = n, "fetched");
628/// ```
629///
630/// A bare negated expression has no `PropertyValue` impl either:
631///
632/// ```compile_fail
633/// use micromegas_tracing::prelude::*;
634///
635/// let n = 3_i32;
636/// info!(delta = -n, "fetched");
637/// ```
638///
639/// `..set` can't be followed by other entries, and appears at most once:
640///
641/// ```compile_fail
642/// use micromegas_tracing::prelude::*;
643/// use micromegas_tracing::property_set::PropertySet;
644///
645/// let set = PropertySet::empty();
646/// info!(..set, kind = "a", "message");
647/// ```
648///
649/// ```compile_fail
650/// use micromegas_tracing::prelude::*;
651/// use micromegas_tracing::property_set::PropertySet;
652///
653/// let set = PropertySet::empty();
654/// info!(..set, ..set, "message");
655/// ```
656#[macro_export]
657macro_rules! log {
658    (target: $target:expr, $lvl:expr, $($rest:tt)+) => (
659        $crate::__props!(@m log [$target, $lvl] [] [] [] [] [] $($rest)+)
660    );
661    ($lvl:expr, $($rest:tt)+) => (
662        $crate::log!(target: $crate::__log_module_path!(), $lvl, $($rest)+)
663    );
664}
665
666/// Muncher behind the property lists of `log!`, `imetric!` and `fmetric!`.
667///
668/// Accumulators, in order: literal and static pairs `(key, lit|stat, (value))` for the
669/// per-callsite set, dynamic entries `(key, kind, value)`, every non-static entry in source
670/// order (used when a `..set` is spread without a static value, so that the last pair wins),
671/// the spread set, and `[static]` once a `static` value was seen.
672#[doc(hidden)]
673#[macro_export]
674macro_rules! __props {
675    // `..set` is only accepted as the last property.
676    (@m $kind:ident $ctx:tt $s:tt $d:tt $a:tt $set:tt $t:tt
677        .. $new_set:expr, $k:tt = $($x:tt)*) => {
678        compile_error!("`..set` must be the last entry of the property list")
679    };
680    (@m $kind:ident $ctx:tt $s:tt $d:tt $a:tt $set:tt $t:tt
681        .. $new_set:expr, .. $($x:tt)*) => {
682        compile_error!("`..set` can only appear once, as the last entry of the property list")
683    };
684    (@m $kind:ident $ctx:tt $s:tt $d:tt $a:tt $set:tt $t:tt
685        .. $new_set:expr, $($rest:tt)+) => {
686        $crate::__props!(@end $kind $ctx $s $d $a [$new_set] $t $($rest)+)
687    };
688    // `static` never starts a literal or a bare expression, so this arm can come first.
689    (@m $kind:ident $ctx:tt [$($s:tt)*] [$($d:tt)*] [$($a:tt)*] $set:tt $t:tt
690        $k:tt = static $v:expr $(, $($rest:tt)*)?) => {
691        $crate::__props!(@m $kind $ctx
692            [$($s)* ($k, stat, ($v))] [$($d)*] [$($a)*] $set [static] $($($rest)*)?)
693    };
694    // The negative literal arm precedes the `-` fallback, which precedes the plain literal arm:
695    // `$v:literal` is a hard parse error on `-x`.
696    (@m $kind:ident $ctx:tt [$($s:tt)*] [$($d:tt)*] [$($a:tt)*] $set:tt $t:tt
697        $k:tt = - $v:literal $(, $($rest:tt)*)?) => {
698        $crate::__props!(@m $kind $ctx
699            [$($s)* ($k, lit, (concat!("-", $v)))] [$($d)*]
700            [$($a)* ($k, lit, (concat!("-", $v)))] $set $t $($($rest)*)?)
701    };
702    (@m $kind:ident $ctx:tt $s:tt $d:tt $a:tt $set:tt $t:tt
703        $k:tt = - $($rest:tt)*) => {
704        $crate::__props!(@e $kind $ctx $s $d $a $set $t $k = - $($rest)*)
705    };
706    (@m $kind:ident $ctx:tt [$($s:tt)*] [$($d:tt)*] [$($a:tt)*] $set:tt $t:tt
707        $k:tt = % $v:expr $(, $($rest:tt)*)?) => {
708        $crate::__props!(@m $kind $ctx
709            [$($s)*] [$($d)* ($k, disp, $v)] [$($a)* ($k, disp, $v)] $set $t $($($rest)*)?)
710    };
711    (@m $kind:ident $ctx:tt [$($s:tt)*] [$($d:tt)*] [$($a:tt)*] $set:tt $t:tt
712        $k:tt = ? $v:expr $(, $($rest:tt)*)?) => {
713        $crate::__props!(@m $kind $ctx
714            [$($s)*] [$($d)* ($k, dbg, $v)] [$($a)* ($k, dbg, $v)] $set $t $($($rest)*)?)
715    };
716    (@m $kind:ident $ctx:tt [$($s:tt)*] [$($d:tt)*] [$($a:tt)*] $set:tt $t:tt
717        $k:tt = $v:literal $(, $($rest:tt)*)?) => {
718        $crate::__props!(@m $kind $ctx
719            [$($s)* ($k, lit, (concat!($v)))] [$($d)*]
720            [$($a)* ($k, lit, (concat!($v)))] $set $t $($($rest)*)?)
721    };
722    (@m $kind:ident $ctx:tt $s:tt $d:tt $a:tt $set:tt $t:tt
723        $k:tt = $($rest:tt)+) => {
724        $crate::__props!(@e $kind $ctx $s $d $a $set $t $k = $($rest)+)
725    };
726    // A bare value
727    (@e $kind:ident $ctx:tt [$($s:tt)*] [$($d:tt)*] [$($a:tt)*] $set:tt $t:tt
728        $k:tt = $v:expr $(, $($rest:tt)*)?) => {
729        $crate::__props!(@m $kind $ctx
730            [$($s)*] [$($d)* ($k, bare, $v)] [$($a)* ($k, bare, $v)] $set $t $($($rest)*)?)
731    };
732    // The end of the property list: a format string for logs, a value for metrics.
733    (@m log $ctx:tt $s:tt $d:tt $a:tt $set:tt $t:tt) => {
734        compile_error!("log macros require a format string")
735    };
736    (@m log $ctx:tt $s:tt $d:tt $a:tt $set:tt $t:tt $($fmt:tt)+) => {
737        $crate::__props!(@end log $ctx $s $d $a $set $t $($fmt)+)
738    };
739    (@m metric $ctx:tt $s:tt $d:tt $a:tt $set:tt $t:tt $value:expr $(,)?) => {
740        $crate::__props!(@end metric $ctx $s $d $a $set $t $value)
741    };
742
743    // A static value: literals and static values are interned together (over the spread set,
744    // if any) by a per-callsite cache, and only dynamic values go to the slice. Always `gate`:
745    // it is the only log form that evaluates the set expression for an enabled entry alone.
746    (@end log $ctx:tt [$($s:tt)+] [$($d:tt)*] [$($a:tt)*] [] [static] $($fmt:tt)+) => {
747        $crate::__log_call!(gate $ctx [$($fmt)+]
748            $crate::__static_set!(log [] $($s)+), $crate::__dyn_slice!(log $($d)*))
749    };
750    (@end log $ctx:tt [$($s:tt)+] [$($d:tt)*] [$($a:tt)*] [$set:tt] [static] $($fmt:tt)+) => {
751        $crate::__log_call!(gate $ctx [$($fmt)+]
752            $crate::__static_set!(log [$set] $($s)+), $crate::__dyn_slice!(log $($d)*))
753    };
754    (@end metric $ctx:tt [$($s:tt)+] [$($d:tt)*] [$($a:tt)*] [] [static]
755        $value:expr $(,)?) => {
756        $crate::__metric_call!(tagged $ctx
757            $crate::__static_set!(metric [] $($s)+),
758            [$($d)*], $value)
759    };
760    (@end metric $ctx:tt [$($s:tt)+] [$($d:tt)*] [$($a:tt)*] [$set:tt] [static]
761        $value:expr $(,)?) => {
762        $crate::__metric_call!(tagged $ctx
763            $crate::__static_set!(metric [$set] $($s)+),
764            [$($d)*], $value)
765    };
766
767    // The cheapest call that carries the properties: no properties at all, a spread set only,
768    // the per-callsite literal set only, or any of those plus dynamic values.
769    (@end log $ctx:tt [] [] [] [] [] $($fmt:tt)+) => {
770        $crate::__log_call!(plain $ctx [$($fmt)+])
771    };
772    (@end log $ctx:tt [$($s:tt)*] [] [$($a:tt)*] [$set:tt] [] $($fmt:tt)+) => {
773        $crate::__log_call!(nogate $ctx [$($fmt)+] $set, $crate::__dyn_slice!(log $($a)*))
774    };
775    (@end log $ctx:tt [$($s:tt)*] [$($d:tt)+] [$($a:tt)*] [$set:tt] [] $($fmt:tt)+) => {
776        $crate::__log_call!(gate $ctx [$($fmt)+] $set, $crate::__dyn_slice!(log $($a)*))
777    };
778    (@end log $ctx:tt [$($s:tt)+] [] [$($a:tt)*] [] [] $($fmt:tt)+) => {
779        $crate::__log_call!(nogate $ctx [$($fmt)+]
780            $crate::__callsite_set!(log $($s)+), $crate::__dyn_slice!(log))
781    };
782    (@end log $ctx:tt [$($s:tt)+] [$($d:tt)+] [$($a:tt)*] [] [] $($fmt:tt)+) => {
783        $crate::__log_call!(gate $ctx [$($fmt)+]
784            $crate::__callsite_set!(log $($s)+), $crate::__dyn_slice!(log $($d)+))
785    };
786    (@end log $ctx:tt [] [$($d:tt)+] [$($a:tt)*] [] [] $($fmt:tt)+) => {
787        $crate::__log_call!(gate $ctx [$($fmt)+]
788            $crate::property_set::PropertySet::empty(), $crate::__dyn_slice!(log $($d)+))
789    };
790
791    (@end metric $ctx:tt [] [] [] [] [] $value:expr) => {
792        $crate::__metric_call!(plain $ctx $value)
793    };
794    (@end metric $ctx:tt [$($s:tt)*] [$($d:tt)*] [$($a:tt)*] [$set:tt] [] $value:expr $(,)?) => {
795        $crate::__metric_call!(tagged $ctx $set, [$($a)*], $value)
796    };
797    (@end metric $ctx:tt [$($s:tt)+] [$($d:tt)*] [$($a:tt)*] [] [] $value:expr) => {
798        $crate::__metric_call!(tagged $ctx
799            $crate::__callsite_set!(metric $($s)+), [$($d)*], $value)
800    };
801    (@end metric $ctx:tt [] [$($d:tt)+] [$($a:tt)*] [] [] $value:expr) => {
802        $crate::__metric_call!(tagged $ctx
803            $crate::property_set::PropertySet::empty(), [$($d)+], $value)
804    };
805}
806
807#[doc(hidden)]
808#[macro_export]
809macro_rules! __log_call {
810    (plain [$target:expr, $lvl:expr] [$($fmt:tt)+]) => ({
811        static LOG_DESC: $crate::logs::LogMetadata = $crate::logs::LogMetadata {
812            level: $lvl,
813            level_filter: std::sync::atomic::AtomicU32::new($crate::logs::FILTER_LEVEL_UNSET_VALUE),
814            fmt_str: $crate::__first_arg!($($fmt)+),
815            target: $target,
816            module_path: $crate::__log_module_path!(),
817            file: file!(),
818            line: line!(),
819        };
820        if $lvl <= $crate::levels::STATIC_MAX_LEVEL && $lvl <= $crate::levels::max_level() {
821            $crate::dispatch::log(&LOG_DESC, format_args!($($fmt)+));
822        }
823    });
824    (nogate [$target:expr, $lvl:expr] [$($fmt:tt)+] $set:expr, $slice:expr) => ({
825        static LOG_DESC: $crate::logs::LogMetadata = $crate::logs::LogMetadata {
826            level: $lvl,
827            level_filter: std::sync::atomic::AtomicU32::new($crate::logs::FILTER_LEVEL_UNSET_VALUE),
828            fmt_str: $crate::__first_arg!($($fmt)+),
829            target: $target,
830            module_path: $crate::__log_module_path!(),
831            file: file!(),
832            line: line!(),
833        };
834        if $lvl <= $crate::levels::STATIC_MAX_LEVEL && $lvl <= $crate::levels::max_level() {
835            $crate::dispatch::log_dyn_tagged(&LOG_DESC, $set, $slice, format_args!($($fmt)+));
836        }
837    });
838    // Evaluating a dynamic value can allocate, so only do it for an enabled entry.
839    (gate [$target:expr, $lvl:expr] [$($fmt:tt)+] $set:expr, $slice:expr) => ({
840        static LOG_DESC: $crate::logs::LogMetadata = $crate::logs::LogMetadata {
841            level: $lvl,
842            level_filter: std::sync::atomic::AtomicU32::new($crate::logs::FILTER_LEVEL_UNSET_VALUE),
843            fmt_str: $crate::__first_arg!($($fmt)+),
844            target: $target,
845            module_path: $crate::__log_module_path!(),
846            file: file!(),
847            line: line!(),
848        };
849        if $lvl <= $crate::levels::STATIC_MAX_LEVEL && $lvl <= $crate::levels::max_level() {
850            if let Some(sink) = $crate::dispatch::enabled_log_sink(&LOG_DESC) {
851                $crate::dispatch::log_dyn_tagged_enabled(
852                    sink,
853                    &LOG_DESC,
854                    $set,
855                    $slice,
856                    format_args!($($fmt)+),
857                );
858            }
859        }
860    });
861}
862
863#[doc(hidden)]
864#[macro_export]
865macro_rules! __metric_call {
866    (plain [$name:expr, $unit:expr, $target:expr, $plain:ident, $dynf:ident] $value:expr) => {{
867        static METRIC_METADATA: $crate::metrics::StaticMetricMetadata =
868            $crate::metrics::StaticMetricMetadata {
869                lod: $crate::levels::Verbosity::Max,
870                name: $name,
871                unit: $unit,
872                target: $target,
873                file: file!(),
874                line: line!(),
875            };
876        $crate::dispatch::$plain(&METRIC_METADATA, $value);
877    }};
878    (tagged [$name:expr, $unit:expr, $target:expr, $plain:ident, $dynf:ident]
879        $set:expr, [$($slice:tt)*], $value:expr) => {{
880        static METRIC_METADATA: $crate::metrics::StaticMetricMetadata =
881            $crate::metrics::StaticMetricMetadata {
882                lod: $crate::levels::Verbosity::Max,
883                name: $name,
884                unit: $unit,
885                target: $target,
886                file: file!(),
887                line: line!(),
888            };
889        $crate::dispatch::$dynf(
890            &METRIC_METADATA,
891            $set,
892            $crate::__dyn_slice!(metric $($slice)*),
893            $value,
894        );
895    }};
896    // Runtime name and unit: they travel as the `name` and `unit` property overrides.
897    (plain [$name:expr, $unit:expr, $target:expr, $plain:ident, $dynf:ident, dynamic]
898        $value:expr) => {
899        $crate::__metric_call!(tagged [$name, $unit, $target, $plain, $dynf, dynamic]
900            $crate::property_set::PropertySet::empty(), [], $value)
901    };
902    (tagged [$name:expr, $unit:expr, $target:expr, $plain:ident, $dynf:ident, dynamic]
903        $set:expr, [$($slice:tt)*], $value:expr) => {{
904        static METRIC_METADATA: $crate::metrics::StaticMetricMetadata =
905            $crate::metrics::StaticMetricMetadata {
906                lod: $crate::levels::Verbosity::Max,
907                name: "",
908                unit: "",
909                target: $target,
910                file: file!(),
911                line: line!(),
912            };
913        $crate::dispatch::$dynf(
914            &METRIC_METADATA,
915            $set,
916            $crate::__dyn_slice!(metric $($slice)* ;
917                $crate::property_set::DynProperty::new(
918                    "name",
919                    ::std::convert::AsRef::<str>::as_ref(&$name),
920                ),
921                $crate::property_set::DynProperty::new(
922                    "unit",
923                    ::std::convert::AsRef::<str>::as_ref(&$unit),
924                )
925            ),
926            $value,
927        );
928    }};
929}
930
931/// Interns the literal properties of a callsite on its first execution.
932#[doc(hidden)]
933#[macro_export]
934macro_rules! __callsite_set {
935    ($kind:ident $(($k:tt, lit, ($($v:tt)*)))+) => {{
936        static CELL: ::std::sync::OnceLock<&'static $crate::property_set::PropertySet> =
937            ::std::sync::OnceLock::new();
938        static PAIRS: &[(&str, &str)] = &[$(($crate::__prop_key!($kind $k), $($v)*)),+];
939        $crate::property_set::callsite_set(&CELL, PAIRS)
940    }};
941}
942
943/// The set of a callsite with `static` values: the literals and static values over the spread
944/// set (or the empty one), interned once per distinct tuple of values.
945#[doc(hidden)]
946#[macro_export]
947macro_rules! __static_set {
948    ($kind:ident [] $(($k:tt, $tag:ident, $v:tt))+) => {
949        $crate::__static_set!(@get $kind $crate::property_set::PropertySet::empty(),
950            $(($k, $tag, $v))+)
951    };
952    ($kind:ident [$set:expr] $(($k:tt, $tag:ident, $v:tt))+) => {
953        $crate::__static_set!(@get $kind $set, $(($k, $tag, $v))+)
954    };
955    (@get $kind:ident $base:expr, $(($k:tt, $tag:ident, $v:tt))+) => {{
956        static CACHE: $crate::static_set_cache::StaticSetCache<{ [$(stringify!($k)),+].len() }> =
957            $crate::static_set_cache::StaticSetCache::new();
958        CACHE.get(
959            $base,
960            [$(($crate::__prop_key!($kind $k), $crate::__static_value!($tag $v))),+],
961        )
962    }};
963}
964
965#[doc(hidden)]
966#[macro_export]
967macro_rules! __static_value {
968    (lit ($($v:tt)*)) => {
969        $($v)*
970    };
971    (stat ($($v:tt)*)) => {
972        $crate::property_set::static_value($($v)*)
973    };
974}
975
976// The temporaries created for `bare`, `disp` and `dbg` values live until the end of the
977// statement that makes the dispatch call, which is what lets the slice borrow them.
978#[doc(hidden)]
979#[macro_export]
980macro_rules! __dyn_slice {
981    ($kind:ident $(($k:tt, $vk:ident, $v:tt))*) => {
982        &[$($crate::__dyn_prop!($kind $k $vk $v)),*]
983    };
984    // `extra` goes last, where `merge_properties` lets it win over a same-named entry.
985    ($kind:ident $(($k:tt, $vk:ident, $v:tt))* ; $($extra:expr),+) => {
986        &[$($crate::__dyn_prop!($kind $k $vk $v),)* $($extra),+]
987    };
988}
989
990#[doc(hidden)]
991#[macro_export]
992macro_rules! __dyn_prop {
993    ($kind:ident $k:tt lit $v:tt) => {
994        $crate::property_set::DynProperty::new($crate::__prop_key!($kind $k), $v)
995    };
996    ($kind:ident $k:tt bare $v:tt) => {
997        $crate::property_set::DynProperty::new(
998            $crate::__prop_key!($kind $k),
999            &*$crate::property_value::PropertyValue::property_value(&$v),
1000        )
1001    };
1002    ($kind:ident $k:tt disp $v:tt) => {
1003        $crate::property_set::DynProperty::new(
1004            $crate::__prop_key!($kind $k),
1005            &*::std::format!("{}", $v),
1006        )
1007    };
1008    ($kind:ident $k:tt dbg $v:tt) => {
1009        $crate::property_set::DynProperty::new(
1010            $crate::__prop_key!($kind $k),
1011            &*::std::format!("{:?}", $v),
1012        )
1013    };
1014}
1015
1016/// Turns a property key into a `&'static str`. Analytics treats some names as column
1017/// overrides, so the macros reject them; a `..set` spread or a runtime `DynProperty` slice is
1018/// the way to set them (the `_dyn` metric macros set `name` and `unit` themselves).
1019#[doc(hidden)]
1020#[macro_export]
1021macro_rules! __prop_key {
1022    (log level) => {
1023        compile_error!(
1024            "`level` is reserved: the level is chosen by the macro (`info!`, `log!(Level::..)`)"
1025        )
1026    };
1027    (log "level") => {
1028        compile_error!(
1029            "`level` is reserved: the level is chosen by the macro (`info!`, `log!(Level::..)`)"
1030        )
1031    };
1032    (log target) => {
1033        compile_error!("`target` is reserved: pass it as `target: ..` before the other arguments")
1034    };
1035    (log "target") => {
1036        compile_error!("`target` is reserved: pass it as `target: ..` before the other arguments")
1037    };
1038    (metric target) => {
1039        compile_error!("`target` is reserved: pass it as `target: ..` before the metric name")
1040    };
1041    (metric "target") => {
1042        compile_error!("`target` is reserved: pass it as `target: ..` before the metric name")
1043    };
1044    (metric name) => {
1045        compile_error!("`name` is reserved: it is the first argument of the metric")
1046    };
1047    (metric "name") => {
1048        compile_error!("`name` is reserved: it is the first argument of the metric")
1049    };
1050    (metric unit) => {
1051        compile_error!("`unit` is reserved: it is the second argument of the metric")
1052    };
1053    (metric "unit") => {
1054        compile_error!("`unit` is reserved: it is the second argument of the metric")
1055    };
1056    ($kind:ident $k:ident) => {
1057        stringify!($k)
1058    };
1059    ($kind:ident $k:literal) => {
1060        $k
1061    };
1062    ($kind:ident $($k:tt)*) => {
1063        compile_error!("a property key must be an identifier or a string literal")
1064    };
1065}
1066
1067/// Logs a message at the error level.
1068///
1069/// # Examples
1070///
1071/// ```
1072/// use micromegas_tracing::prelude::*;
1073///
1074/// # fn main() {
1075/// let (err_info, port) = ("No connection", 22);
1076///
1077/// error!("Error: {} on port {}", err_info, port);
1078/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
1079/// # }
1080/// ```
1081#[macro_export]
1082macro_rules! error {
1083    (target: $target:expr, $($arg:tt)+) => (
1084        $crate::log!(target: $target, $crate::levels::Level::Error, $($arg)+)
1085    );
1086    ($($arg:tt)+) => (
1087        $crate::log!($crate::levels::Level::Error, $($arg)+)
1088    )
1089}
1090
1091/// Logs a message representing a crash or panic
1092#[macro_export]
1093macro_rules! fatal {
1094    (target: $target:expr, $($arg:tt)+) => (
1095        $crate::log!(target: $target, $crate::levels::Level::Fatal, $($arg)+)
1096    );
1097    ($($arg:tt)+) => (
1098        $crate::log!($crate::levels::Level::Fatal, $($arg)+)
1099    )
1100}
1101
1102/// Logs a message at the warn level.
1103///
1104/// # Examples
1105///
1106/// ```
1107/// use micromegas_tracing::prelude::*;
1108///
1109/// # fn main() {
1110/// let warn_description = "Invalid Input";
1111///
1112/// warn!("Warning! {}!", warn_description);
1113/// warn!(target: "input_events", "App received warning: {}", warn_description);
1114/// # }
1115/// ```
1116#[macro_export]
1117macro_rules! warn {
1118    (target: $target:expr, $($arg:tt)+) => (
1119        $crate::log!(target: $target, $crate::levels::Level::Warn, $($arg)+)
1120    );
1121    ($($arg:tt)+) => (
1122        $crate::log!($crate::levels::Level::Warn, $($arg)+)
1123    )
1124}
1125
1126/// Logs a message at the info level.
1127///
1128/// # Examples
1129///
1130/// ```
1131/// use micromegas_tracing::prelude::*;
1132///
1133/// # fn main() {
1134/// # struct Connection { port: u32, speed: f32 }
1135/// let conn_info = Connection { port: 40, speed: 3.20 };
1136///
1137/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
1138/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}",
1139///       conn_info.port, conn_info.speed);
1140/// # }
1141/// ```
1142#[macro_export]
1143macro_rules! info {
1144    (target: $target:expr, $($arg:tt)+) => (
1145        $crate::log!(target: $target, $crate::levels::Level::Info, $($arg)+)
1146    );
1147    ($($arg:tt)+) => (
1148        $crate::log!($crate::levels::Level::Info, $($arg)+)
1149    )
1150}
1151
1152/// Logs a message at the debug level.
1153///
1154/// # Examples
1155///
1156/// ```
1157/// use micromegas_tracing::debug;
1158///
1159/// # fn main() {
1160/// # struct Position { x: f32, y: f32 }
1161/// let pos = Position { x: 3.234, y: -1.223 };
1162///
1163/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
1164/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
1165/// # }
1166/// ```
1167#[macro_export]
1168macro_rules! debug {
1169    (target: $target:expr, $($arg:tt)+) => (
1170        $crate::log!(target: $target, $crate::levels::Level::Debug, $($arg)+)
1171    );
1172    ($($arg:tt)+) => (
1173        $crate::log!($crate::levels::Level::Debug, $($arg)+)
1174    )
1175}
1176
1177/// Logs a message at the trace level.
1178///
1179/// # Examples
1180///
1181/// ```
1182/// use micromegas_tracing::trace;
1183///
1184/// # fn main() {
1185/// # struct Position { x: f32, y: f32 }
1186/// let pos = Position { x: 3.234, y: -1.223 };
1187///
1188/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
1189/// trace!(target: "app_events", "x is {} and y is {}",
1190///        if pos.x >= 0.0 { "positive" } else { "negative" },
1191///        if pos.y >= 0.0 { "positive" } else { "negative" });
1192/// # }
1193/// ```
1194#[macro_export]
1195macro_rules! trace {
1196    (target: $target:expr, $($arg:tt)+) => (
1197        $crate::log!(target: $target, $crate::levels::Level::Trace, $($arg)+)
1198    );
1199    ($($arg:tt)+) => (
1200        $crate::log!($crate::levels::Level::Trace, $($arg)+)
1201    )
1202}
1203
1204/// Determines if a message logged at the specified level in that module will
1205/// be logged.
1206///
1207/// This can be used to avoid expensive computation of log message arguments if
1208/// the message would be ignored anyway.
1209///
1210/// # Examples
1211///
1212/// ```
1213/// use micromegas_tracing::prelude::*;
1214///
1215/// # fn foo() {
1216/// if log_enabled!(Level::Debug) {
1217///     let data = expensive_call();
1218///     debug!("expensive debug data: {} {}", data.x, data.y);
1219/// }
1220/// if log_enabled!(target: "Global", Level::Debug) {
1221///    let data = expensive_call();
1222///    debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
1223/// }
1224/// # }
1225/// # struct Data { x: u32, y: u32 }
1226/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
1227/// # fn main() {}
1228/// ```
1229#[macro_export(local_inner_macros)]
1230macro_rules! log_enabled {
1231    (target: $target:expr, $lvl:expr) => {{
1232        let lvl = $lvl;
1233        static LOG_ENABLED_METADATA: $crate::logs::LogMetadata = $crate::logs::LogMetadata {
1234            level: $lvl,
1235            level_filter: std::sync::atomic::AtomicU32::new($crate::logs::FILTER_LEVEL_UNSET_VALUE),
1236            fmt_str: "",
1237            target: $target,
1238            module_path: $crate::__log_module_path!(),
1239            file: $crate::__log_file!(),
1240            line: $crate::__log_line!(),
1241        };
1242        lvl <= $crate::levels::STATIC_MAX_LEVEL
1243            && lvl <= $crate::levels::max_level()
1244            && $crate::dispatch::log_enabled(&LOG_ENABLED_METADATA)
1245    }};
1246    ($lvl:expr) => {
1247        $crate::log_enabled!(target: $crate::__log_module_path!(), $lvl)
1248    };
1249}
1250
1251//pub const fn type_name_of<T>(_: &T) -> &'static str {
1252//    //until type_name_of_val is out of nightly-only
1253//    std::any::type_name::<T>()
1254//}
1255
1256#[doc(hidden)]
1257#[macro_export]
1258macro_rules! __function_name {
1259    () => {{
1260        // Okay, this is ugly, I get it. However, this is the best we can get on a stable rust.
1261        fn f() {}
1262        fn type_name_of<T>(_: T) -> &'static str {
1263            std::any::type_name::<T>()
1264        }
1265        let name = type_name_of(f);
1266        // `3` is the length of the `::f`.
1267        &name[..name.len() - 3]
1268    }};
1269}
1270
1271#[doc(hidden)]
1272#[macro_export]
1273macro_rules! __first_arg {
1274    ($first:tt) => {
1275        $first
1276    };
1277    ($first:tt, $($args:tt)*) => {
1278        $crate::__first_arg!($first)
1279    };
1280}
1281
1282#[doc(hidden)]
1283#[macro_export]
1284macro_rules! __log_format_args {
1285    ($($args:tt)*) => {
1286        format_args!($($args)*)
1287    };
1288}
1289
1290#[doc(hidden)]
1291#[macro_export]
1292macro_rules! __log_module_path {
1293    () => {
1294        module_path!()
1295    };
1296}
1297
1298#[doc(hidden)]
1299#[macro_export]
1300macro_rules! __log_file {
1301    () => {
1302        file!()
1303    };
1304}
1305
1306#[doc(hidden)]
1307#[macro_export]
1308macro_rules! __log_line {
1309    () => {
1310        line!()
1311    };
1312}