gix_trace/
enabled.rs

1use tracing_core::{dispatcher::get_default as with_dispatcher, span, span::Id, Dispatch};
2// these are used later in macros.
3pub use tracing_core::{field, metadata, Event, Metadata};
4
5/// An entered span which will exit on drop.
6#[derive(Clone)]
7pub struct Span {
8    id: Option<(Id, Dispatch, &'static Metadata<'static>)>,
9}
10
11impl Span {
12    /// Create a new span.
13    ///
14    /// This constructor is typically invoked by the [`crate::span!`] macro.
15    pub fn new(
16        level: crate::Level,
17        meta: &'static Metadata<'static>,
18        values: &tracing_core::field::ValueSet<'_>,
19    ) -> Self {
20        if level > crate::MAX_LEVEL {
21            Self { id: None }
22        } else {
23            with_dispatcher(|dispatch| {
24                let id = dispatch.new_span(&tracing_core::span::Attributes::new(meta, values));
25                dispatch.enter(&id);
26                Self {
27                    id: Some((id, dispatch.clone(), meta)),
28                }
29            })
30        }
31    }
32
33    /// Record a single `field` to take `value`.
34    ///
35    /// ### Panics
36    ///
37    /// If the field name wasn't mentioned when the span was created.
38    pub fn record<V>(&self, field: &str, value: V) -> &Self
39    where
40        V: field::Value,
41    {
42        if let Some((_, _, meta)) = &self.id {
43            let fields = meta.fields();
44            let field = fields
45                .field(field)
46                .unwrap_or_else(|| panic!("Field name '{field}' must be registered at creation time."));
47            self.record_all(&fields.value_set(&[(&field, Some(&value as &dyn field::Value))]));
48        }
49        self
50    }
51
52    fn record_all(&self, values: &field::ValueSet<'_>) -> &Self {
53        if let Some((id, dispatch, _)) = &self.id {
54            let record = span::Record::new(values);
55            dispatch.record(id, &record);
56        }
57        self
58    }
59}
60
61impl Drop for Span {
62    fn drop(&mut self) {
63        if let Some((id, dispatch, _meta)) = self.id.take() {
64            dispatch.exit(&id);
65            dispatch.try_close(id);
66        }
67    }
68}
69
70#[doc(hidden)]
71pub struct MetaOnlyCallsite(pub &'static Metadata<'static>);
72
73impl tracing_core::callsite::Callsite for MetaOnlyCallsite {
74    fn set_interest(&self, _: tracing_core::subscriber::Interest) {}
75
76    fn metadata(&self) -> &Metadata<'_> {
77        self.0
78    }
79}
80
81#[doc(hidden)]
82impl crate::Level {
83    pub const fn into_tracing_level(self) -> tracing_core::Level {
84        match self {
85            crate::Level::Coarse => tracing_core::Level::INFO,
86            crate::Level::Detail => tracing_core::Level::DEBUG,
87        }
88    }
89}
90
91/// A macro to create a span.
92#[macro_export]
93macro_rules! span {
94    (target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
95        {
96            static META: $crate::Metadata<'static> = {
97                $crate::metadata! {
98                    name: $name,
99                    target: $target,
100                    level: $lvl.into_tracing_level(),
101                    fields: $crate::fieldset!( $($fields)* ),
102                    callsite: &$crate::MetaOnlyCallsite(&META),
103                    kind: $crate::metadata::Kind::SPAN,
104                }
105            };
106
107            $crate::Span::new(
108                $lvl,
109                &META,
110                &$crate::valueset!(META.fields(), $($fields)*),
111            )
112        }
113    };
114    (target: $target:expr, $lvl:expr, $name:expr) => {
115        $crate::span!(target: $target, $lvl, $name,)
116    };
117    ($lvl:expr, $name:expr, $($fields:tt)*) => {
118        $crate::span!(
119            target: module_path!(),
120            $lvl,
121            $name,
122            $($fields)*
123        )
124    };
125    ($lvl:expr, $name:expr) => {
126        $crate::span!(
127            target: module_path!(),
128            $lvl,
129            $name,
130        )
131    };
132}
133
134/// Create an event with the given level.
135#[macro_export]
136macro_rules! event {
137    (target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> (
138        {
139            static META: $crate::Metadata<'static> = {
140                $crate::metadata! {
141                    name: concat!(
142                        "event ",
143                        file!(),
144                        ":",
145                        line!()
146                    ),
147                    target: $target,
148                    level: $lvl,
149                    fields: $crate::fieldset!( $($fields)* ),
150                    callsite: &$crate::MetaOnlyCallsite(&META),
151                    kind: $crate::metadata::Kind::EVENT,
152                }
153            };
154            $crate::Event::dispatch(
155                &META,
156                &$crate::valueset!(META.fields(), $($fields)*)
157            );
158        }
159    );
160    (target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
161        $crate::event!(
162            target: $target,
163            $lvl,
164            { message = format_args!($($arg)+), $($fields)* }
165        )
166    );
167    (target: $target:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
168        $crate::event!(target: $target, $lvl, { $($k).+ = $($fields)* })
169    );
170    (target: $target:expr, $lvl:expr, $($arg:tt)+ ) => (
171        $crate::event!(target: $target, $lvl, { $($arg)+ })
172    );
173    ( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
174        $crate::event!(
175            target: module_path!(),
176            $lvl,
177            { message = format_args!($($arg)+), $($fields)* }
178        )
179    );
180    ($lvl:expr, $($k:ident).+ = $($field:tt)*) => (
181        $crate::event!(
182            target: module_path!(),
183            $lvl,
184            { $($k).+ = $($field)*}
185        )
186    );
187    ($lvl:expr, $($k:ident).+, $($field:tt)*) => (
188        $crate::event!(
189            target: module_path!(),
190            $lvl,
191            { $($k).+, $($field)*}
192        )
193    );
194    ($lvl:expr, ?$($k:ident).+, $($field:tt)*) => (
195        $crate::event!(
196            target: module_path!(),
197            $lvl,
198            { ?$($k).+, $($field)*}
199        )
200    );
201    ($lvl:expr, %$($k:ident).+, $($field:tt)*) => (
202        $crate::event!(
203            target: module_path!(),
204            $lvl,
205            { %$($k).+, $($field)*}
206        )
207    );
208    ($lvl:expr, ?$($k:ident).+) => (
209        $crate::event!($lvl, ?$($k).+,)
210    );
211    ($lvl:expr, %$($k:ident).+) => (
212        $crate::event!($lvl, %$($k).+,)
213    );
214    ($lvl:expr, $($k:ident).+) => (
215        $crate::event!($lvl, $($k).+,)
216    );
217    ( $lvl:expr, $($arg:tt)+ ) => (
218        $crate::event!(target: module_path!(), $lvl, { $($arg)+ })
219    );
220}
221
222// Copied from`tracing`, would be nice to have it in `tracing-core`.
223#[doc(hidden)]
224#[macro_export]
225macro_rules! fieldset {
226    // == base case ==
227    (@ { $(,)* $($out:expr),* $(,)* } $(,)*) => {
228        &[ $($out),* ]
229    };
230
231    // == recursive cases (more tts) ==
232    (@ { $(,)* $($out:expr),* } $($k:ident).+ = ?$val:expr, $($rest:tt)*) => {
233        $crate::fieldset!(@ { $($out),*, stringify!($($k).+) } $($rest)*)
234    };
235    (@ { $(,)* $($out:expr),* } $($k:ident).+ = %$val:expr, $($rest:tt)*) => {
236        $crate::fieldset!(@ { $($out),*, stringify!($($k).+) } $($rest)*)
237    };
238    (@ { $(,)* $($out:expr),* } $($k:ident).+ = $val:expr, $($rest:tt)*) => {
239        $crate::fieldset!(@ { $($out),*, stringify!($($k).+) } $($rest)*)
240    };
241    // TODO(#1138): determine a new syntax for uninitialized span fields, and
242    // re-enable this.
243    // (@ { $($out:expr),* } $($k:ident).+ = _, $($rest:tt)*) => {
244    //     $crate::fieldset!(@ { $($out),*, stringify!($($k).+) } $($rest)*)
245    // };
246    (@ { $(,)* $($out:expr),* } ?$($k:ident).+, $($rest:tt)*) => {
247        $crate::fieldset!(@ { $($out),*, stringify!($($k).+) } $($rest)*)
248    };
249    (@ { $(,)* $($out:expr),* } %$($k:ident).+, $($rest:tt)*) => {
250        $crate::fieldset!(@ { $($out),*, stringify!($($k).+) } $($rest)*)
251    };
252    (@ { $(,)* $($out:expr),* } $($k:ident).+, $($rest:tt)*) => {
253        $crate::fieldset!(@ { $($out),*, stringify!($($k).+) } $($rest)*)
254    };
255
256    // Handle literal names
257    (@ { $(,)* $($out:expr),* } $k:literal = ?$val:expr, $($rest:tt)*) => {
258        $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
259    };
260    (@ { $(,)* $($out:expr),* } $k:literal = %$val:expr, $($rest:tt)*) => {
261        $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
262    };
263    (@ { $(,)* $($out:expr),* } $k:literal = $val:expr, $($rest:tt)*) => {
264        $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
265    };
266
267    // Remainder is unparsable, but exists --- must be format args!
268    (@ { $(,)* $($out:expr),* } $($rest:tt)+) => {
269        $crate::fieldset!(@ { "message", $($out),*, })
270    };
271
272    // == entry ==
273    ($($args:tt)*) => {
274        $crate::fieldset!(@ { } $($args)*,)
275    };
276}
277
278// Copied from`tracing`, would be nice to have it in `tracing-core`.
279#[doc(hidden)]
280#[macro_export]
281macro_rules! valueset {
282
283    // === base case ===
284    (@ { $(,)* $($val:expr),* $(,)* }, $next:expr $(,)*) => {
285        &[ $($val),* ]
286    };
287
288    // === recursive case (more tts) ===
289
290    // TODO(#1138): determine a new syntax for uninitialized span fields, and
291    // re-enable this.
292    // (@{ $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = _, $($rest:tt)*) => {
293    //     $crate::valueset!(@ { $($out),*, (&$next, None) }, $next, $($rest)*)
294    // };
295    (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr, $($rest:tt)*) => {
296        $crate::valueset!(
297            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
298            $next,
299            $($rest)*
300        )
301    };
302    (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr, $($rest:tt)*) => {
303        $crate::valueset!(
304            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
305            $next,
306            $($rest)*
307        )
308    };
309    (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr, $($rest:tt)*) => {
310        $crate::valueset!(
311            @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
312            $next,
313            $($rest)*
314        )
315    };
316    (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+, $($rest:tt)*) => {
317        $crate::valueset!(
318            @ { $($out),*, (&$next, Some(&$($k).+ as &dyn Value)) },
319            $next,
320            $($rest)*
321        )
322    };
323    (@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+, $($rest:tt)*) => {
324        $crate::valueset!(
325            @ { $($out),*, (&$next, Some(&debug(&$($k).+) as &dyn Value)) },
326            $next,
327            $($rest)*
328        )
329    };
330    (@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+, $($rest:tt)*) => {
331        $crate::valueset!(
332            @ { $($out),*, (&$next, Some(&display(&$($k).+) as &dyn Value)) },
333            $next,
334            $($rest)*
335        )
336    };
337    (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr) => {
338        $crate::valueset!(
339            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
340            $next,
341        )
342    };
343    (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr) => {
344        $crate::valueset!(
345            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
346            $next,
347        )
348    };
349    (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr) => {
350        $crate::valueset!(
351            @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
352            $next,
353        )
354    };
355    (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+) => {
356        $crate::valueset!(
357            @ { $($out),*, (&$next, Some(&$($k).+ as &dyn Value)) },
358            $next,
359        )
360    };
361    (@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+) => {
362        $crate::valueset!(
363            @ { $($out),*, (&$next, Some(&debug(&$($k).+) as &dyn Value)) },
364            $next,
365        )
366    };
367    (@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+) => {
368        $crate::valueset!(
369            @ { $($out),*, (&$next, Some(&display(&$($k).+) as &dyn Value)) },
370            $next,
371        )
372    };
373
374    // Handle literal names
375    (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr, $($rest:tt)*) => {
376        $crate::valueset!(
377            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
378            $next,
379            $($rest)*
380        )
381    };
382    (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr, $($rest:tt)*) => {
383        $crate::valueset!(
384            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
385            $next,
386            $($rest)*
387        )
388    };
389    (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr, $($rest:tt)*) => {
390        $crate::valueset!(
391            @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
392            $next,
393            $($rest)*
394        )
395    };
396    (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr) => {
397        $crate::valueset!(
398            @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
399            $next,
400        )
401    };
402    (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr) => {
403        $crate::valueset!(
404            @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
405            $next,
406        )
407    };
408    (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr) => {
409        $crate::valueset!(
410            @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
411            $next,
412        )
413    };
414
415    // Remainder is unparsable, but exists --- must be format args!
416    (@ { $(,)* $($out:expr),* }, $next:expr, $($rest:tt)+) => {
417        $crate::valueset!(@ { (&$next, Some(&format_args!($($rest)+) as &dyn Value)), $($out),* }, $next, )
418    };
419
420    // === entry ===
421    ($fields:expr, $($kvs:tt)+) => {
422        {
423            #[allow(unused_imports)]
424            use $crate::field::{debug, display, Value};
425            let mut iter = $fields.iter();
426            $fields.value_set($crate::valueset!(
427                @ { },
428                iter.next().expect("FieldSet corrupted (this is a bug)"),
429                $($kvs)+
430            ))
431        }
432    };
433    ($fields:expr,) => {
434        {
435            $fields.value_set(&[])
436        }
437    };
438}