1use tracing_core::{dispatcher::get_default as with_dispatcher, span, span::Id, Dispatch};
2pub use tracing_core::{field, metadata, Event, Metadata};
4
5#[derive(Clone)]
7pub struct Span {
8 id: Option<(Id, Dispatch, &'static Metadata<'static>)>,
9}
10
11impl Span {
12 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 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#[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#[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#[doc(hidden)]
224#[macro_export]
225macro_rules! fieldset {
226 (@ { $(,)* $($out:expr),* $(,)* } $(,)*) => {
228 &[ $($out),* ]
229 };
230
231 (@ { $(,)* $($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 (@ { $(,)* $($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 (@ { $(,)* $($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 (@ { $(,)* $($out:expr),* } $($rest:tt)+) => {
269 $crate::fieldset!(@ { "message", $($out),*, })
270 };
271
272 ($($args:tt)*) => {
274 $crate::fieldset!(@ { } $($args)*,)
275 };
276}
277
278#[doc(hidden)]
280#[macro_export]
281macro_rules! valueset {
282
283 (@ { $(,)* $($val:expr),* $(,)* }, $next:expr $(,)*) => {
285 &[ $($val),* ]
286 };
287
288 (@ { $(,)* $($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 (@ { $(,)* $($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 (@ { $(,)* $($out:expr),* }, $next:expr, $($rest:tt)+) => {
417 $crate::valueset!(@ { (&$next, Some(&format_args!($($rest)+) as &dyn Value)), $($out),* }, $next, )
418 };
419
420 ($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}