shepmaster / snafu

Easily assign underlying errors into domain-specific errors while adding context
https://docs.rs/snafu/
Apache License 2.0
1.39k stars 60 forks source link

Is it possible to automatically include fields in error's display? #404

Closed MichaelScofield closed 7 months ago

MichaelScofield commented 1 year ago

Found a similar question in stackoverflow: https://stackoverflow.com/questions/76903644/is-it-possible-to-automatically-add-location-to-snafu-display

Basically, I'd like to have something to let me include the "location" (or other commonly used information like "user_id" or "request_id") in the error's display, without explicitly write it everytime.

For example, without this feature, I have to include "location" manually in #[snafu(display)]:

#[derive(Debug, Snafu)]
enum MyError {
    #[snafu(display("Foo, blabla: {err_msg}, at {location}")]
    Foo {
        err_msg: String,
        location: Location,
    }
}

With it, snafu automatically include it for me:

#[derive(Debug, Snafu)]
enum MyError {
    #[snafu(display("Foo, blabla: {err_msg}")]
    Foo {
        err_msg: String,

        #[snafu(extend_display)] // <-- If a field is annotated with this attribute, it will be automatically included in the display.
        location: Location,
    }
}

If this feature request sounds good to you, I'd like be working on this issue. Thx!

shepmaster commented 1 year ago

At first glance, this doesn't feel like a good fit. Some points:

One partial alternative that you could do today would be to create your own Location type that wraps snafu::Locationand implement Display to output the , at part in addition to the inner location information. Then your attribute would be just #[snafu(display("Foo, blabla: {err_msg}{location}")]

Happy for you to correct any misunderstandings I have!

MichaelScofield commented 1 year ago

@shepmaster thx, that make sense. Then is it possible to display the whole error that automatically include all of its fields? For example:

#[derive(Debug, Snafu)]
enum MyError {
    #[snafu(display)] // <-- If this "display" has no "()", then snafu will automatically make the "Foo { .. }" "to_string"ed.
    Foo {
        err_msg: String,
        location: Location,
    }
}

If the Foo is annotated with #[snafu(display)], but without a display format, then snafu could automatically make the Foo implemented std::fmt::Display and the display of Foo is something with predefined format like "Foo, err_msg: {err_msg}, location: {location}".