1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
use std::fmt::{Display, Formatter};
use anyhow::{Result, anyhow};
const HIDDEN_PACKAGES: &[&str] = &[
"backtrace",
"anyhow",
"core",
"alloc",
"std",
"test",
"tokio",
"futures",
"futures_util",
];
fn nested2() -> Result<()> {
Err(anyhow!("Not implemented"))
}
pub fn nested1() -> Result<()> {
nested2()
}
struct DecodedFrame {
raw_line1: String,
raw_line2: String,
}
pub struct DecodedUserBacktrace {
frames: Vec<DecodedFrame>,
}
impl Display for DecodedUserBacktrace {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for frame in &self.frames {
writeln!(f, "{}", frame.raw_line1)?;
writeln!(f, "{}", frame.raw_line2)?;
}
Ok(())
}
}
fn decode_backtrace<Backtrace: Display>(b: &Backtrace, hide_packages: &[&str]) -> DecodedUserBacktrace {
let s = format!("{}", b);
let mut lines = s.lines();
let mut frames = Vec::new();
while let Some(line1) = lines.next() {
let frame = &line1[6..];
if frame.starts_with("__") {
continue
}
let line2 = lines.next().unwrap();
if frame.starts_with('<') {
let package1 = frame[1..].splitn(2, "::").next().unwrap();
let package2 = frame.splitn(2, " as ").skip(1).next().unwrap().splitn(2, "::").next().unwrap();
if hide_packages.contains(&package1) && hide_packages.contains(&package2) {
continue;
}
} else {
let package = frame.splitn(2, "::").next().unwrap();
if hide_packages.contains(&package) {
continue;
}
};
frames.push(DecodedFrame {
raw_line1: line1.to_string(),
raw_line2: line2.to_string(),
});
}
DecodedUserBacktrace { frames }
}
pub trait UserBacktrace {
fn user_backtrace(&self) -> DecodedUserBacktrace;
}
impl UserBacktrace for anyhow::Error {
fn user_backtrace(&self) -> DecodedUserBacktrace {
decode_backtrace(self.backtrace(), HIDDEN_PACKAGES)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_anyhow_err() {
let Err(e) = nested1() else { panic!("expected error"); };
let user_backtrace = format!("{}", e.user_backtrace());
assert_eq!(user_backtrace.lines().count(), 8);
}
}