Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: reversed stacktraces #187

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

39 changes: 33 additions & 6 deletions color-eyre/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ pub struct HookBuilder {
filters: Vec<Box<FilterCallback>>,
capture_span_trace_by_default: bool,
display_env_section: bool,
reversed_stacktrace: bool,
#[cfg(feature = "track-caller")]
display_location_section: bool,
panic_section: Option<Box<dyn Display + Send + Sync + 'static>>,
Expand Down Expand Up @@ -430,6 +431,7 @@ impl HookBuilder {
filters: vec![],
capture_span_trace_by_default: false,
display_env_section: true,
reversed_stacktrace: false,
#[cfg(feature = "track-caller")]
display_location_section: true,
panic_section: None,
Expand Down Expand Up @@ -616,12 +618,18 @@ impl HookBuilder {
self
}

/// Configures the enviroment varible info section and whether or not it is displayed
/// Configures the environment variable info section and whether or not it is displayed
pub fn display_env_section(mut self, cond: bool) -> Self {
self.display_env_section = cond;
self
}

/// Configures the whether or not the stacktrace frame order is reversed
pub fn reversed_stacktrace(mut self, cond: bool) -> Self {
self.reversed_stacktrace = cond;
self
}

/// Configures the location info section and whether or not it is displayed.
///
/// # Notes
Expand Down Expand Up @@ -697,6 +705,7 @@ impl HookBuilder {
#[cfg(feature = "capture-spantrace")]
capture_span_trace_by_default: self.capture_span_trace_by_default,
display_env_section: self.display_env_section,
reversed_stacktrace: self.reversed_stacktrace,
panic_message: self
.panic_message
.unwrap_or_else(|| Box::new(DefaultPanicMessage(theme))),
Expand All @@ -714,6 +723,7 @@ impl HookBuilder {
#[cfg(feature = "capture-spantrace")]
capture_span_trace_by_default: self.capture_span_trace_by_default,
display_env_section: self.display_env_section,
reversed_stacktrace: self.reversed_stacktrace,
#[cfg(feature = "track-caller")]
display_location_section: self.display_location_section,
theme,
Expand Down Expand Up @@ -914,6 +924,7 @@ pub struct PanicHook {
#[cfg(feature = "capture-spantrace")]
capture_span_trace_by_default: bool,
display_env_section: bool,
reversed_stacktrace: bool,
#[cfg(feature = "issue-url")]
issue_url: Option<String>,
#[cfg(feature = "issue-url")]
Expand All @@ -931,6 +942,7 @@ impl PanicHook {
filters: &self.filters,
inner: trace,
theme: self.theme,
reversed_stacktrace: self.reversed_stacktrace,
}
}

Expand Down Expand Up @@ -993,6 +1005,7 @@ pub struct EyreHook {
#[cfg(feature = "capture-spantrace")]
capture_span_trace_by_default: bool,
display_env_section: bool,
reversed_stacktrace: bool,
#[cfg(feature = "track-caller")]
display_location_section: bool,
theme: Theme,
Expand Down Expand Up @@ -1037,6 +1050,7 @@ impl EyreHook {
span_trace,
sections: Vec::new(),
display_env_section: self.display_env_section,
reversed_stacktrace: self.reversed_stacktrace,
#[cfg(feature = "track-caller")]
display_location_section: self.display_location_section,
#[cfg(feature = "issue-url")]
Expand Down Expand Up @@ -1073,6 +1087,7 @@ pub(crate) struct BacktraceFormatter<'a> {
pub(crate) filters: &'a [Box<FilterCallback>],
pub(crate) inner: &'a backtrace::Backtrace,
pub(crate) theme: Theme,
pub(crate) reversed_stacktrace: bool,
}

impl fmt::Display for BacktraceFormatter<'_> {
Expand Down Expand Up @@ -1114,6 +1129,10 @@ impl fmt::Display for BacktraceFormatter<'_> {
// Don't let filters mess with the order.
filtered_frames.sort_by_key(|x| x.n);

if self.reversed_stacktrace {
filtered_frames.reverse();
}

let mut buf = String::new();

macro_rules! print_hidden {
Expand All @@ -1136,9 +1155,13 @@ impl fmt::Display for BacktraceFormatter<'_> {
};
}

let mut last_n = 0;
let mut last_n = if self.reversed_stacktrace {
frames.last().unwrap().n
} else {
0
};
for frame in &filtered_frames {
let frame_delta = frame.n - last_n - 1;
let frame_delta = frame.n.abs_diff(last_n) - 1;
if frame_delta != 0 {
print_hidden!(frame_delta);
}
Expand All @@ -1147,9 +1170,13 @@ impl fmt::Display for BacktraceFormatter<'_> {
}

let last_filtered_n = filtered_frames.last().unwrap().n;
let last_unfiltered_n = frames.last().unwrap().n;
if last_filtered_n < last_unfiltered_n {
print_hidden!(last_unfiltered_n - last_filtered_n);
let last_unfiltered_n = if self.reversed_stacktrace {
0
} else {
frames.last().unwrap().n
};
if last_filtered_n != last_unfiltered_n {
print_hidden!(last_unfiltered_n.abs_diff(last_filtered_n));
}

Ok(())
Expand Down
1 change: 1 addition & 0 deletions color-eyre/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ impl Handler {
filters: &self.filters,
inner: trace,
theme: self.theme,
reversed_stacktrace: self.reversed_stacktrace,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions color-eyre/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ pub struct Handler {
display_env_section: bool,
#[cfg(feature = "track-caller")]
display_location_section: bool,
reversed_stacktrace: bool,
#[cfg(feature = "issue-url")]
issue_url: Option<String>,
#[cfg(feature = "issue-url")]
Expand Down
48 changes: 48 additions & 0 deletions color-eyre/tests/stacktrace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use color_eyre::eyre;
use eyre::eyre;

fn foo5() -> eyre::Report {
foo4()
}
fn foo4() -> eyre::Report {
foo3()
}
fn foo3() -> eyre::Report {
foo2()
}
fn foo2() -> eyre::Report {
foo1()
}
fn foo1() -> eyre::Report {
eyre::eyre!("error occured")
}

#[test]
fn stacktrace_forward() {
color_eyre::config::HookBuilder::default()
.display_env_section(true)
.reversed_stacktrace(false)
.install()
.unwrap();

let report = foo5();

let report = format!("{:?}", report);
println!("{}", report);
assert!(report.contains("RUST_BACKTRACE"));
}

#[test]
fn stacktrace_reversed() {
color_eyre::config::HookBuilder::default()
.display_env_section(true)
.reversed_stacktrace(true)
.install()
.unwrap();

let report = foo5();

let report = format!("{:?}", report);
println!("{}", report);
assert!(report.contains("RUST_BACKTRACE"));
}