Attribute Macro tracing::instrument [−][src]
#[instrument]
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:
- multiple argument names can be passed to
skip
. - arguments passed to
skip
do not need to implementfmt::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) { // ... }
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 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) {} }
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
).