Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

attributes: support recording error as std::error::Error #3057

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

magurotuna
Copy link

@magurotuna magurotuna commented Aug 13, 2024

Motivation

While tracing::event! macro accepts a value that implements std::error::Error trait (that is, tracing::Value trait is implemented for dyn std::error::Error), there is no way to achieve the same thing when a function annotated with #[tracing::instrument] returns an error which implements std::error::Error; all we can do using the instrument attribute macro is something equivalent to either:

  • event!(error = %e) (corresponds to err or err(Display))
  • event!(error = ?e) (corresponds to err(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 implementing std::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 the instrument attribute macro. This works in a very similar way to the existing err(Display) or err(Debug), with a difference that the returned error is converted into &dyn std::error::Error before being passed to the event! 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 or eyre. Since the error types provided by them don't implement std::error::Error, we won't be able to use err(StdError) if an instrumented function returns, for example, anyhow::Error.

// This doesn't compile
#[tracing::instrument(err(StdError))]
fn foo() -> Result<(), anyhow::Error> {
    Ok(())
}

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 that AsRef<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 or Debug only, which doesn't really work well with OTel's semantic conventions on exceptions.

This commit adds a way of recording an error returned from the
instrumented function as `std::error::Error` instead of recording
description of the error stringified with `std::fmt::Display` or
`std::fmt::Debug`.

A new notation introduced to do that is `err(StdError)`. When this is
used, the returned error is converted into a trait object and then
passed to `tracing::event!` macro with its key set to `error` to
construct a tracing's event.

Refs: tokio-rs#2648
@magurotuna magurotuna requested review from hawkw, davidbarsky and a team as code owners August 13, 2024 15:32
Copy link
Contributor

@kaffarell kaffarell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glanced over the code and tested it quickly. Looks really good! IMO the AsRefStdError option is quite important as anyhow is really popular these days. This could be done in a follow-up PR though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants