Skip to content

Commit

Permalink
feat: allow personalizing the panic message
Browse files Browse the repository at this point in the history
Make setup_panic accept a function as a parameter, that will be called
to write the message. This function receives a Write reference, an
optional Path and the Metadata. If no function is provided, use the
original function "write_msg"
  • Loading branch information
saulvaldelvira committed Jan 4, 2025
1 parent 343f1c0 commit 89e7986
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 13 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
members = [
"tests/single-panic",
"tests/custom-panic",
"tests/custom-message",
]
resolver = "2"

Expand Down
35 changes: 22 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ use std::path::{Path, PathBuf};
///
/// See [`metadata!`]
pub struct Metadata {
name: Cow<'static, str>,
version: Cow<'static, str>,
authors: Option<Cow<'static, str>>,
homepage: Option<Cow<'static, str>>,
support: Option<Cow<'static, str>>,
pub name: Cow<'static, str>,
pub version: Cow<'static, str>,
pub authors: Option<Cow<'static, str>>,
pub homepage: Option<Cow<'static, str>>,
pub support: Option<Cow<'static, str>>,
}

impl Metadata {
Expand Down Expand Up @@ -140,16 +140,22 @@ macro_rules! metadata {
#[macro_export]
macro_rules! setup_panic {
($meta:expr) => {{
$crate::setup_panic(|| $meta);
$crate::setup_panic(|| $meta, None);
}};

($meta:expr, $print_fn:expr) => {{
$crate::setup_panic(|| $meta, Some($print_fn));
}};

() => {
$crate::setup_panic!($crate::metadata!());
$crate::setup_panic(|| $crate::metadata!(), None);
};
}

pub type WriteFunc = fn (&mut dyn std::io::Write, Option<&Path>, &Metadata) -> IoResult<()>;

#[doc(hidden)]
pub fn setup_panic(meta: impl Fn() -> Metadata) {
pub fn setup_panic(meta: impl Fn() -> Metadata, write_func: Option<WriteFunc>) {
#![allow(deprecated)]

#[allow(unused_imports)]
Expand All @@ -162,7 +168,8 @@ pub fn setup_panic(meta: impl Fn() -> Metadata) {

panic::set_hook(Box::new(move |info: &PanicInfo<'_>| {
let file_path = handle_dump(&meta, info);
print_msg(file_path, &meta)
let write_func = write_func.unwrap_or(|mut buf,fp,meta| write_msg(&mut buf,fp,meta));
print_msg(file_path, &meta, write_func)
.expect("human-panic: printing error message to console failed");
}));
}
Expand Down Expand Up @@ -194,25 +201,27 @@ impl Default for PanicStyle {

/// Utility function that prints a message to our human users
#[cfg(feature = "color")]
pub fn print_msg<P: AsRef<Path>>(file_path: Option<P>, meta: &Metadata) -> IoResult<()> {
pub fn print_msg<P: AsRef<Path>>(file_path: Option<P>, meta: &Metadata, write_func: WriteFunc) -> IoResult<()> {
use std::io::Write as _;

let stderr = anstream::stderr();
let mut stderr = stderr.lock();

write!(stderr, "{}", anstyle::AnsiColor::Red.render_fg())?;
write_msg(&mut stderr, file_path, meta)?;
let fp = file_path.as_ref().map(|fp| fp.as_ref());
write_func(&mut stderr, fp, meta)?;
write!(stderr, "{}", anstyle::Reset.render())?;

Ok(())
}

#[cfg(not(feature = "color"))]
pub fn print_msg<P: AsRef<Path>>(file_path: Option<P>, meta: &Metadata) -> IoResult<()> {
pub fn print_msg<P: AsRef<Path>>(file_path: Option<P>, meta: &Metadata, write_func: WriteFunc) -> IoResult<()> {
let stderr = std::io::stderr();
let mut stderr = stderr.lock();

write_msg(&mut stderr, file_path, meta)?;
let fp = file_path.as_ref().map(|fp| fp.as_ref());
write_func(&mut stderr, fp, meta)?;

Ok(())
}
Expand Down
15 changes: 15 additions & 0 deletions tests/custom-message/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "custom-message-test"
version = "0.1.0"
authors = ["Human Panic Authors <[email protected]>"]
edition.workspace = true
publish = false

[package.metadata.release]
release = false

[dependencies]
human-panic = { path = "../.." }

[dev-dependencies]
snapbox = { version = "0.6.4", features = ["cmd"] }
46 changes: 46 additions & 0 deletions tests/custom-message/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use std::path::Path;

use human_panic::metadata;
use human_panic::Metadata;
use human_panic::setup_panic;

fn custom_message(
buf: &mut dyn std::io::Write,
path: Option<&Path>,
meta: &Metadata
) -> std::io::Result<()> {
let Metadata {
name,
homepage,
..
} = meta;

writeln!(buf, "A fatal error ocurred!")?;
writeln!(buf,"{name} is DEAD :(")?;
writeln!(
buf,
"You can see details at \"{}\".",
match path {
Some(fp) => format!("{}", fp.display()),
None => "<Failed to store file to disk>".to_owned(),
},
)?;

if let Some(homepage) = homepage {
writeln!(buf, "\nShare your condolences: {homepage}")?;
}

Ok(())
}

fn main() {
setup_panic!(
metadata!()
.authors("My Company Support <[email protected]>")
.homepage("www.mycompany.com")
.support("- Open a support request by email to [email protected]"),
custom_message);

println!("A normal log message");
panic!("OMG EVERYTHING IS ON FIRE!!!");
}
29 changes: 29 additions & 0 deletions tests/custom-message/tests/integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#[test]
#[cfg_attr(debug_assertions, ignore)]
fn release() {
snapbox::cmd::Command::new(snapbox::cmd::cargo_bin!("custom-message-test"))
.assert()
.stderr_eq(snapbox::str![[r#"
A fatal error ocurred!
custom-message-test is DEAD :(
You can see details at [..].
Share your condolences: www.mycompany.com
"#]])
.code(101);
}

#[test]
#[cfg_attr(not(debug_assertions), ignore)]
fn debug() {
snapbox::cmd::Command::new(snapbox::cmd::cargo_bin!("custom-message-test"))
.assert()
.stderr_eq(snapbox::str![[r#"
thread 'main' panicked at tests/custom-message/src/main.rs:45:5:
OMG EVERYTHING IS ON FIRE!!!
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
"#]])
.code(101);
}

0 comments on commit 89e7986

Please sign in to comment.