Tracing fallible functions
The ok_lvl
and err_lvl
control parameters can be applied to span macros to assign a level based on whether the annotated function returned Ok
or Err
:
#![allow(unused)] fn main() { extern crate emit; #[emit::span( ok_lvl: emit::Level::Info, err_lvl: emit::Level::Error, "wait a bit", sleep_ms, )] fn wait_a_bit(sleep_ms: u64) -> Result<(), std::io::Error> { if sleep_ms > 500 { return Err(std::io::Error::new(std::io::ErrorKind::Other, "the wait is too long")); } std::thread::sleep(std::time::Duration::from_millis(sleep_ms)); Ok(()) } let _ = wait_a_bit(100); let _ = wait_a_bit(1200); }
Event {
mdl: "my_app",
tpl: "wait a bit",
extent: Some(
"2024-06-12T21:43:03.556361000Z".."2024-06-12T21:43:03.661164000Z",
),
props: {
"lvl": info,
"evt_kind": span,
"span_name": "wait a bit",
"trace_id": 6a3fc0e46bfa1da71537e39e3bf1942c,
"span_id": f5bcc5821c6c3227,
"sleep_ms": 100,
},
}
Event {
mdl: "my_app",
tpl: "wait a bit",
extent: Some(
"2024-06-12T21:43:03.661850000Z".."2024-06-12T21:43:03.661986000Z",
),
props: {
"lvl": error,
"err": Custom {
kind: Other,
error: "the wait is too long",
},
"evt_kind": span,
"span_name": "wait a bit",
"trace_id": 3226b70b45ff90f92f4feccee4325d4d,
"span_id": 3702ba2429f9a7b7,
"sleep_ms": 1200,
},
}
Mapping error types
Attaching errors to spans requires they're either &str
, &(dyn std::error::Error + 'static)
, or impl std::error::Error
. Error types like anyhow::Error
don't satisfy these requirements so need to be mapped.
The err
control parameter can be used to map the error type of a fallible span into one that can be captured:
#![allow(unused)] fn main() { extern crate emit; extern crate anyhow; #[emit::span( ok_lvl: emit::Level::Info, err: anyhow_err, "wait a bit", sleep_ms, )] fn wait_a_bit(sleep_ms: u64) -> Result<(), anyhow::Error> { if sleep_ms > 500 { return Err(anyhow::Error::msg("the wait is too long")); } std::thread::sleep(std::time::Duration::from_millis(sleep_ms)); Ok(()) } fn anyhow_err(err: &anyhow::Error) -> &(dyn std::error::Error + 'static) { err.as_ref() } let _ = wait_a_bit(100); let _ = wait_a_bit(1200); }
The err
control parameter accepts an expression that implements Fn(&E) -> U
, which can either be provided as a closure inline, or as an external function like anyhow_err
in the above example.
If your error type can't be mapped, you can also fall back to just providing a static string description as the error value:
#![allow(unused)] fn main() { extern crate emit; #[emit::span( ok_lvl: emit::Level::Info, err: (|_| "wait a bit failed"), "wait a bit", sleep_ms, )] fn wait_a_bit(sleep_ms: u64) -> Result<(), ()> { if sleep_ms > 500 { return Err(()); } std::thread::sleep(std::time::Duration::from_millis(sleep_ms)); Ok(()) } let _ = wait_a_bit(100); let _ = wait_a_bit(1200); }