charon_error/
panic_hook.rs1#[macro_export]
44macro_rules! setup_panic {
45 () => {
46 if ::std::env::var("RUST_BACKTRACE").is_err() {
49 #[allow(unused_imports)]
50 use charon_error::prelude::panic_hook::*;
51 #[allow(unused_imports)]
52 use std::panic::{self, PanicHookInfo};
53 #[allow(unused_imports)]
54 use std::ops::Deref;
55
56 #[cfg(debug_assertions)]
58 {
59 use charon_error::ResultExt;
60 let global_settings = ERGlobalSettings::get_or_default_settings().map(|gs| gs.deref().clone()).unwrap_or_default();
61 let test_error = StringError::new("").into();
62 let test_report = (global_settings.submit_error_reporter_fn)(&test_error);
63 if let Err(err) = test_report.validate_settings() {
64 let error = err.attach_public_string("triggered_from", "setup_panic!()".to_owned());
65 panic!("Failed to validate settings for Panic Error Reporter, \nmake sure they are set (correctly) for the current `ERGlobalSettings::submit_error_reporter_fn`:\n{error}");
66 }
67 }
68
69 panic::set_hook(Box::new(move |info: &PanicHookInfo| {
70 let payload = info.payload();
71 let panic_message = if let Some(s) = payload.downcast_ref::<&str>() {
72 s.to_string()
73 } else if let Some(s) = payload.downcast_ref::<String>() {
74 s.clone()
75 } else if let Some(s) = payload.downcast_ref::<AnyhowError>() {
76 s.to_string()
77 } else if let Some(s) = payload.downcast_ref::<ErrorReport>() {
78 s.get_last_error_title()
79 } else {
80 format!("<unknown panic payload: {:?}>", payload.type_id())
81 };
82
83 let global_settings = ERGlobalSettings::get_or_default_settings().map(|gs| gs.deref().clone()).unwrap_or_default();
85
86 if let Some(message) = (global_settings.check_known_error_types_fn)(&panic_message) {
87 eprintln!(
89 "{}: The application encountered an error it could not recover from.\n\
90 This is a known issue: {}\n\
91 Panic message: {}\n",
92 "PANIC".bright_red(),
93 message,
94 panic_message,
95 );
96 } else {
97 let panic_location: Option<SourceLocation> = match info.location() {
99 Some(location) => Some(SourceLocation::from_panic_location(location)),
100 None => None,
101 };
102
103 eprintln!(
104 "{}: A panic occurred during execution.\n\
105 * Message: '{}'\n\
106 * Path: '{}'",
107 "PANIC".bright_red(),
108 panic_message.bright_cyan().bold(),
109 panic_location.as_ref()
110 .map(|s| s.display_location(Some(global_settings.link_format)))
111 .unwrap_or(String::from("Unknown location")),
112 );
113
114 let error_report: &ErrorReport = if let Some(s) = payload.downcast_ref::<&str>() {
115 &ErrorReport::from_error(StringError::new(s.to_string()))
116 } else if let Some(s) = payload.downcast_ref::<String>() {
117 &ErrorReport::from_error(StringError::new(s.to_string()))
118 } else if let Some(s) = payload.downcast_ref::<AnyhowError>() {
119 &ErrorReport::from_anyhow_error_ref(s)
120 } else if let Some(s) = payload.downcast_ref::<ErrorReport>() {
121 s
122 } else {
123 &ErrorReport::from_error(StringError::new(panic_message))
124 };
125
126 #[cfg(not(debug_assertions))]
129 {
130 let submit_report =
131 (global_settings.submit_error_reporter_fn)(error_report);
132 eprintln!(
133 "{}: The application encountered an error it could not recover from.\n\
134 If you report this we might be able to fix this in the future.\n\
135 Title: {title}\n\n\
136 {message}",
137 "PANIC".bright_red(),
138 title = submit_report.get_title().red().bold(),
139 message = submit_report.create_message().unwrap_or_else(
140 |err| format!("{}\nSomething went wrong while generating error report: \n{err}", "Error while processing Panic".red().bold())
141 ),
142 );
143 let error_report_id = submit_report.get_error_report().get_unique_id();
145 let error_title = submit_report.get_title();
146 let panic_location_string = panic_location.as_ref()
147 .map(|s| s.display_location(Some(global_settings.link_format)))
148 .unwrap_or(String::from("Unknown location"));
149 error!(
150 error_type = "PANIC",
151 error_report_id = error_report_id,
152 error_title = error_title,
153 panic_location = panic_location_string,
154 "The application encountered an error it could not recover from: {error_title}"
155 );
156 }
157
158 #[cfg(debug_assertions)]
161 {
162 let submit_report =
163 (global_settings.submit_error_reporter_fn)(error_report);
164 let message = submit_report.get_error_report().stringify(ErrorFmtSettings::from(&global_settings));
165 let url = submit_report.create_submit_url_limited(2083).map(|s| s.to_string());
168
169 match (message, url) {
170 (Err(m_err), Err(u_err)) => {
171 eprintln!(
172 "PANIC: The application encountered an error it could not recover from.\n\
173 This error occurred while handling the Panic of an other error.\n\
174 Panic message while creating panic message: {m_err}\n\
175 Panic message while creating panic report URL: {u_err}\n"
176 );
177 }
178 (Err(m_err), Ok(_)) => {
179 eprintln!(
180 "PANIC: The application encountered an error it could not recover from.\n\
181 This error occurred while handling the Panic of an other error.\n\
182 Panic message while creating panic message: {m_err}"
183 );
184 }
185 (Ok(_), Err(u_err)) => {
186 eprintln!(
187 "PANIC: The application encountered an error it could not recover from.\n\
188 This error occurred while handling the Panic of an other error.\n\
189 Panic message while creating panic report URL: {u_err}"
190 );
191 }
192 (Ok(message), Ok(url)) => {
193 let mut report_link = "No report link available.".to_owned();
195 if !url.starts_with("data:text/plain,") {
196 report_link = format!("\
197 ┌──────────────────────────┐\n\
198 │ \x1b]8;;{url}\x1b\\\u{f296} Open/Submit Bug Report\x1b]8;;\x1b\\ │\n\
199 └──────────────────────────┘");
200 }
201 if !url.starts_with("data:text/plain,") && std::env::var("NO_COLOR").is_ok() {
202 report_link = format!("Report Link: {}", url);
203 }
204
205 eprintln!(
206 "{}: The application encountered an error it could not recover from.\n\
207 {message}\n\
208 {report_link}",
209 "PANIC".bright_red(),
210 );
211 }
212 }
213 let error_report_id = submit_report.get_error_report().get_unique_id();
215 let error_title = submit_report.get_title();
216 let panic_location_string = panic_location.as_ref()
217 .map(|s| s.display_location(Some(LinkDebugIde::NoLink)))
218 .unwrap_or(String::from("Unknown location"));
219 error!(
220 error_type = "PANIC",
221 error_report_id = error_report_id,
222 error_title = error_title,
223 panic_location = panic_location_string,
224 "The application encountered an error it could not recover from: {error_title}"
225 );
226 }
227 }
228 }));
229 }
230 };
231}
232
233#[macro_export]
239macro_rules! setup_panic_simple {
240 () => {{
241 if ::std::env::var("RUST_BACKTRACE").is_err() {
244 #[allow(unused_imports)]
245 use charon_error::prelude::panic_hook::*;
246 #[allow(unused_imports)]
247 use std::panic::{self, PanicHookInfo};
248
249 panic::set_hook(Box::new(move |info: &PanicHookInfo| {
250 let payload = info.payload();
251 let panic_message = if let Some(s) = payload.downcast_ref::<&str>() {
252 s.to_string()
253 } else if let Some(s) = payload.downcast_ref::<String>() {
254 s.clone()
255 } else if let Some(s) = payload.downcast_ref::<AnyhowError>() {
256 s.to_string()
257 } else if let Some(s) = payload.downcast_ref::<ErrorReport>() {
258 s.get_last_error_title()
259 } else {
260 format!("<unknown panic payload: {:?}>", payload.type_id())
261 };
262 let panic_location: Option<SourceLocation> = match info.location() {
263 Some(location) => Some(SourceLocation::from_panic_location(location)),
264 None => None,
265 };
266 eprintln!(
267 "PANIC: The application encountered an error it could not recover from.\n\
268 * Message: '{panic_message}'\n\
269 * Path: '{}'",
270 panic_location
271 .as_ref()
272 .map(|s| s.display_location(None))
273 .unwrap_or(String::from("Unknown location"))
274 );
275 let panic_title = panic_message;
277 let panic_location_string = panic_location
278 .as_ref()
279 .map(|s| s.display_location(Some(LinkDebugIde::NoLink)))
280 .unwrap_or(String::from("Unknown location"));
281 error!(
282 error_type = "PANIC",
283 panic_location = panic_location_string,
284 panic_title = panic_title,
285 "The application encountered an error it could not recover from: {panic_title}"
286 );
287 }));
288 }
289 }};
290}