1 //! A procedural macro attribute for instrumenting functions with [`tracing`].
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.
7 //! Note that this macro is also re-exported by the main `tracing` crate.
9 //! *Compiler support: [requires `rustc` 1.49+][msrv]*
11 //! [msrv]: #supported-rust-versions
15 //! First, add this to your `Cargo.toml`:
19 //! tracing-attributes = "0.1.20"
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:
27 //! use tracing_attributes::instrument;
30 //! pub fn my_function(my_arg: usize) {
37 //! [`tracing`]: https://crates.io/crates/tracing
38 //! [span]: https://docs.rs/tracing/latest/tracing/span/index.html
39 //! [instrument]: attr.instrument.html
41 //! ## Supported Rust Versions
43 //! Tracing is built against the latest stable release. The minimum supported
44 //! version is 1.49. The current Tracing version is not guaranteed to build on
45 //! Rust versions earlier than the minimum supported version.
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.45, the minimum supported version will not be
51 //! increased past 1.42, 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.
55 #![doc(html_root_url = "https://docs.rs/tracing-attributes/0.1.20")]
57 html_logo_url
= "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
58 issue_tracker_base_url
= "https://github.com/tokio-rs/tracing/issues/"
60 #![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))]
62 missing_debug_implementations
,
70 non_shorthand_field_patterns
,
71 no_mangle_generic_items
,
74 patterns_in_fns_without_body
,
76 unconditional_recursion
,
82 // TODO: once `tracing` bumps its MSRV to 1.42, remove this allow.
84 extern crate proc_macro
;
86 use proc_macro2
::TokenStream
;
88 use syn
::parse
::{Parse, ParseStream}
;
89 use syn
::{Attribute, Block, ItemFn, Signature, Visibility}
;
93 /// Instruments a function to create and enter a `tracing` [span] every time
94 /// the function is called.
96 /// Unless overriden, a span with `info` level will be generated.
97 /// The generated span's name will be the name of the function.
98 /// By default, all arguments to the function are included as fields on the
99 /// span. Arguments that are `tracing` [primitive types] implementing the
100 /// [`Value` trait] will be recorded as fields of that type. Types which do
101 /// not implement `Value` will be recorded using [`std::fmt::Debug`].
103 /// [primitive types]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html#foreign-impls
104 /// [`Value` trait]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html.
106 /// # Overriding Span Attributes
108 /// To change the [name] of the generated span, add a `name` argument to the
109 /// `#[instrument]` macro, followed by an equals sign and a string literal. For
113 /// # use tracing_attributes::instrument;
115 /// // The generated span's name will be "my_span" rather than "my_function".
116 /// #[instrument(name = "my_span")]
117 /// pub fn my_function() {
118 /// // ... do something incredibly interesting and important ...
122 /// To override the [target] of the generated span, add a `target` argument to
123 /// the `#[instrument]` macro, followed by an equals sign and a string literal
124 /// for the new target. The [module path] is still recorded separately. For
128 /// pub mod my_module {
129 /// # use tracing_attributes::instrument;
130 /// // The generated span's target will be "my_crate::some_special_target",
131 /// // rather than "my_crate::my_module".
132 /// #[instrument(target = "my_crate::some_special_target")]
133 /// pub fn my_function() {
134 /// // ... all kinds of neat code in here ...
139 /// Finally, to override the [level] of the generated span, add a `level`
140 /// argument, followed by an equals sign and a string literal with the name of
141 /// the desired level. Level names are not case sensitive. For example:
144 /// # use tracing_attributes::instrument;
145 /// // The span's level will be TRACE rather than INFO.
146 /// #[instrument(level = "trace")]
147 /// pub fn my_function() {
148 /// // ... I have written a truly marvelous implementation of this function,
149 /// // which this example is too narrow to contain ...
153 /// # Skipping Fields
155 /// To skip recording one or more arguments to a function or method, pass
156 /// the argument's name inside the `skip()` argument on the `#[instrument]`
157 /// macro. This can be used when an argument to an instrumented function does
158 /// not implement [`fmt::Debug`], or to exclude an argument with a verbose or
159 /// costly `Debug` implementation. Note that:
161 /// - multiple argument names can be passed to `skip`.
162 /// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
164 /// You can also use `skip_all` to skip all arguments.
169 /// # use tracing_attributes::instrument;
170 /// # use std::collections::HashMap;
171 /// // This type doesn't implement `fmt::Debug`!
174 /// // `arg` will be recorded, while `non_debug` will not.
175 /// #[instrument(skip(non_debug))]
176 /// fn my_function(arg: usize, non_debug: NonDebug) {
180 /// // These arguments are huge
181 /// #[instrument(skip_all)]
182 /// fn my_big_data_function(large: Vec<u8>, also_large: HashMap<String, String>) {
187 /// Skipping the `self` parameter:
190 /// # use tracing_attributes::instrument;
193 /// data: Vec<u8>, // Suppose this buffer is often quite long...
197 /// // Suppose we don't want to print an entire kilobyte of `data`
198 /// // every time this is called...
199 /// #[instrument(skip(self))]
200 /// pub fn my_method(&mut self, an_interesting_argument: usize) {
201 /// // ... do something (hopefully, using all that `data`!)
208 /// Additional fields (key-value pairs with arbitrary data) may be added to the
209 /// generated span using the `fields` argument on the `#[instrument]` macro. Any
210 /// Rust expression can be used as a field value in this manner. These
211 /// expressions will be evaluated at the beginning of the function's body, so
212 /// arguments to the function may be used in these expressions. Field names may
213 /// also be specified *without* values. Doing so will result in an [empty field]
214 /// whose value may be recorded later within the function body.
216 /// This supports the same [field syntax] as the `span!` and `event!` macros.
218 /// Note that overlap between the names of fields and (non-skipped) arguments
219 /// will result in a compile error.
223 /// Adding a new field based on the value of an argument:
226 /// # use tracing_attributes::instrument;
228 /// // This will record a field named "i" with the value of `i` *and* a field
229 /// // named "next" with the value of `i` + 1.
230 /// #[instrument(fields(next = i + 1))]
231 /// pub fn my_function(i: usize) {
236 /// Recording specific properties of a struct as their own fields:
240 /// # pub struct Error;
241 /// # pub struct Response<B> { pub(super) _b: std::marker::PhantomData<B> }
242 /// # pub struct Request<B> { _b: B }
243 /// # impl<B> std::fmt::Debug for Request<B> {
244 /// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 /// # f.pad("request")
248 /// # impl<B> Request<B> {
249 /// # pub fn uri(&self) -> &str { "fake" }
250 /// # pub fn method(&self) -> &str { "GET" }
253 /// # use tracing_attributes::instrument;
255 /// // This will record the request's URI and HTTP method as their own separate
257 /// #[instrument(fields(http.uri = req.uri(), http.method = req.method()))]
258 /// pub fn handle_request<B>(req: http::Request<B>) -> http::Response<B> {
259 /// // ... handle the request ...
260 /// # http::Response { _b: std::marker::PhantomData }
264 /// This can be used in conjunction with `skip` or `skip_all` to record only
265 /// some fields of a struct:
267 /// # use tracing_attributes::instrument;
268 /// // Remember the struct with the very large `data` field from the earlier
269 /// // example? Now it also has a `name`, which we might want to include in
273 /// name: &'static str,
278 /// // This will skip the `data` field, but will include `self.name`,
279 /// // formatted using `fmt::Display`.
280 /// #[instrument(skip(self), fields(self.name = %self.name))]
281 /// pub fn my_method(&mut self, an_interesting_argument: usize) {
282 /// // ... do something (hopefully, using all that `data`!)
287 /// Adding an empty field to be recorded later:
290 /// # use tracing_attributes::instrument;
292 /// // This function does a very interesting and important mathematical calculation.
293 /// // Suppose we want to record both the inputs to the calculation *and* its result...
294 /// #[instrument(fields(result))]
295 /// pub fn do_calculation(input_1: usize, input_2: usize) -> usize {
296 /// // Rerform the calculation.
297 /// let result = input_1 + input_2;
299 /// // Record the result as part of the current span.
300 /// tracing::Span::current().record("result", &result);
302 /// // Now, the result will also be included on this event!
303 /// tracing::info!("calculation complete!");
312 /// Instrumenting a function:
315 /// # use tracing_attributes::instrument;
317 /// pub fn my_function(my_arg: usize) {
318 /// // This event will be recorded inside a span named `my_function` with the
319 /// // field `my_arg`.
320 /// tracing::info!("inside my_function!");
324 /// Setting the level for the generated span:
326 /// # use tracing_attributes::instrument;
327 /// #[instrument(level = "debug")]
328 /// pub fn my_function() {
332 /// Overriding the generated span's name:
334 /// # use tracing_attributes::instrument;
335 /// #[instrument(name = "my_name")]
336 /// pub fn my_function() {
340 /// Overriding the generated span's target:
342 /// # use tracing_attributes::instrument;
343 /// #[instrument(target = "my_target")]
344 /// pub fn my_function() {
349 /// To skip recording an argument, pass the argument's name to the `skip`:
352 /// # use tracing_attributes::instrument;
355 /// #[instrument(skip(non_debug))]
356 /// fn my_function(arg: usize, non_debug: NonDebug) {
361 /// To add an additional context to the span, pass key-value pairs to `fields`:
364 /// # use tracing_attributes::instrument;
365 /// #[instrument(fields(foo="bar", id=1, show=true))]
366 /// fn my_function(arg: usize) {
371 /// Adding the `ret` argument to `#[instrument]` will emit an event with the function's
372 /// return value when the function returns:
375 /// # use tracing_attributes::instrument;
376 /// #[instrument(ret)]
377 /// fn my_function() -> i32 {
381 /// The return value event will have the same level as the span generated by `#[instrument]`.
382 /// By default, this will be `TRACE`, but if the level is overridden, the event will be at the same
385 /// **Note**: if the function returns a `Result<T, E>`, `ret` will record returned values if and
386 /// only if the function returns [`Result::Ok`].
388 /// By default, returned values will be recorded using their [`std::fmt::Debug`] implementations.
389 /// If a returned value implements [`std::fmt::Display`], it can be recorded using its `Display`
390 /// implementation instead, by writing `ret(Display)`:
393 /// # use tracing_attributes::instrument;
394 /// #[instrument(ret(Display))]
395 /// fn my_function() -> i32 {
400 /// If the function returns a `Result<T, E>` and `E` implements `std::fmt::Display`, you can add
401 /// `err` or `err(Display)` to emit error events when the function returns `Err`:
404 /// # use tracing_attributes::instrument;
405 /// #[instrument(err)]
406 /// fn my_function(arg: usize) -> Result<(), std::io::Error> {
411 /// By default, error values will be recorded using their `std::fmt::Display` implementations.
412 /// If an error implements `std::fmt::Debug`, it can be recorded using its `Debug` implementation
413 /// instead, by writing `err(Debug)`:
416 /// # use tracing_attributes::instrument;
417 /// #[instrument(err(Debug))]
418 /// fn my_function(arg: usize) -> Result<(), std::io::Error> {
423 /// The `ret` and `err` arguments can be combined in order to record an event if a
424 /// function returns [`Result::Ok`] or [`Result::Err`]:
427 /// # use tracing_attributes::instrument;
428 /// #[instrument(err, ret)]
429 /// fn my_function(arg: usize) -> Result<(), std::io::Error> {
434 /// `async fn`s may also be instrumented:
437 /// # use tracing_attributes::instrument;
439 /// pub async fn my_function() -> Result<(), ()> {
445 /// It also works with [async-trait](https://crates.io/crates/async-trait)
446 /// (a crate that allows defining async functions in traits,
447 /// something not currently possible in Rust),
448 /// and hopefully most libraries that exhibit similar behaviors:
451 /// # use tracing::instrument;
452 /// use async_trait::async_trait;
456 /// async fn foo(&self, arg: usize);
460 /// struct FooImpl(usize);
463 /// impl Foo for FooImpl {
464 /// #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
465 /// async fn foo(&self, arg: usize) {}
469 /// Note than on `async-trait` <= 0.1.43, references to the `Self`
470 /// type inside the `fields` argument were only allowed when the instrumented
471 /// function is a method (i.e., the function receives `self` as an argument).
472 /// For example, this *used to not work* because the instrument function
473 /// didn't receive `self`:
475 /// # use tracing::instrument;
476 /// use async_trait::async_trait;
484 /// struct BarImpl(usize);
487 /// impl Bar for BarImpl {
488 /// #[instrument(fields(tmp = std::any::type_name::<Self>()))]
489 /// async fn bar() {}
492 /// Instead, you should manually rewrite any `Self` types as the type for
493 /// which you implement the trait: `#[instrument(fields(tmp = std::any::type_name::<Bar>()))]`
494 /// (or maybe you can just bump `async-trait`).
496 /// [span]: https://docs.rs/tracing/latest/tracing/span/index.html
497 /// [name]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.name
498 /// [target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target
499 /// [level]: https://docs.rs/tracing/latest/tracing/struct.Level.html
500 /// [module path]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.module_path
501 /// [`INFO`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.INFO
502 /// [empty field]: https://docs.rs/tracing/latest/tracing/field/struct.Empty.html
503 /// [field syntax]: https://docs.rs/tracing/latest/tracing/#recording-fields
504 /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
505 #[proc_macro_attribute]
507 args
: proc_macro
::TokenStream
,
508 item
: proc_macro
::TokenStream
,
509 ) -> proc_macro
::TokenStream
{
510 let args
= syn
::parse_macro_input
!(args
as attr
::InstrumentArgs
);
511 // Cloning a `TokenStream` is cheap since it's reference counted internally.
512 instrument_precise(args
.clone(), item
.clone())
513 .unwrap_or_else(|_err
| instrument_speculative(args
, item
))
516 /// Instrument the function, without parsing the function body (instead using the raw tokens).
517 fn instrument_speculative(
518 args
: attr
::InstrumentArgs
,
519 item
: proc_macro
::TokenStream
,
520 ) -> proc_macro
::TokenStream
{
521 let input
= syn
::parse_macro_input
!(item
as MaybeItemFn
);
522 let instrumented_function_name
= input
.sig
.ident
.to_string();
523 expand
::gen_function(
526 instrumented_function_name
.as_str(),
532 /// Instrument the function, by fully parsing the function body,
533 /// which allows us to rewrite some statements related to async-like patterns.
534 fn instrument_precise(
535 args
: attr
::InstrumentArgs
,
536 item
: proc_macro
::TokenStream
,
537 ) -> Result
<proc_macro
::TokenStream
, syn
::Error
> {
538 let input
= syn
::parse
::<ItemFn
>(item
)?
;
539 let instrumented_function_name
= input
.sig
.ident
.to_string();
541 // check for async_trait-like patterns in the block, and instrument
542 // the future instead of the wrapper
543 if let Some(async_like
) = expand
::AsyncInfo
::from_fn(&input
) {
544 return Ok(async_like
.gen_async(args
, instrumented_function_name
.as_str()));
547 Ok(expand
::gen_function(
550 instrumented_function_name
.as_str(),
556 /// This is a more flexible/imprecise `ItemFn` type,
557 /// which's block is just a `TokenStream` (it may contain invalid code).
558 #[derive(Debug, Clone)]
560 attrs
: Vec
<Attribute
>,
567 fn as_ref(&self) -> MaybeItemFnRef
<'_
, TokenStream
> {
577 /// This parses a `TokenStream` into a `MaybeItemFn`
578 /// (just like `ItemFn`, but skips parsing the body).
579 impl Parse
for MaybeItemFn
{
580 fn parse(input
: ParseStream
<'_
>) -> syn
::Result
<Self> {
581 let attrs
= input
.call(syn
::Attribute
::parse_outer
)?
;
582 let vis
: Visibility
= input
.parse()?
;
583 let sig
: Signature
= input
.parse()?
;
584 let block
: TokenStream
= input
.parse()?
;
594 /// A generic reference type for `MaybeItemFn`,
595 /// that takes a generic block type `B` that implements `ToTokens` (eg. `TokenStream`, `Block`).
596 #[derive(Debug, Clone)]
597 struct MaybeItemFnRef
<'a
, B
: ToTokens
> {
598 attrs
: &'a Vec
<Attribute
>,
604 impl<'a
> From
<&'a ItemFn
> for MaybeItemFnRef
<'a
, Box
<Block
>> {
605 fn from(val
: &'a ItemFn
) -> Self {