[][src]Attribute Macro tracing::instrument

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

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. Any arguments to that function will be recorded as fields using 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:

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) {
    // ...
}

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

#[instrument(err)]
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) {}
}

An interesting note on this subject is that references to the Self type inside the fields argument are only allowed when the instrumented function is a method aka. the function receives self as an argument. For example, this will not work because it doesn't receive self:

This example deliberately fails to compile
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>()))].