mirror of
https://github.com/eyre-rs/eyre.git
synced 2025-10-02 07:21:36 +00:00
Add support for customized panic message sections (#57)
* (cargo-release) start next development iteration 0.5.3-alpha.0 * add support for customized panic messages * reorg a little * add example and changelog * reorder items in example * fix missing semi
This commit is contained in:
parent
17c325d38f
commit
ff84554ed4
@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
### Added
|
||||||
|
- add `panic_section` method to `HookBuilder` for overriding the printer for
|
||||||
|
the panic message at the start of panic reports
|
||||||
|
|
||||||
## [0.5.2] - 2020-08-31
|
## [0.5.2] - 2020-08-31
|
||||||
### Added
|
### Added
|
||||||
|
105
src/config.rs
105
src/config.rs
@ -1,6 +1,9 @@
|
|||||||
//! Configuration options for customizing the behavior of the provided panic
|
//! Configuration options for customizing the behavior of the provided panic
|
||||||
//! and error reporting hooks
|
//! and error reporting hooks
|
||||||
use crate::writers::{EnvSection, WriterExt};
|
use crate::{
|
||||||
|
section::PanicMessage,
|
||||||
|
writers::{EnvSection, WriterExt},
|
||||||
|
};
|
||||||
use fmt::Display;
|
use fmt::Display;
|
||||||
use indenter::{indented, Format};
|
use indenter::{indented, Format};
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
@ -246,6 +249,7 @@ pub struct HookBuilder {
|
|||||||
capture_span_trace_by_default: bool,
|
capture_span_trace_by_default: bool,
|
||||||
display_env_section: bool,
|
display_env_section: bool,
|
||||||
panic_section: Option<Box<dyn Display + Send + Sync + 'static>>,
|
panic_section: Option<Box<dyn Display + Send + Sync + 'static>>,
|
||||||
|
panic_message: Box<dyn PanicMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HookBuilder {
|
impl HookBuilder {
|
||||||
@ -279,6 +283,7 @@ impl HookBuilder {
|
|||||||
capture_span_trace_by_default: false,
|
capture_span_trace_by_default: false,
|
||||||
display_env_section: true,
|
display_env_section: true,
|
||||||
panic_section: None,
|
panic_section: None,
|
||||||
|
panic_message: Box::new(DefaultPanicMessage),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,6 +303,63 @@ impl HookBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Overrides the main error message printing section at the start of panic
|
||||||
|
/// reports
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use std::{panic::Location, fmt};
|
||||||
|
/// use color_eyre::section::PanicMessage;
|
||||||
|
/// use owo_colors::OwoColorize;
|
||||||
|
///
|
||||||
|
/// struct MyPanicMessage;
|
||||||
|
///
|
||||||
|
/// color_eyre::config::HookBuilder::default()
|
||||||
|
/// .panic_message(MyPanicMessage)
|
||||||
|
/// .install()
|
||||||
|
/// .unwrap();
|
||||||
|
///
|
||||||
|
/// impl PanicMessage for MyPanicMessage {
|
||||||
|
/// fn display(&self, pi: &std::panic::PanicInfo<'_>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
/// writeln!(f, "{}", "The application panicked (crashed).".red())?;
|
||||||
|
///
|
||||||
|
/// // Print panic message.
|
||||||
|
/// let payload = pi
|
||||||
|
/// .payload()
|
||||||
|
/// .downcast_ref::<String>()
|
||||||
|
/// .map(String::as_str)
|
||||||
|
/// .or_else(|| pi.payload().downcast_ref::<&str>().cloned())
|
||||||
|
/// .unwrap_or("<non string panic payload>");
|
||||||
|
///
|
||||||
|
/// write!(f, "Message: ")?;
|
||||||
|
/// writeln!(f, "{}", payload.cyan())?;
|
||||||
|
///
|
||||||
|
/// // If known, print panic location.
|
||||||
|
/// write!(f, "Location: ")?;
|
||||||
|
/// if let Some(loc) = pi.location() {
|
||||||
|
/// write!(f, "{}", loc.file().purple())?;
|
||||||
|
/// write!(f, ":")?;
|
||||||
|
/// write!(f, "{}", loc.line().purple())?;
|
||||||
|
///
|
||||||
|
/// write!(f, "\n\nConsider reporting the bug at {}", custom_url(loc, payload))?;
|
||||||
|
/// } else {
|
||||||
|
/// write!(f, "<unknown>")?;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Ok(())
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn custom_url(location: &Location<'_>, message: &str) -> impl fmt::Display {
|
||||||
|
/// "todo"
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn panic_message<S: PanicMessage>(mut self, section: S) -> Self {
|
||||||
|
self.panic_message = Box::new(section);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Configures the default capture mode for `SpanTraces` in error reports and panics
|
/// Configures the default capture mode for `SpanTraces` in error reports and panics
|
||||||
pub fn capture_span_trace_by_default(mut self, cond: bool) -> Self {
|
pub fn capture_span_trace_by_default(mut self, cond: bool) -> Self {
|
||||||
self.capture_span_trace_by_default = cond;
|
self.capture_span_trace_by_default = cond;
|
||||||
@ -367,6 +429,7 @@ impl HookBuilder {
|
|||||||
#[cfg(feature = "capture-spantrace")]
|
#[cfg(feature = "capture-spantrace")]
|
||||||
capture_span_trace_by_default: self.capture_span_trace_by_default,
|
capture_span_trace_by_default: self.capture_span_trace_by_default,
|
||||||
display_env_section: self.display_env_section,
|
display_env_section: self.display_env_section,
|
||||||
|
panic_message: self.panic_message,
|
||||||
};
|
};
|
||||||
|
|
||||||
let eyre_hook = EyreHook {
|
let eyre_hook = EyreHook {
|
||||||
@ -379,6 +442,7 @@ impl HookBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
impl Default for HookBuilder {
|
impl Default for HookBuilder {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
@ -433,12 +497,11 @@ fn install_panic_hook() {
|
|||||||
std::panic::set_hook(Box::new(|pi| eprintln!("{}", PanicPrinter(pi))))
|
std::panic::set_hook(Box::new(|pi| eprintln!("{}", PanicPrinter(pi))))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PanicMessage<'a>(&'a PanicPrinter<'a>);
|
struct DefaultPanicMessage;
|
||||||
|
|
||||||
impl fmt::Display for PanicMessage<'_> {
|
impl PanicMessage for DefaultPanicMessage {
|
||||||
fn fmt(&self, out: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn display(&self, pi: &std::panic::PanicInfo<'_>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let pi = (self.0).0;
|
writeln!(f, "{}", "The application panicked (crashed).".red())?;
|
||||||
writeln!(out, "{}", "The application panicked (crashed).".red())?;
|
|
||||||
|
|
||||||
// Print panic message.
|
// Print panic message.
|
||||||
let payload = pi
|
let payload = pi
|
||||||
@ -448,17 +511,17 @@ impl fmt::Display for PanicMessage<'_> {
|
|||||||
.or_else(|| pi.payload().downcast_ref::<&str>().cloned())
|
.or_else(|| pi.payload().downcast_ref::<&str>().cloned())
|
||||||
.unwrap_or("<non string panic payload>");
|
.unwrap_or("<non string panic payload>");
|
||||||
|
|
||||||
write!(out, "Message: ")?;
|
write!(f, "Message: ")?;
|
||||||
writeln!(out, "{}", payload.cyan())?;
|
writeln!(f, "{}", payload.cyan())?;
|
||||||
|
|
||||||
// If known, print panic location.
|
// If known, print panic location.
|
||||||
write!(out, "Location: ")?;
|
write!(f, "Location: ")?;
|
||||||
if let Some(loc) = pi.location() {
|
if let Some(loc) = pi.location() {
|
||||||
write!(out, "{}", loc.file().purple())?;
|
write!(f, "{}", loc.file().purple())?;
|
||||||
write!(out, ":")?;
|
write!(f, ":")?;
|
||||||
write!(out, "{}", loc.line().purple())?;
|
write!(f, "{}", loc.line().purple())?;
|
||||||
} else {
|
} else {
|
||||||
write!(out, "<unknown>")?;
|
write!(f, "<unknown>")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -466,14 +529,13 @@ impl fmt::Display for PanicMessage<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_panic_info(printer: &PanicPrinter<'_>, out: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn print_panic_info(printer: &PanicPrinter<'_>, out: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(out, "{}", PanicMessage(printer))?;
|
let hook = installed_hook();
|
||||||
|
hook.panic_message.display(printer.0, out)?;
|
||||||
|
|
||||||
let v = panic_verbosity();
|
let v = panic_verbosity();
|
||||||
|
|
||||||
let printer = installed_printer();
|
|
||||||
|
|
||||||
#[cfg(feature = "capture-spantrace")]
|
#[cfg(feature = "capture-spantrace")]
|
||||||
let span_trace = if printer.spantrace_capture_enabled() {
|
let span_trace = if hook.spantrace_capture_enabled() {
|
||||||
Some(tracing_error::SpanTrace::capture())
|
Some(tracing_error::SpanTrace::capture())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -481,7 +543,7 @@ fn print_panic_info(printer: &PanicPrinter<'_>, out: &mut fmt::Formatter<'_>) ->
|
|||||||
|
|
||||||
let mut separated = out.header("\n\n");
|
let mut separated = out.header("\n\n");
|
||||||
|
|
||||||
if let Some(ref section) = printer.section {
|
if let Some(ref section) = hook.section {
|
||||||
write!(&mut separated.ready(), "{}", section)?;
|
write!(&mut separated.ready(), "{}", section)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,7 +562,7 @@ fn print_panic_info(printer: &PanicPrinter<'_>, out: &mut fmt::Formatter<'_>) ->
|
|||||||
|
|
||||||
if capture_bt {
|
if capture_bt {
|
||||||
let bt = backtrace::Backtrace::new();
|
let bt = backtrace::Backtrace::new();
|
||||||
let fmted_bt = printer.format_backtrace(&bt);
|
let fmted_bt = hook.format_backtrace(&bt);
|
||||||
write!(
|
write!(
|
||||||
indented(&mut separated.ready()).with_format(Format::Uniform { indentation: " " }),
|
indented(&mut separated.ready()).with_format(Format::Uniform { indentation: " " }),
|
||||||
"{}",
|
"{}",
|
||||||
@ -508,7 +570,7 @@ fn print_panic_info(printer: &PanicPrinter<'_>, out: &mut fmt::Formatter<'_>) ->
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if printer.display_env_section {
|
if hook.display_env_section {
|
||||||
let env_section = EnvSection {
|
let env_section = EnvSection {
|
||||||
bt_captured: &capture_bt,
|
bt_captured: &capture_bt,
|
||||||
#[cfg(feature = "capture-spantrace")]
|
#[cfg(feature = "capture-spantrace")]
|
||||||
@ -524,6 +586,7 @@ fn print_panic_info(printer: &PanicPrinter<'_>, out: &mut fmt::Formatter<'_>) ->
|
|||||||
pub(crate) struct PanicHook {
|
pub(crate) struct PanicHook {
|
||||||
filters: Vec<Arc<FilterCallback>>,
|
filters: Vec<Arc<FilterCallback>>,
|
||||||
section: Option<Box<dyn Display + Send + Sync + 'static>>,
|
section: Option<Box<dyn Display + Send + Sync + 'static>>,
|
||||||
|
panic_message: Box<dyn PanicMessage>,
|
||||||
#[cfg(feature = "capture-spantrace")]
|
#[cfg(feature = "capture-spantrace")]
|
||||||
capture_span_trace_by_default: bool,
|
capture_span_trace_by_default: bool,
|
||||||
display_env_section: bool,
|
display_env_section: bool,
|
||||||
@ -671,7 +734,7 @@ impl fmt::Display for BacktraceFormatter<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn installed_printer() -> &'static PanicHook {
|
pub(crate) fn installed_hook() -> &'static PanicHook {
|
||||||
crate::CONFIG.get_or_init(default_printer)
|
crate::CONFIG.get_or_init(default_printer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::config::installed_printer;
|
use crate::config::installed_hook;
|
||||||
use crate::{
|
use crate::{
|
||||||
section::help::HelpInfo,
|
section::help::HelpInfo,
|
||||||
writers::{EnvSection, WriterExt},
|
writers::{EnvSection, WriterExt},
|
||||||
@ -86,7 +86,7 @@ impl eyre::EyreHandler for Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(backtrace) = self.backtrace.as_ref() {
|
if let Some(backtrace) = self.backtrace.as_ref() {
|
||||||
let fmted_bt = installed_printer().format_backtrace(&backtrace);
|
let fmted_bt = installed_hook().format_backtrace(&backtrace);
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
indented(&mut separated.ready()).with_format(Format::Uniform { indentation: " " }),
|
indented(&mut separated.ready()).with_format(Format::Uniform { indentation: " " }),
|
||||||
|
@ -314,3 +314,9 @@ pub trait Section: crate::private::Sealed {
|
|||||||
D: Display + Send + Sync + 'static,
|
D: Display + Send + Sync + 'static,
|
||||||
F: FnOnce() -> D;
|
F: FnOnce() -> D;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for printing a panic error message for the given PanicInfo
|
||||||
|
pub trait PanicMessage: Send + Sync + 'static {
|
||||||
|
/// Display trait equivalent for implementing the display logic
|
||||||
|
fn display(&self, pi: &std::panic::PanicInfo<'_>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user