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}