Attribute Macro snafu::report

source ·
#[report]
Expand description

Adapts a function to provide user-friendly error output for main functions and tests.

use snafu::prelude::*;

#[snafu::report]
fn main() -> Result<()> {
    let _v = frobnicate_the_mumbletypeg()?;

    Ok(())
}

fn frobnicate_the_mumbletypeg() -> Result<u8> {
    api::contact_frobnicate_api().context(FrobnicateSnafu)
}

#[derive(Debug, Snafu)]
#[snafu(display("Unable to frobnicate the mumbletypeg"))]
struct FrobnicateError {
    source: api::ContactFrobnicateApiError,
}

type Result<T, E = FrobnicateError> = std::result::Result<T, E>;

mod api {
    use crate::config;
    use snafu::prelude::*;

    pub fn contact_frobnicate_api() -> Result<u8> {
        config::load_password().context(ContactFrobnicateApiSnafu)
    }

    #[derive(Debug, Snafu)]
    #[snafu(display("Could not contact the mumbletypeg API"))]
    pub struct ContactFrobnicateApiError {
        source: crate::config::MissingPasswordError,
    }

    pub type Result<T, E = ContactFrobnicateApiError> = std::result::Result<T, E>;
}

mod config {
    use snafu::prelude::*;

    pub fn load_password() -> Result<u8> {
        MissingPasswordSnafu.fail()
    }

    #[derive(Debug, Snafu)]
    #[snafu(display("The configuration has no password"))]
    pub struct MissingPasswordError {
        backtrace: snafu::Backtrace,
    }

    pub type Result<T, E = MissingPasswordError> = std::result::Result<T, E>;
}

When using #[snafu::report], the output of running this program may look like (backtrace edited for clarity and brevity):

Error: Unable to frobnicate the mumbletypeg

Caused by these errors (recent errors listed first):
  1: Could not contact the mumbletypeg API
  2: The configuration has no password

Backtrace:
   [... output edited ...]
   3: <std::backtrace::Backtrace as snafu::GenerateImplicitData>::generate
             at crates/snafu/src/lib.rs:1210:9
   4: backtrace_example::config::MissingPasswordSnafu::build
             at ./src/main.rs:48:21
   5: backtrace_example::config::MissingPasswordSnafu::fail
             at ./src/main.rs:48:21
   6: backtrace_example::config::load_password
             at ./src/main.rs:45:9
   7: backtrace_example::api::contact_frobnicate_api
             at ./src/main.rs:29:9
   8: backtrace_example::frobnicate_the_mumbletypeg
             at ./src/main.rs:13:5
   9: backtrace_example::main::{{closure}}
             at ./src/main.rs:7:14
  10: backtrace_example::main
             at ./src/main.rs:5:1
   [... output edited ...]

Contrast this to the default output produced when returning a Result:

Error: FrobnicateError { source: ContactFrobnicateApiError { source: MissingPasswordError { backtrace: Backtrace [...2000+ bytes of backtrace...] } } }

This macro is syntax sugar for using Report; please read its documentation for detailed information, especially if you wish to see backtraces in the output.

§Usage with other procedural macros

This macro should work with other common procedural macros. It has been tested with

  • tokio::main
  • tokio::test
  • async_std::main
  • async_std::test

Depending on the implementation details of each procedural macro, you may need to experiment by placing snafu::report before or after other macro invocations.