🛈 Note: This is pre-release documentation for the upcoming tracing 0.2.0 ecosystem.

For the release documentation, please see docs.rs, instead.

Attribute Macro tracing::instrument

#[instrument]
Available on crate feature attributes only.
Expand description

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

Unless overridden, 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.

Additional fields (key-value pairs with arbitrary data) can be passed to to the generated span through the fields argument on the #[instrument] macro. Strings, integers or boolean literals are accepted values 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 = Level::DEBUG)]
pub fn my_function() {
    // ...
}

Levels can be specified either with Level constants, literal strings (e.g., "debug", "info") or numerically (1—5, corresponding to Level::TRACELevel::ERROR).

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

Overriding the generated span’s parent:

#[instrument(parent = None)]
pub fn my_function() {
    // ...
}
// A struct which owns a span handle.
struct MyStruct
{
    span: tracing::Span
}

impl MyStruct
{
    // Use the struct's `span` field as the parent span
    #[instrument(parent = &self.span, skip(self))]
    fn my_method(&self) {}
}

Specifying follows_from relationships:

#[instrument(follows_from = causes)]
pub fn my_function(causes: &[tracing::Id]) {
    // ...
}

Any expression of type impl IntoIterator<Item = impl Into<Option<Id>>> may be provided to follows_from; e.g.:

#[instrument(follows_from = [cause])]
pub fn my_function(cause: &tracing::span::EnteredSpan) {
    // ...
}

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 additional context to the span, 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 level of the return value event defaults to the same level as the span generated by #[instrument]. By default, this will be TRACE, but if the span level is overridden, the event will be at the same level.

It’s also possible to override the level for the ret event independently:

#[instrument(ret(level = Level::WARN))]
fn my_function() -> i32 {
    42
}

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, adding err or err(Display) will emit error events when the function returns Err:

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

The level of the error value event defaults to ERROR.

Similarly, overriding the level of the err event :

#[instrument(err(level = Level::INFO))]
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(())
}

If a target is specified, both the ret and err arguments will emit outputs to the declared target (or the default channel if target is not specified).

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

const fn cannot be instrumented, and will result in a compilation failure:

#[instrument]
const fn my_const_function() {}