Skip to main content

veilid_tools/
trim_backtrace.rs

1use super::*;
2
3pub struct TrimmedBacktrace {
4    backtrace: backtrace::Backtrace,
5}
6
7impl TrimmedBacktrace {
8    #[must_use]
9    pub fn new(mut backtrace: backtrace::Backtrace) -> Self {
10        backtrace.resolve();
11        Self { backtrace }
12    }
13
14    #[must_use]
15    pub fn backtrace(&self) -> &backtrace::Backtrace {
16        &self.backtrace
17    }
18
19    #[must_use]
20    pub fn backtrace_mut(&mut self) -> &mut backtrace::Backtrace {
21        &mut self.backtrace
22    }
23
24    fn format_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        let cwd = std::env::current_dir();
26        let mut print_path =
27            move |f: &mut fmt::Formatter<'_>, path: backtrace::BytesOrWideString<'_>| {
28                let path = path.into_path_buf();
29                if let Ok(cwd) = &cwd {
30                    if let Ok(suffix) = path.strip_prefix(cwd) {
31                        return fmt::Display::fmt(&suffix.display(), f);
32                    }
33                }
34                fmt::Display::fmt(&path.display(), f)
35            };
36
37        let mut f = backtrace::BacktraceFmt::new(f, backtrace::PrintFmt::Short, &mut print_path);
38        f.add_context()?;
39        'frame_loop: for frame in self.backtrace.frames() {
40            let mut frame_fmt = f.frame();
41
42            let symbols = frame.symbols();
43            for symbol in symbols {
44                let symbol_name = symbol.name().map(|x| x.to_string()).unwrap_or_default();
45
46                // Trim: Don't print lines with certain symbols
47                if symbol_name.starts_with("backtrace::")
48                    || symbol_name.starts_with("veilid_tools::async_locks::")
49                    || symbol_name.starts_with("<tracing::instrument::Instrumented")
50                    || symbol_name.starts_with("<core::pin::Pin<")
51                    || symbol_name.starts_with("<core::panic::")
52                    || symbol_name.starts_with("tokio::runtime::")
53                    || symbol_name.starts_with("tokio::loom::")
54                    || symbol_name.starts_with("std::panicking::")
55                    || symbol_name.starts_with("std::panic::")
56                {
57                    continue 'frame_loop;
58                }
59
60                // Trim: Stop the backtrace at the first rust try/unwind frame
61                if symbol_name.starts_with("___rust_try") {
62                    break 'frame_loop;
63                }
64
65                frame_fmt.backtrace_symbol(frame, symbol)?;
66            }
67            if symbols.is_empty() {
68                // Trim: don't print raw frames
69                // frame_fmt.print_raw(frame.ip(), None, None, None)?;
70            }
71        }
72        f.finish()?;
73        Ok(())
74    }
75}
76
77impl core::ops::Deref for TrimmedBacktrace {
78    type Target = backtrace::Backtrace;
79
80    fn deref(&self) -> &Self::Target {
81        self.backtrace()
82    }
83}
84
85impl core::ops::DerefMut for TrimmedBacktrace {
86    fn deref_mut(&mut self) -> &mut Self::Target {
87        self.backtrace_mut()
88    }
89}
90
91pub trait TrimBacktraceTrait {
92    fn trim(&self) -> TrimmedBacktrace;
93}
94
95impl TrimBacktraceTrait for backtrace::Backtrace {
96    fn trim(&self) -> TrimmedBacktrace {
97        TrimmedBacktrace::new(self.clone())
98    }
99}
100
101impl From<TrimmedBacktrace> for backtrace::Backtrace {
102    fn from(value: TrimmedBacktrace) -> Self {
103        value.backtrace
104    }
105}
106
107impl fmt::Display for TrimmedBacktrace {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        self.format_display(f)
110    }
111}
112
113impl fmt::Debug for TrimmedBacktrace {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        self.backtrace.fmt(f)
116    }
117}