1//! A procedural macro attribute for instrumenting functions with [`tracing`].
2//!
3//! [`tracing`] is a framework for instrumenting Rust programs to collect
4//! structured, event-based diagnostic information. This crate provides the
5//! [`#[instrument]`][instrument] procedural macro attribute.
6//!
7//! Note that this macro is also re-exported by the main `tracing` crate.
8//!
9//! *Compiler support: [requires `rustc` 1.56+][msrv]*
10//!
11//! [msrv]: #supported-rust-versions
12//!
13//! ## Usage
14//!
15//! In the `Cargo.toml`:
16//!
17//! ```toml
18//! [dependencies]
19//! tracing-attributes = "0.1.24"
20//! ```
21//!
22//! The [`#[instrument]`][instrument] attribute can now be added to a function
23//! to automatically create and enter `tracing` [span] when that function is
24//! called. For example:
25//!
26//! ```
27//! use tracing::instrument;
28//!
29//! #[instrument]
30//! pub fn my_function(my_arg: usize) {
31//! // ...
32//! }
33//!
34//! # fn main() {}
35//! ```
36//!
37//! [`tracing`]: https://crates.io/crates/tracing
38//! [span]: https://docs.rs/tracing/latest/tracing/span/index.html
39//! [instrument]: macro@self::instrument
40//!
41//! ## Supported Rust Versions
42//!
43//! Tracing is built against the latest stable release. The minimum supported
44//! version is 1.56. The current Tracing version is not guaranteed to build on
45//! Rust versions earlier than the minimum supported version.
46//!
47//! Tracing follows the same compiler support policies as the rest of the Tokio
48//! project. The current stable Rust compiler and the three most recent minor
49//! versions before it will always be supported. For example, if the current
50//! stable compiler version is 1.69, the minimum supported version will not be
51//! increased past 1.66, three minor versions prior. Increasing the minimum
52//! supported compiler version is not considered a semver breaking change as
53//! long as doing so complies with this policy.
54//!
55#![doc(
56 html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
57 issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
58)]
59#![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))]
60#![warn(
61 missing_debug_implementations,
62 missing_docs,
63 rust_2018_idioms,
64 unreachable_pub,
65 bad_style,
66 dead_code,
67 improper_ctypes,
68 non_shorthand_field_patterns,
69 no_mangle_generic_items,
70 overflowing_literals,
71 path_statements,
72 patterns_in_fns_without_body,
73 private_in_public,
74 unconditional_recursion,
75 unused_allocation,
76 unused_comparisons,
77 unused_parens,
78 while_true
79)]
80// TODO: once `tracing` bumps its MSRV to 1.42, remove this allow.
81#![allow(unused)]
82extern crate proc_macro;
83
84use proc_macro2::TokenStream;
85use quote::{quote, ToTokens};
86use syn::parse::{Parse, ParseStream};
87use syn::{Attribute, ItemFn, Signature, Visibility};
88
89mod attr;
90mod expand;
91/// Instruments a function to create and enter a `tracing` [span] every time
92/// the function is called.
93///
94/// Unless overriden, a span with the [`INFO`] [level] will be generated.
95/// The generated span's name will be the name of the function.
96/// By default, all arguments to the function are included as fields on the
97/// span. Arguments that are `tracing` [primitive types] implementing the
98/// [`Value` trait] will be recorded as fields of that type. Types which do
99/// not implement `Value` will be recorded using [`std::fmt::Debug`].
100///
101/// [primitive types]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html#foreign-impls
102/// [`Value` trait]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html.
103///
104/// # Overriding Span Attributes
105///
106/// To change the [name] of the generated span, add a `name` argument to the
107/// `#[instrument]` macro, followed by an equals sign and a string literal. For
108/// example:
109///
110/// ```
111/// # use tracing_attributes::instrument;
112///
113/// // The generated span's name will be "my_span" rather than "my_function".
114/// #[instrument(name = "my_span")]
115/// pub fn my_function() {
116/// // ... do something incredibly interesting and important ...
117/// }
118/// ```
119///
120/// To override the [target] of the generated span, add a `target` argument to
121/// the `#[instrument]` macro, followed by an equals sign and a string literal
122/// for the new target. The [module path] is still recorded separately. For
123/// example:
124///
125/// ```
126/// pub mod my_module {
127/// # use tracing_attributes::instrument;
128/// // The generated span's target will be "my_crate::some_special_target",
129/// // rather than "my_crate::my_module".
130/// #[instrument(target = "my_crate::some_special_target")]
131/// pub fn my_function() {
132/// // ... all kinds of neat code in here ...
133/// }
134/// }
135/// ```
136///
137/// Finally, to override the [level] of the generated span, add a `level`
138/// argument, followed by an equals sign and a string literal with the name of
139/// the desired level. Level names are not case sensitive. For example:
140///
141/// ```
142/// # use tracing_attributes::instrument;
143/// // The span's level will be TRACE rather than INFO.
144/// #[instrument(level = "trace")]
145/// pub fn my_function() {
146/// // ... I have written a truly marvelous implementation of this function,
147/// // which this example is too narrow to contain ...
148/// }
149/// ```
150///
151/// # Skipping Fields
152///
153/// To skip recording one or more arguments to a function or method, pass
154/// the argument's name inside the `skip()` argument on the `#[instrument]`
155/// macro. This can be used when an argument to an instrumented function does
156/// not implement [`fmt::Debug`], or to exclude an argument with a verbose or
157/// costly `Debug` implementation. Note that:
158///
159/// - multiple argument names can be passed to `skip`.
160/// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
161///
162/// You can also use `skip_all` to skip all arguments.
163///
164/// ## Examples
165///
166/// ```
167/// # use tracing_attributes::instrument;
168/// # use std::collections::HashMap;
169/// // This type doesn't implement `fmt::Debug`!
170/// struct NonDebug;
171///
172/// // `arg` will be recorded, while `non_debug` will not.
173/// #[instrument(skip(non_debug))]
174/// fn my_function(arg: usize, non_debug: NonDebug) {
175/// // ...
176/// }
177///
178/// // These arguments are huge
179/// #[instrument(skip_all)]
180/// fn my_big_data_function(large: Vec<u8>, also_large: HashMap<String, String>) {
181/// // ...
182/// }
183/// ```
184///
185/// Skipping the `self` parameter:
186///
187/// ```
188/// # use tracing_attributes::instrument;
189/// #[derive(Debug)]
190/// struct MyType {
191/// data: Vec<u8>, // Suppose this buffer is often quite long...
192/// }
193///
194/// impl MyType {
195/// // Suppose we don't want to print an entire kilobyte of `data`
196/// // every time this is called...
197/// #[instrument(skip(self))]
198/// pub fn my_method(&mut self, an_interesting_argument: usize) {
199/// // ... do something (hopefully, using all that `data`!)
200/// }
201/// }
202/// ```
203///
204/// # Adding Fields
205///
206/// Additional fields (key-value pairs with arbitrary data) can be passed to
207/// to the generated span through the `fields` argument on the
208/// `#[instrument]` macro. Strings, integers or boolean literals are accepted values
209/// for each field. The name of the field must be a single valid Rust
210/// identifier, nested (dotted) field names are not supported. Any
211/// Rust expression can be used as a field value in this manner. These
212/// expressions will be evaluated at the beginning of the function's body, so
213/// arguments to the function may be used in these expressions. Field names may
214/// also be specified *without* values. Doing so will result in an [empty field]
215/// whose value may be recorded later within the function body.
216///
217/// Note that overlap between the names of fields and (non-skipped) arguments
218/// will result in a compile error.
219///
220/// ## Examples
221///
222/// Adding a new field based on the value of an argument:
223///
224/// ```
225/// # use tracing_attributes::instrument;
226///
227/// // This will record a field named "i" with the value of `i` *and* a field
228/// // named "next" with the value of `i` + 1.
229/// #[instrument(fields(next = i + 1))]
230/// pub fn my_function(i: usize) {
231/// // ...
232/// }
233/// ```
234///
235/// Recording specific properties of a struct as their own fields:
236///
237/// ```
238/// # mod http {
239/// # pub struct Error;
240/// # pub struct Response<B> { pub(super) _b: std::marker::PhantomData<B> }
241/// # pub struct Request<B> { _b: B }
242/// # impl<B> std::fmt::Debug for Request<B> {
243/// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244/// # f.pad("request")
245/// # }
246/// # }
247/// # impl<B> Request<B> {
248/// # pub fn uri(&self) -> &str { "fake" }
249/// # pub fn method(&self) -> &str { "GET" }
250/// # }
251/// # }
252/// # use tracing_attributes::instrument;
253///
254/// // This will record the request's URI and HTTP method as their own separate
255/// // fields.
256/// #[instrument(fields(http.uri = req.uri(), http.method = req.method()))]
257/// pub fn handle_request<B>(req: http::Request<B>) -> http::Response<B> {
258/// // ... handle the request ...
259/// # http::Response { _b: std::marker::PhantomData }
260/// }
261/// ```
262///
263/// This can be used in conjunction with `skip` or `skip_all` to record only
264/// some fields of a struct:
265/// ```
266/// # use tracing_attributes::instrument;
267/// // Remember the struct with the very large `data` field from the earlier
268/// // example? Now it also has a `name`, which we might want to include in
269/// // our span.
270/// #[derive(Debug)]
271/// struct MyType {
272/// name: &'static str,
273/// data: Vec<u8>,
274/// }
275///
276/// impl MyType {
277/// // This will skip the `data` field, but will include `self.name`,
278/// // formatted using `fmt::Display`.
279/// #[instrument(skip(self), fields(self.name = %self.name))]
280/// pub fn my_method(&mut self, an_interesting_argument: usize) {
281/// // ... do something (hopefully, using all that `data`!)
282/// }
283/// }
284/// ```
285///
286/// Adding an empty field to be recorded later:
287///
288/// ```
289/// # use tracing_attributes::instrument;
290///
291/// // This function does a very interesting and important mathematical calculation.
292/// // Suppose we want to record both the inputs to the calculation *and* its result...
293/// #[instrument(fields(result))]
294/// pub fn do_calculation(input_1: usize, input_2: usize) -> usize {
295/// // Rerform the calculation.
296/// let result = input_1 + input_2;
297///
298/// // Record the result as part of the current span.
299/// tracing::Span::current().record("result", &result);
300///
301/// // Now, the result will also be included on this event!
302/// tracing::info!("calculation complete!");
303///
304/// // ... etc ...
305/// # 0
306/// }
307/// ```
308///
309/// # Examples
310///
311/// Instrumenting a function:
312///
313/// ```
314/// # use tracing_attributes::instrument;
315/// #[instrument]
316/// pub fn my_function(my_arg: usize) {
317/// // This event will be recorded inside a span named `my_function` with the
318/// // field `my_arg`.
319/// tracing::info!("inside my_function!");
320/// // ...
321/// }
322/// ```
323/// Setting the level for the generated span:
324/// ```
325/// # use tracing_attributes::instrument;
326/// # use tracing::Level;
327/// #[instrument(level = Level::DEBUG)]
328/// pub fn my_function() {
329/// // ...
330/// }
331/// ```
332/// Levels can be specified either with [`Level`] constants, literal strings
333/// (e.g., `"debug"`, `"info"`) or numerically (1—5, corresponding to [`Level::TRACE`]—[`Level::ERROR`]).
334///
335/// Overriding the generated span's name:
336/// ```
337/// # use tracing_attributes::instrument;
338/// #[instrument(name = "my_name")]
339/// pub fn my_function() {
340/// // ...
341/// }
342/// ```
343/// Overriding the generated span's target:
344/// ```
345/// # use tracing_attributes::instrument;
346/// #[instrument(target = "my_target")]
347/// pub fn my_function() {
348/// // ...
349/// }
350/// ```
351/// Overriding the generated span's parent:
352/// ```
353/// # use tracing_attributes::instrument;
354/// #[instrument(parent = None)]
355/// pub fn my_function() {
356/// // ...
357/// }
358/// ```
359/// ```
360/// # use tracing_attributes::instrument;
361/// // A struct which owns a span handle.
362/// struct MyStruct
363/// {
364/// span: tracing::Span
365/// }
366///
367/// impl MyStruct
368/// {
369/// // Use the struct's `span` field as the parent span
370/// #[instrument(parent = &self.span, skip(self))]
371/// fn my_method(&self) {}
372/// }
373/// ```
374/// Specifying [`follows_from`] relationships:
375/// ```
376/// # use tracing_attributes::instrument;
377/// #[instrument(follows_from = causes)]
378/// pub fn my_function(causes: &[tracing::Id]) {
379/// // ...
380/// }
381/// ```
382/// Any expression of type `impl IntoIterator<Item = impl Into<Option<Id>>>`
383/// may be provided to `follows_from`; e.g.:
384/// ```
385/// # use tracing_attributes::instrument;
386/// #[instrument(follows_from = [cause])]
387/// pub fn my_function(cause: &tracing::span::EnteredSpan) {
388/// // ...
389/// }
390/// ```
391///
392///
393/// To skip recording an argument, pass the argument's name to the `skip`:
394///
395/// ```
396/// # use tracing_attributes::instrument;
397/// struct NonDebug;
398///
399/// #[instrument(skip(non_debug))]
400/// fn my_function(arg: usize, non_debug: NonDebug) {
401/// // ...
402/// }
403/// ```
404///
405/// To add additional context to the span, pass key-value pairs to `fields`:
406///
407/// ```
408/// # use tracing_attributes::instrument;
409/// #[instrument(fields(foo="bar", id=1, show=true))]
410/// fn my_function(arg: usize) {
411/// // ...
412/// }
413/// ```
414///
415/// Adding the `ret` argument to `#[instrument]` will emit an event with the function's
416/// return value when the function returns:
417///
418/// ```
419/// # use tracing_attributes::instrument;
420/// #[instrument(ret)]
421/// fn my_function() -> i32 {
422/// 42
423/// }
424/// ```
425/// The return value event will have the same level as the span generated by `#[instrument]`.
426/// By default, this will be [`INFO`], but if the level is overridden, the event will be at the same
427/// level.
428///
429/// It's also possible to override the level for the `ret` event independently:
430///
431/// ```
432/// # use tracing_attributes::instrument;
433/// # use tracing::Level;
434/// #[instrument(ret(level = Level::WARN))]
435/// fn my_function() -> i32 {
436/// 42
437/// }
438/// ```
439///
440/// **Note**: if the function returns a `Result<T, E>`, `ret` will record returned values if and
441/// only if the function returns [`Result::Ok`].
442///
443/// By default, returned values will be recorded using their [`std::fmt::Debug`] implementations.
444/// If a returned value implements [`std::fmt::Display`], it can be recorded using its `Display`
445/// implementation instead, by writing `ret(Display)`:
446///
447/// ```
448/// # use tracing_attributes::instrument;
449/// #[instrument(ret(Display))]
450/// fn my_function() -> i32 {
451/// 42
452/// }
453/// ```
454///
455/// If the function returns a `Result<T, E>` and `E` implements `std::fmt::Display`, adding
456/// `err` or `err(Display)` will emit error events when the function returns `Err`:
457///
458/// ```
459/// # use tracing_attributes::instrument;
460/// #[instrument(err)]
461/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
462/// Ok(())
463/// }
464/// ```
465///
466/// The level of the error value event defaults to `ERROR`.
467///
468/// Similarly, overriding the level of the `err` event :
469///
470/// ```
471/// # use tracing_attributes::instrument;
472/// # use tracing::Level;
473/// #[instrument(err(level = Level::INFO))]
474/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
475/// Ok(())
476/// }
477/// ```
478///
479/// By default, error values will be recorded using their `std::fmt::Display` implementations.
480/// If an error implements `std::fmt::Debug`, it can be recorded using its `Debug` implementation
481/// instead by writing `err(Debug)`:
482///
483/// ```
484/// # use tracing_attributes::instrument;
485/// #[instrument(err(Debug))]
486/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
487/// Ok(())
488/// }
489/// ```
490///
491/// If a `target` is specified, both the `ret` and `err` arguments will emit outputs to
492/// the declared target (or the default channel if `target` is not specified).
493///
494/// The `ret` and `err` arguments can be combined in order to record an event if a
495/// function returns [`Result::Ok`] or [`Result::Err`]:
496///
497/// ```
498/// # use tracing_attributes::instrument;
499/// #[instrument(err, ret)]
500/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
501/// Ok(())
502/// }
503/// ```
504///
505/// `async fn`s may also be instrumented:
506///
507/// ```
508/// # use tracing_attributes::instrument;
509/// #[instrument]
510/// pub async fn my_function() -> Result<(), ()> {
511/// // ...
512/// # Ok(())
513/// }
514/// ```
515///
516/// It also works with [async-trait](https://crates.io/crates/async-trait)
517/// (a crate that allows defining async functions in traits,
518/// something not currently possible in Rust),
519/// and hopefully most libraries that exhibit similar behaviors:
520///
521/// ```
522/// # use tracing::instrument;
523/// use async_trait::async_trait;
524///
525/// #[async_trait]
526/// pub trait Foo {
527/// async fn foo(&self, arg: usize);
528/// }
529///
530/// #[derive(Debug)]
531/// struct FooImpl(usize);
532///
533/// #[async_trait]
534/// impl Foo for FooImpl {
535/// #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
536/// async fn foo(&self, arg: usize) {}
537/// }
538/// ```
539///
540/// `const fn` cannot be instrumented, and will result in a compilation failure:
541///
542/// ```compile_fail
543/// # use tracing_attributes::instrument;
544/// #[instrument]
545/// const fn my_const_function() {}
546/// ```
547///
548/// [span]: https://docs.rs/tracing/latest/tracing/span/index.html
549/// [name]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.name
550/// [target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target
551/// [level]: https://docs.rs/tracing/latest/tracing/struct.Level.html
552/// [module path]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.module_path
553/// [`INFO`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.INFO
554/// [empty field]: https://docs.rs/tracing/latest/tracing/field/struct.Empty.html
555/// [field syntax]: https://docs.rs/tracing/latest/tracing/#recording-fields
556/// [`follows_from`]: https://docs.rs/tracing/latest/tracing/struct.Span.html#method.follows_from
557/// [`tracing`]: https://github.com/tokio-rs/tracing
558/// [`fmt::Debug`]: std::fmt::Debug
559/// [`Level`]: https://docs.rs/tracing/latest/tracing/struct.Level.html
560/// [`Level::TRACE`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.TRACE
561/// [`Level::ERROR`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.ERROR
562#[proc_macro_attribute]
563pub fn instrument(
564 args: proc_macro::TokenStream,
565 item: proc_macro::TokenStream,
566) -> proc_macro::TokenStream {
567 let args: InstrumentArgs = syn::parse_macro_input!(args as attr::InstrumentArgs);
568 // Cloning a `TokenStream` is cheap since it's reference counted internally.
569 instrument_precise(args.clone(), item.clone())
570 .unwrap_or_else(|_err: Error| instrument_speculative(args, item))
571}
572
573/// Instrument the function, without parsing the function body (instead using the raw tokens).
574fn instrument_speculative(
575 args: attr::InstrumentArgs,
576 item: proc_macro::TokenStream,
577) -> proc_macro::TokenStream {
578 let input: MaybeItemFn = syn::parse_macro_input!(item as MaybeItemFn);
579 let instrumented_function_name: String = input.sig.ident.to_string();
580 expandTokenStream::gen_function(
581 input.as_ref(),
582 args,
583 instrumented_function_name:instrumented_function_name.as_str(),
584 self_type:None,
585 )
586 .into()
587}
588
589/// Instrument the function, by fully parsing the function body,
590/// which allows us to rewrite some statements related to async-like patterns.
591fn instrument_precise(
592 args: attr::InstrumentArgs,
593 item: proc_macro::TokenStream,
594) -> Result<proc_macro::TokenStream, syn::Error> {
595 let input = syn::parse::<ItemFn>(item)?;
596 let instrumented_function_name = input.sig.ident.to_string();
597
598 if input.sig.constness.is_some() {
599 return Ok(quote! {
600 compile_error!("the `#[instrument]` attribute may not be used with `const fn`s")
601 }
602 .into());
603 }
604
605 // check for async_trait-like patterns in the block, and instrument
606 // the future instead of the wrapper
607 if let Some(async_like) = expand::AsyncInfo::from_fn(&input) {
608 return async_like.gen_async(args, instrumented_function_name.as_str());
609 }
610
611 let input = MaybeItemFn::from(input);
612
613 Ok(expand::gen_function(
614 input.as_ref(),
615 args,
616 instrumented_function_name.as_str(),
617 None,
618 )
619 .into())
620}
621
622/// This is a more flexible/imprecise `ItemFn` type,
623/// which's block is just a `TokenStream` (it may contain invalid code).
624#[derive(Debug, Clone)]
625struct MaybeItemFn {
626 outer_attrs: Vec<Attribute>,
627 inner_attrs: Vec<Attribute>,
628 vis: Visibility,
629 sig: Signature,
630 block: TokenStream,
631}
632
633impl MaybeItemFn {
634 fn as_ref(&self) -> MaybeItemFnRef<'_, TokenStream> {
635 MaybeItemFnRef {
636 outer_attrs: &self.outer_attrs,
637 inner_attrs: &self.inner_attrs,
638 vis: &self.vis,
639 sig: &self.sig,
640 block: &self.block,
641 }
642 }
643}
644
645/// This parses a `TokenStream` into a `MaybeItemFn`
646/// (just like `ItemFn`, but skips parsing the body).
647impl Parse for MaybeItemFn {
648 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
649 let outer_attrs: Vec = input.call(function:Attribute::parse_outer)?;
650 let vis: Visibility = input.parse()?;
651 let sig: Signature = input.parse()?;
652 let inner_attrs: Vec = input.call(function:Attribute::parse_inner)?;
653 let block: TokenStream = input.parse()?;
654 Ok(Self {
655 outer_attrs,
656 inner_attrs,
657 vis,
658 sig,
659 block,
660 })
661 }
662}
663
664impl From<ItemFn> for MaybeItemFn {
665 fn from(
666 ItemFn {
667 attrs: Vec,
668 vis: Visibility,
669 sig: Signature,
670 block: Box,
671 }: ItemFn,
672 ) -> Self {
673 let (outer_attrs: Vec, inner_attrs: Vec) = attrsIntoIter
674 .into_iter()
675 .partition(|attr: &Attribute| attr.style == syn::AttrStyle::Outer);
676 Self {
677 outer_attrs,
678 inner_attrs,
679 vis,
680 sig,
681 block: block.to_token_stream(),
682 }
683 }
684}
685
686/// A generic reference type for `MaybeItemFn`,
687/// that takes a generic block type `B` that implements `ToTokens` (eg. `TokenStream`, `Block`).
688#[derive(Debug, Clone)]
689struct MaybeItemFnRef<'a, B: ToTokens> {
690 outer_attrs: &'a Vec<Attribute>,
691 inner_attrs: &'a Vec<Attribute>,
692 vis: &'a Visibility,
693 sig: &'a Signature,
694 block: &'a B,
695}
696