Attribute Macro instrument
#[instrument]
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 implementfmt::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::TRACE
—Level::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 fn
s 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() {}