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

feat: implement serialize for report #168

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

thewh1teagle
Copy link

@thewh1teagle thewh1teagle commented Apr 23, 2024

I use eyre with tauri. When returning a result from it, it requires that the error implements Serialize (as it returns it to the browser). So instead, I had to return std::result::Result<(), String> (which of course implements it) and map many errors to a string each time:

#[command]
fn hello() -> Result<(), String> {
  do_something().map_err(|e| e.to_string())?;
}

With this feature, I can now return an eyre result and propagate almost any error.

#[command]
fn hello() -> Result<()> {
  do_something()?;
}

@thewh1teagle
Copy link
Author

thewh1teagle commented Apr 29, 2024

Turns out that by default err.to_string() in eyre returns from fmt::Display, and it doesn't include the backtrace in the error string, and the final error string (which returns to the browser in tauri) is useless.

I'm thinking of a way to include the backtrace conditionally in the serializer from eyre,
What do you think about adding serialize_backtrace feature which will be used as:

use serde::{ser::Serializer, Serialize};
use crate::Report;

impl Serialize for Report {
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        if cfg!(feature = "serialize_backtrace") {
            serializer.serialize_str(format!("{:?}", self).as_ref()) // include backtrace
        } else {
            serializer.serialize_str(self.to_string().as_ref())
        }
    }
}

Copy link
Contributor

@ten3roberts ten3roberts left a comment

Choose a reason for hiding this comment

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

This is great, serialized errors is something I've made use of too (specifically in games where they are sent over the wire or scripting boundary)

However, do you think we could use a more structural serialization, such as

{ 
    "message": "Something failed",
    "caused_by": [ "A failed" ],
    "backtrace": [...]
}

Or similar?

This way, we would also support your aforementioned backtrace inclusion, among other data, and allow the error to be picked apart and displayed better on the other end.

What we could do to make it configurable is to add the serialization as a default method on the EyreHandler so that handler which capture backtraces can show it as well as other handler-specific data like tracing spans.

Example

trait EyreHandler {
    ...
    fn serialize(serializer: &mut dyn erased_serde::Serializer ) -> erased_serde::Result {
         ... default "good enough" serialization of message and causes
    }
}

@thewh1teagle
Copy link
Author

thewh1teagle commented May 2, 2024

Sounds even better.
I'm not sure how it can work with a custom handler (or how Eyre currently works with custom handlers).

Anyway, I think that should be another feature, and the default serializer should be just like the default error, with a backtrace (currently, the format in the PR doesn't include a stack trace).

@ten3roberts
Copy link
Contributor

Clippy is failing on master due to introducing additional lints in a new version, I'll fix it up, so don't worry about it.

@jsimonrichard
Copy link

This is great! I'm working on another tauri project, so this would be helpful.

Since color_eyre re-exports eyre, could you add serialize as a feature to that as well?

@MordechaiHadad
Copy link

Whats the status of this? would really appreciate this.

@LeoniePhiline
Copy link
Contributor

LeoniePhiline commented Jun 28, 2024

Whats the status of this? would really appreciate this.

There seems to be no consensus on the structural serialization format.

Serializing the Debug representation is easily done by crate users by implementing Serialize on a newtype wrapper.

The real interesting serialization would include information internal to eyre::Report, such as the error chain (backtrace) and stack trace for each error in the chain - where available.

It seems to be that this needs some more design work before we can settle on an implementation.

The serialization output would be part of the public API. Thus, if we serialize a Debug representation of the eyre::Report, we are bound to sticking with that.

@ten3roberts
Copy link
Contributor

Whats the status of this? would really appreciate this.

There seems to be no consensus on the structural serialization format.

Serializing the Debug representation is easily done by crate users by implementing Serialize on a newtype wrapper.

The real interesting serialization would include information internal to eyre::Report, such as the error chain (backtrace) and stack trace for each error in the chain - where available.

It seems to be that this needs some more design work before we can settle on an implementation.

The serialization output would be part of the public API. Thus, if we serialize a Debug representation of the eyre::Report, we are bound to sticking with that.

Exactly.

I think best approach would be to add serialization to the handler (I.e; color-eyre), because the handler is the one who knows about things like spans, backtrace, etc, and it may be different based on handler what information is available.

A new method to the Handler trait would with a default-noop impl would then be exposed to access this handler-specific serialization.

To start with, we can add it to color-eyre and see how a structural serialization fairs there (basically struct-like serde with spantrace, backtrace, and error chain) and go from there

@thewh1teagle
Copy link
Author

Would it be possible to add initial support for serialization first? This way, users won't need to implement their own types and deal with the overhead of getting serialization for errors. This PR has been pending for two months, and addressing this now would help reduce the waiting time for users. Once we have this minimal support in place, we can explore various improvements in future PRs/issues. Could you please clarify the benefits of waiting this long before merging?

@dionysuzx
Copy link

any update on this? would love this feature. thanks for your work on it.

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.

7 participants