1use crate::{
2 config::BacktraceFormatter,
3 section::help::HelpInfo,
4 writers::{EnvSection, WriterExt},
5 Handler,
6};
7use backtrace::Backtrace;
8use indenter::{indented, Format};
9use std::fmt::Write;
10#[cfg(feature = "capture-spantrace")]
11use tracing_error::{ExtractSpanTrace, SpanTrace};
12
13impl std::fmt::Debug for Handler {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 f.write_str(data:"redacted")
16 }
17}
18
19impl Handler {
20 /// Return a reference to the captured `Backtrace` type
21 pub fn backtrace(&self) -> Option<&Backtrace> {
22 self.backtrace.as_ref()
23 }
24
25 /// Return a reference to the captured `SpanTrace` type
26 #[cfg(feature = "capture-spantrace")]
27 #[cfg_attr(docsrs, doc(cfg(feature = "capture-spantrace")))]
28 pub fn span_trace(&self) -> Option<&SpanTrace> {
29 self.span_trace.as_ref()
30 }
31
32 pub(crate) fn format_backtrace<'a>(
33 &'a self,
34 trace: &'a backtrace::Backtrace,
35 ) -> BacktraceFormatter<'a> {
36 BacktraceFormatter {
37 filters: &self.filters,
38 inner: trace,
39 theme: self.theme,
40 }
41 }
42}
43
44impl eyre::EyreHandler for Handler {
45 fn debug(
46 &self,
47 error: &(dyn std::error::Error + 'static),
48 f: &mut core::fmt::Formatter<'_>,
49 ) -> core::fmt::Result {
50 if f.alternate() {
51 return core::fmt::Debug::fmt(error, f);
52 }
53
54 #[cfg(feature = "capture-spantrace")]
55 let errors = || {
56 eyre::Chain::new(error)
57 .filter(|e| e.span_trace().is_none())
58 .enumerate()
59 };
60
61 #[cfg(not(feature = "capture-spantrace"))]
62 let errors = || eyre::Chain::new(error).enumerate();
63
64 for (n, error) in errors() {
65 writeln!(f)?;
66 write!(indented(f).ind(n), "{}", self.theme.error.style(error))?;
67 }
68
69 let mut separated = f.header("\n\n");
70
71 #[cfg(feature = "track-caller")]
72 if self.display_location_section {
73 write!(
74 separated.ready(),
75 "{}",
76 crate::SectionExt::header(
77 crate::fmt::LocationSection(self.location, self.theme),
78 "Location:"
79 )
80 )?;
81 }
82
83 for section in self
84 .sections
85 .iter()
86 .filter(|s| matches!(s, HelpInfo::Error(_, _)))
87 {
88 write!(separated.ready(), "{}", section)?;
89 }
90
91 for section in self
92 .sections
93 .iter()
94 .filter(|s| matches!(s, HelpInfo::Custom(_)))
95 {
96 write!(separated.ready(), "{}", section)?;
97 }
98
99 #[cfg(feature = "capture-spantrace")]
100 let span_trace = self
101 .span_trace
102 .as_ref()
103 .or_else(|| get_deepest_spantrace(error));
104
105 #[cfg(feature = "capture-spantrace")]
106 {
107 if let Some(span_trace) = span_trace {
108 write!(
109 &mut separated.ready(),
110 "{}",
111 crate::writers::FormattedSpanTrace(span_trace)
112 )?;
113 }
114 }
115
116 if let Some(backtrace) = self.backtrace.as_ref() {
117 let fmted_bt = self.format_backtrace(backtrace);
118
119 write!(
120 indented(&mut separated.ready()).with_format(Format::Uniform { indentation: " " }),
121 "{}",
122 fmted_bt
123 )?;
124 }
125
126 let f = separated.ready();
127 let mut h = f.header("\n");
128 let mut f = h.in_progress();
129
130 for section in self
131 .sections
132 .iter()
133 .filter(|s| !matches!(s, HelpInfo::Custom(_) | HelpInfo::Error(_, _)))
134 {
135 write!(&mut f, "{}", section)?;
136 f = h.ready();
137 }
138
139 if self.display_env_section {
140 let env_section = EnvSection {
141 bt_captured: &self.backtrace.is_some(),
142 #[cfg(feature = "capture-spantrace")]
143 span_trace,
144 };
145
146 write!(&mut separated.ready(), "{}", env_section)?;
147 }
148
149 #[cfg(feature = "issue-url")]
150 if self.issue_url.is_some() && (*self.issue_filter)(crate::ErrorKind::Recoverable(error)) {
151 let url = self.issue_url.as_ref().unwrap();
152 let mut payload = String::from("Error: ");
153 for (n, error) in errors() {
154 writeln!(&mut payload)?;
155 write!(indented(&mut payload).ind(n), "{}", error)?;
156 }
157
158 let issue_section = crate::section::github::IssueSection::new(url, &payload)
159 .with_backtrace(self.backtrace.as_ref())
160 .with_metadata(&**self.issue_metadata);
161
162 #[cfg(feature = "capture-spantrace")]
163 let issue_section = issue_section.with_span_trace(span_trace);
164
165 write!(&mut separated.ready(), "{}", issue_section)?;
166 }
167
168 Ok(())
169 }
170
171 #[cfg(feature = "track-caller")]
172 fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {
173 self.location = Some(location);
174 }
175}
176
177#[cfg(feature = "capture-spantrace")]
178pub(crate) fn get_deepest_spantrace<'a>(
179 error: &'a (dyn std::error::Error + 'static),
180) -> Option<&'a SpanTrace> {
181 eyreimpl Iterator::Chain::new(head:error)
182 .rev()
183 .flat_map(|error: &dyn Error| error.span_trace())
184 .next()
185}
186