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
/*!
Custom formatting for stack backtraces inteded to be printed to the console for developers.
*/

use core::fmt;

use backtrace::{Backtrace, BacktraceFmt, BacktraceFrame, PrintFmt, SymbolName};

/**
Formats backtraces for printing but omits unnecessary stack frames.

Customized version of `impl fmt::Debug` from the `Backtrace` crate.
*/
pub fn format_backtrace(backtrace: &Backtrace, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
    let cwd = std::env::current_dir().ok();
    let cwd_copy = cwd.clone();
    let mut print_path = move |fmt: &mut fmt::Formatter<'_>,
                               path: backtrace::BytesOrWideString<'_>| {
        let cwd_path_buf = path.into_path_buf();

        if let Some(cwd) = &cwd_copy {
            if let Ok(suffix) = cwd_path_buf.strip_prefix(cwd) {
                return fmt::Display::fmt(&suffix.display(), fmt);
            }
        }

        fmt::Display::fmt(&cwd_path_buf.display(), fmt)
    };

    let mut f = BacktraceFmt::new(fmt, PrintFmt::Short, &mut print_path);
    f.add_context()?;

    let mut skipped_n_frames = 0;
    let frames = backtrace.frames();
    // Skip 1 because our errors are always contructed with a constructor and we want the trace to start where the constructor was called.
    for frame in frames.iter().skip(1) {
        let frame_from_this_project = frame.symbols().iter().any(|symbol| {
            symbol
                .filename()
                .map(|path| {
                    if let Some(cwd) = cwd.clone() {
                        // If the path starts with the cwd, we assume it's from the current crate
                        path.starts_with(cwd)
                    } else {
                        false
                    }
                })
                .unwrap_or(false)
        });
        if !frame_from_this_project {
            skipped_n_frames += 1;
            continue;
        } else {
            if skipped_n_frames > 0 {
                print_filtered_frame_placeholder(skipped_n_frames, &mut f, frame)?;
            }
            skipped_n_frames = 0;
        }

        f.frame().backtrace_frame(frame)?;
    }
    if skipped_n_frames > 0 {
        // Just need some frame, taking the first one because the last one has a null adddress and those are not printed by default.
        if let Some(some_frame) = frames.first() {
            print_filtered_frame_placeholder(skipped_n_frames, &mut f, some_frame)?;
        }
    }

    f.finish()?;
    Ok(())
}

fn print_filtered_frame_placeholder(
    skipped_n_frames: i32,
    f: &mut BacktraceFmt,
    reference_frame: &BacktraceFrame,
) -> fmt::Result {
    let mut backtrace_frame_fmt = f.frame();
    let word = if skipped_n_frames == 1 {
        "frame"
    } else {
        "frames"
    };
    backtrace_frame_fmt.print_raw(
        // Using some frame ip to get the formatter to print.
        reference_frame.ip(),
        Some(SymbolName::new(
            format!("<----- {} filtered {} ----->", skipped_n_frames, word).as_bytes(),
        )),
        None,
        None,
    )?;
    Ok(())
}