Alternatives to panic!() and expect() for --release?

Viewed 740

In development, my code uses .expect() and panic!() to handle fatal errors.

Their behaviour is exactly what I need during development.

When I compile with --release, I was hoping that their output would become more succinct.

i.e. This code:

let mut file_a = OpenOptions::new().write(true)
                                   .read(true)
                                   .open(args.file_a).expect("foo bar");

generates:

thread 'main' panicked at 'foo bar: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/bin/vsapply.rs:131:59

When I would prefer just:

foo bar: No such file or directory

when compiled with --release.

Is there already a way of doing this?

2 Answers

Combination of std::panic::set_hook and #[cfg(debug_assertions)] soleves the problem.

use std::panic;

fn main() {
    #[cfg(not(debug_assertions))]
    panic::set_hook(Box::new(|panic_info| {
        if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
            println!("panic occurred: {:?}", s);
        } else {
            println!("panic occurred");
        }
    }));
    println!("Hello, world!");
    panic!("nyaan");
}

When exec cargo run, output is:

Hello, world!
thread 'main' panicked at 'nyaan', src\main.rs:14:5

When cargo run --release:

Hello, world!
panic occurred: "nyaan"

One option you have available to you is, rather than flatly panicking, instead printing information to stderr by using eprintln!() and exiting with a non-zero error code.

use std::process;

fn main() -> {
    // some terrible state
    eprintln!("foo bar: No such file or directory.");
    process::exit(1);
}

This has a couple of benefits:

  • Printing to stderr ensures that your error message isn't instead directed to some output file (e.g. foo --option arg1 arg2 > output.txt).
  • A program calling your program can interpret a non-zero error code as an indication of failure.
Related