Attribute Macro tracing::instrument[][src]

#[instrument]
This is supported on crate feature attributes only.
Expand description

Instruments a function to create and enter a tracing span every time the function is called.

Unless overriden, a span with info level will be generated. The generated span’s name will be the name of the function. By default, all arguments to the function are included as fields on the span. Arguments that are tracing primitive types implementing the Value trait will be recorded as fields of that type. Types which do not implement Value will be recorded using std::fmt::Debug.

To skip recording a function’s or method’s argument, pass the argument’s name to the skip argument on the #[instrument] macro. For example, skip can be used when an argument to an instrumented function does not implement fmt::Debug, or to exclude an argument with a verbose or costly Debug implementation. Note that:

  • multiple argument names can be passed to skip.
  • arguments passed to skip do not need to implement fmt::Debug.

You can also pass additional fields (key-value pairs with arbitrary data) to the generated span. This is achieved using the fields argument on the #[instrument] macro. You can use a string, integer or boolean literal as a value for each field. The name of the field must be a single valid Rust identifier, nested (dotted) field names are not supported.

Note that overlap between the names of fields and (non-skipped) arguments will result in a compile error.

Examples

Instrumenting a function:

#[instrument]
pub fn my_function(my_arg: usize) {
    // This event will be recorded inside a span named `my_function` with the
    // field `my_arg`.
    tracing::info!("inside my_function!");
    // ...
}

Setting the level for the generated span:

#[instrument(level = "debug")]
pub fn my_function() {
    // ...
}

Overriding the generated span’s name:

#[instrument(name = "my_name")]
pub fn my_function() {
    // ...
}

Overriding the generated span’s target:

#[instrument(target = "my_target")]
pub fn my_function() {
    // ...
}

To skip recording an argument, pass the argument’s name to the skip:

struct NonDebug;

#[instrument(skip(non_debug))]
fn my_function(arg: usize, non_debug: NonDebug) {
    // ...
}

To add an additional context to the span, you can pass key-value pairs to fields:

#[instrument(fields(foo="bar", id=1, show=true))]
fn my_function(arg: usize) {
    // ...
}

Adding the ret argument to #[instrument] will emit an event with the function’s return value when the function returns:

#[instrument(ret)]
fn my_function() -> i32 {
    42
}

The return value event will have the same level as the span generated by #[instrument]. By default, this will be TRACE, but if the level is overridden, the event will be at the same level.

Note: if the function returns a Result<T, E>, ret will record returned values if and only if the function returns Result::Ok.

By default, returned values will be recorded using their std::fmt::Debug implementations. If a returned value implements std::fmt::Display, it can be recorded using its Display implementation instead, by writing ret(Display):

#[instrument(ret(Display))]
fn my_function() -> i32 {
    42
}

If the function returns a Result<T, E> and E implements std::fmt::Display, you can add err or err(Display) to emit error events when the function returns Err:

#[instrument(err)]
fn my_function(arg: usize) -> Result<(), std::io::Error> {
    Ok(())
}

By default, error values will be recorded using their std::fmt::Display implementations. If an error implements std::fmt::Debug, it can be recorded using its Debug implementation instead, by writing err(Debug):

#[instrument(err(Debug))]
fn my_function(arg: usize) -> Result<(), std::io::Error> {
    Ok(())
}

The ret and err arguments can be combined in order to record an event if a function returns Result::Ok or Result::Err:

#[instrument(err, ret)]
fn my_function(arg: usize) -> Result<(), std::io::Error> {
    Ok(())
}

async fns may also be instrumented:

#[instrument]
pub async fn my_function() -> Result<(), ()> {
    // ...
}

It also works with async-trait (a crate that allows defining async functions in traits, something not currently possible in Rust), and hopefully most libraries that exhibit similar behaviors:

use async_trait::async_trait;

#[async_trait]
pub trait Foo {
    async fn foo(&self, arg: usize);
}

#[derive(Debug)]
struct FooImpl(usize);

#[async_trait]
impl Foo for FooImpl {
    #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
    async fn foo(&self, arg: usize) {}
}

Note than on async-trait <= 0.1.43, references to the Self type inside the fields argument were only allowed when the instrumented function is a method (i.e., the function receives self as an argument). For example, this used to not work because the instrument function didn’t receive self:

use async_trait::async_trait;

#[async_trait]
pub trait Bar {
    async fn bar();
}

#[derive(Debug)]
struct BarImpl(usize);

#[async_trait]
impl Bar for BarImpl {
    #[instrument(fields(tmp = std::any::type_name::<Self>()))]
    async fn bar() {}
}

Instead, you should manually rewrite any Self types as the type for which you implement the trait: #[instrument(fields(tmp = std::any::type_name::<Bar>()))] (or maybe you can just bump async-trait).