attributes: support recording error as std::error::Error
#3057
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivation
While
tracing::event!
macro accepts a value that implementsstd::error::Error
trait (that is,tracing::Value
trait is implemented fordyn std::error::Error
), there is no way to achieve the same thing when a function annotated with#[tracing::instrument]
returns an error which implementsstd::error::Error
; all we can do using the instrument attribute macro is something equivalent to either:event!(error = %e)
(corresponds toerr
orerr(Display)
)event!(error = ?e)
(corresponds toerr(Debug)
)The lack of support of recording errors as
std::error::Error
becomes more apparent especially when we want to integrate them with OpenTelemetry. The tracing-opentelemetry crate provides a bridge layer, where it generates OTel's event that the chain of error causes based on a passed value implementingstd::error::Error
in accordance with Semantic Conventions for Exceptions on Spans. It would be really helpful in troubleshooting an error if its virtual stack trace was recorded and viewable in OTel-compatible tracing platform.Solution
Added a new notation
err(StdError)
to theinstrument
attribute macro. This works in a very similar way to the existingerr(Display)
orerr(Debug)
, with a difference that the returned error is converted into&dyn std::error::Error
before being passed to theevent!
macro.Consideration
It is very usual especially in application layer (as opposed to library layer) that error types are represented as the one provided by third party crates such as
anyhow
oreyre
. Since the error types provided by them don't implementstd::error::Error
, we won't be able to useerr(StdError)
if an instrumented function returns, for example,anyhow::Error
.To support these types, I think the most straightforward approach would be to introduce another notation like
err(AsRefStdError)
that calls.as_ref()
on the returned error before casting it into a trait object (note thatAsRef<dyn std::error::Error>
is implemented for third party error types). We could maybe revisit and consider how to deal with this case later.Ref
#2648 pointed out that the instrument macro is limited to recording errors using either
Display
orDebug
only, which doesn't really work well with OTel's semantic conventions on exceptions.