pub fn error_field<E, TMarker>(error: &E) -> Box<dyn Value + '_>where
E: AsTracingValue<TMarker>,Expand description
Emit an error as a tracing event with its full source chain intact.
This utility provides a streamlined way to emit errors as tracing event fields
and their full source-chain without verbose conversion to &dyn std::error::Error
trait objects.
§Why this exists
To emit errors as fields in tracing events in the way tracing intended (that is,
via tracing::Value for dyn std::error::Error), one can either use
error = &error as &dyn std::error::Error for typed errors, or alternatively
error = AsRef::<std::error::Error::as_ref(&error) for dynamic errors such
eyre::Report. Both are verbose and not nice to use. Many users instead just reach
for the sigils % or ?. But % uses the Display formatting for a type,
skipping its source chain. And ? uses Debug, which can leak implementation details,
is hard to read, and can break formatting (in the case of eyre) – and its inconsistent.
The error_field utility allows treating both errors the same way, while making
use of the tracing machinery.
§Notes on the implementation
[tracing::Value] is implemented for E: dyn std::error::Error, but
actually using it requires a verbose error as &dyn std::error::Error
for types that actually implement that trait. Or worse,
AsRef::<dyn std::error::Error>::as_ref(&eyre_report) for eyre::Report,
which by itself does not implement the trait.
Right now the implementation requires an additional heap allocation of the type-erased error object. Because usually errors are not handled in the hot path of an application this should be an acceptable performance hit.
§Examples
use eyre::WrapErr;
use tempo_telemetry_util::error_field;
let read_error: Result<(), std::io::Error> = Err(std::io::ErrorKind::NotFound.into());
if let Err(error) = Err::<(), _>(std::io::Error::from(std::io::ErrorKind::NotFound))
.wrap_err("failed opening config")
.wrap_err("failed to start server")
{
tracing::error!(
error = error_field(&error),
);
}This will print (using the standard tracing_subscriber::fmt::init() formatting subscriber):
2025-08-08T14:38:17.541852Z ERROR tempo_telemetry_util: error=failed starting server error.sources=[failed opening config, entity not found]