marker_error/
trace.rs

1use std::backtrace::{Backtrace, BacktraceStatus};
2use std::fmt;
3use tracing_error::SpanTrace;
4use yansi::Paint;
5
6/// Contains a verbose information useful for debugging. The developers
7/// will most likely want to see this when a panic happens in their code or
8/// an error is returned from a function where it shouldn't be returned.
9#[derive(Debug)]
10pub struct ErrorTrace {
11    spantrace: SpanTrace,
12    backtrace: Backtrace,
13}
14
15impl ErrorTrace {
16    pub fn capture() -> Self {
17        Self {
18            spantrace: SpanTrace::capture(),
19            backtrace: Backtrace::force_capture(),
20        }
21    }
22
23    fn write_trace(f: &mut fmt::Formatter<'_>, kind: &str, trace: &dyn fmt::Display) -> fmt::Result {
24        writeln!(f, "{}\n{trace}", format_args!("{kind}:").red().bold())
25    }
26}
27
28impl fmt::Display for ErrorTrace {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        let backtrace = &self.backtrace;
31
32        match backtrace.status() {
33            BacktraceStatus::Captured => Self::write_trace(f, "Backtrace", backtrace)?,
34            // This must never happen because we use `force_capture`, but let's
35            // be safe and not panic the second time in a row here if this ever breaks
36            BacktraceStatus::Disabled => writeln!(
37                f,
38                "{}",
39                "⚠️  Backtrace wasn't captured. This is probably a bug in our error \
40                trace capturing code."
41                    .red(),
42            )?,
43            BacktraceStatus::Unsupported => writeln!(f, "{}", "backtrace is unsupported".red())?,
44            _ => writeln!(f, "{}\n{backtrace}", "Backtrace is in unknown status:".red())?,
45        };
46
47        let spantrace = &self.spantrace;
48
49        match spantrace.status() {
50            tracing_error::SpanTraceStatus::CAPTURED => {
51                write!(f, "{}\n{spantrace}", "Spantrace:".red().bold())?;
52            },
53            tracing_error::SpanTraceStatus::EMPTY => {
54                write!(
55                    f,
56                    "{}. It may be expected if the error happened outside of \
57                    any spans, or those spans were not enabled. You may try \
58                    capturing it by enabling {} logging or increasing its level \
59                    via MARKER_LOG env variable in cargo-marker. Spantrace capturing \
60                    in marker_rustc_driver isn't supported yet.",
61                    "⚠️  Spantrace wasn't captured".yellow(),
62                    "tracing".bold()
63                )?;
64            },
65            tracing_error::SpanTraceStatus::UNSUPPORTED => f.write_str("spantrace is unsupported")?,
66        }
67
68        Ok(())
69    }
70}