traceback_error/lib.rs
1pub mod block_on;
2pub mod set_callback;
3
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use serde_json::{json, Value};
7use set_callback::TracebackCallbackType;
8use std::{
9 error::Error,
10 fmt::{Display, Formatter},
11 fs::File,
12 io::Write,
13};
14
15pub use paste;
16pub use serde_json;
17
18/// # Traceback Error Callback
19///
20/// The `TRACEBACK_ERROR_CALLBACK` is a mutable static variable that holds an
21/// optional callback function for custom error handling in a Rust program using
22/// the `traceback_error` crate. This callback is called when a `TracebackError`
23/// goes out of scope, allowing you to customize how error information is handled
24/// and reported.
25///
26/// ## Usage
27///
28/// To use the `TRACEBACK_ERROR_CALLBACK`, you can set it to your custom traceback
29/// callback function using the `set_traceback!` macro.
30/// Your custom traceback callback function should take an argument of type
31/// `traceback_error::TracebackError`. The macro generates a unique struct and
32/// function to wrap your callback and sets it as the traceback callback.
33///
34/// Example of setting a custom traceback callback:
35///
36/// ```rust
37/// // Define a custom traceback callback function
38/// fn my_traceback_callback(error: traceback_error::TracebackError) {
39/// // Custom error handling logic here
40/// println!("Custom traceback callback called: {:?}", error);
41/// }
42///
43/// // Use the set_traceback macro to set the custom traceback callback
44/// traceback_error::set_traceback!(my_traceback_callback);
45///
46/// // Any TracebackErrors will now be handled by my_traceback_callback when dropped
47/// ```
48///
49/// ## Asynchronous Callbacks
50///
51/// If your custom traceback callback is asynchronous, you can specify it as such
52/// using the `async` keyword when calling the `set_traceback!` macro.
53///
54/// Example of setting an asynchronous custom traceback callback:
55///
56/// ```rust
57/// // Define an asynchronous custom traceback callback function
58/// async fn my_async_traceback_callback(error: traceback_error::TracebackError) {
59/// // Custom error handling logic here
60/// println!("Async custom traceback callback called: {:?}", error);
61/// }
62///
63/// // Use the set_traceback macro to set the asynchronous custom traceback callback
64/// traceback_error::set_traceback!(async my_async_traceback_callback);
65/// ```
66pub static mut TRACEBACK_ERROR_CALLBACK: Option<TracebackCallbackType> = None;
67
68/// A custom error struct for handling tracebacks in Rust applications.
69///
70/// This struct is designed to capture error information such as the error message,
71/// the file and line where the error occurred, and additional contextual data.
72///
73/// # Examples
74///
75/// Creating a new `TracebackError` with a custom message:
76///
77/// ```rust
78/// use chrono::{DateTime, Utc};
79/// use serde_json::Value;
80///
81/// let error = traceback_error::traceback!("Custom error message");
82/// println!("{:?}", error);
83/// ```
84///
85/// # Fields
86///
87/// - `message`: A string containing the error message.
88/// - `file`: A string containing the filename where the error occurred.
89/// - `line`: An unsigned integer representing the line number where the error occurred.
90/// - `parent`: An optional boxed `TracebackError` representing the parent error, if any.
91/// - `time_created`: A `chrono::DateTime<Utc>` indicating when the error was created.
92/// - `extra_data`: A `serde_json::Value` for storing additional error-related data.
93/// - `project`: An optional string representing the project name.
94/// - `computer`: An optional string representing the computer name.
95/// - `user`: An optional string representing the username.
96/// - `is_parent`: A boolean indicating if this error is considered a parent error.
97/// - `is_handled`: A boolean indicating if the error has been handled.
98/// - `is_default`: A boolean indicating if this error is the default error.
99///
100/// # Default Implementation
101///
102/// The `Default` trait is implemented for `TracebackError`, creating a default instance
103/// with the following values:
104///
105/// - `message`: "Default message"
106/// - `file`: The current file's name (using `file!()`).
107/// - `line`: The current line number (using `line!()`).
108/// - `parent`: None
109/// - `time_created`: The Unix epoch time.
110/// - `extra_data`: Value::Null
111/// - `project`: None
112/// - `computer`: None
113/// - `user`: None
114/// - `is_parent`: false
115/// - `is_handled`: false
116/// - `is_default`: true
117///
118/// # Equality Comparison
119///
120/// The `PartialEq` trait is implemented for `TracebackError`, allowing you to compare
121/// two `TracebackError` instances for equality based on their message, file, line, and
122/// other relevant fields. The `is_handled` and `is_default` fields are not considered
123/// when comparing for equality.
124///
125/// # Dropping Errors
126///
127/// Errors are automatically dropped when they go out of scope, but before they are dropped,
128/// they are handled by the `TRACEBACK_ERROR_CALLBACK` variable.
129/// By default, this variable is a function simply set to serialize the error and
130/// write it to a JSON file, but the default function can be changed with the
131/// `set_callback!` macro.
132///
133/// # Callback Types
134///
135/// The callback function can be either synchronous or asynchronous, depending on the
136/// `TracebackCallbackType` set globally using the `TRACEBACK_ERROR_CALLBACK` variable.
137/// It can be set using the `set_callback!` macro.
138///
139/// - If `TRACEBACK_ERROR_CALLBACK` is `Some(TracebackCallbackType::Async)`, an
140/// asynchronous callback function is used.
141/// - If `TRACEBACK_ERROR_CALLBACK` is `Some(TracebackCallbackType::Sync)`, a
142/// synchronous callback function is used.
143/// - If `TRACEBACK_ERROR_CALLBACK` is `None`, a default callback function is used.
144///
145/// # Creating Errors
146///
147/// You can create a new `TracebackError` instance using the `traceback!` macro. Additional
148/// data can be added using the `with_extra_data` method, and environment variables are
149/// automatically added when the error is being handled.
150/// The additional data should be stored in a serde_json::Value struct.
151///
152/// # Environment Variables
153///
154/// The `with_env_vars` method populates the `project`, `computer`, and `user` fields with
155/// information obtained from environment variables (`CARGO_PKG_NAME`, `COMPUTERNAME`, and
156/// `USERNAME`, respectively) or assigns default values if the environment variables are
157/// not present.
158///
159/// # Tracing
160///
161/// Tracing can be essential for diagnosing and debugging issues in your applications. When an
162/// error occurs, you can create a `TracebackError` instance to record the error's details, such
163/// as the error message, the location in the code where it occurred, and additional contextual
164/// information.
165/// Should a function return a TracebackError, it can then be re-captured to trace it even further.
166#[derive(Debug, Serialize, Deserialize, Clone)]
167pub struct TracebackError {
168 pub message: String,
169 pub file: String,
170 pub line: u32,
171 pub parent: Option<Box<TracebackError>>,
172 pub time_created: DateTime<Utc>,
173 pub extra_data: Vec<Value>,
174 pub project: Option<String>,
175 pub computer: Option<String>,
176 pub user: Option<String>,
177 pub is_parent: bool,
178 pub is_handled: bool,
179 is_default: bool,
180}
181
182impl Default for TracebackError {
183 fn default() -> Self {
184 Self {
185 message: "Default message".to_string(),
186 file: file!().to_string(),
187 line: line!(),
188 parent: None,
189 time_created: DateTime::from_utc(
190 chrono::NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
191 Utc,
192 ),
193 extra_data: vec![],
194 project: None,
195 computer: None,
196 user: None,
197 is_parent: false,
198 is_handled: false,
199 is_default: true,
200 }
201 }
202}
203
204impl PartialEq for TracebackError {
205 fn eq(&self, other: &Self) -> bool {
206 let (this, mut other) = (self.clone(), other.clone());
207 other.is_handled = this.is_handled;
208 this.message == other.message
209 && this.file == other.file
210 && this.line == other.line
211 && this.parent == other.parent
212 && this.extra_data == other.extra_data
213 && this.project == other.project
214 && this.computer == other.computer
215 && this.user == other.user
216 && this.is_parent == other.is_parent
217 }
218}
219
220impl Drop for TracebackError {
221 fn drop(&mut self) {
222 if self.is_parent || self.is_handled || self.is_default {
223 return;
224 }
225 let mut this = std::mem::take(self);
226 this = this.with_env_vars();
227 this.is_handled = true;
228 unsafe {
229 let callback: Option<&mut TracebackCallbackType> = TRACEBACK_ERROR_CALLBACK.as_mut();
230 match callback {
231 Some(TracebackCallbackType::Async(ref mut f)) => {
232 block_on::block_on(f.call(this)); // bad practice, fix later
233 }
234 Some(TracebackCallbackType::Sync(ref mut f)) => {
235 f.call(this);
236 }
237 None => {
238 default_callback(this);
239 }
240 }
241 }
242 }
243}
244
245impl TracebackError {
246 pub fn new(message: String, file: String, line: u32) -> Self {
247 Self {
248 message,
249 file,
250 line,
251 parent: None,
252 time_created: Utc::now(),
253 extra_data: vec![],
254 project: None,
255 computer: None,
256 user: None,
257 is_parent: false,
258 is_handled: false,
259 is_default: false,
260 }
261 }
262 /// This method allows you to attach additional data to a `TracebackError` instance.
263 /// This extra data can be valuable when diagnosing and debugging errors,
264 /// as it provides context and information related to the error.
265 ///
266 /// ## Parameters:
267 /// - `extra_data`: A `serde_json::Value` containing the extra data you want to associate with the error.
268 ///
269 /// ## Return Value:
270 /// - Returns a modified `TracebackError` instance with the provided `extra_data`.
271 ///
272 /// ## Example Usage:
273 /// ```rs
274 /// use traceback_error::{traceback, TracebackError, serde_json::json};
275 ///
276 /// fn main() {
277 /// // Create a new TracebackError with extra data
278 /// let error = traceback!().with_extra_data(json!({
279 /// "foo": "bar",
280 /// "a": "b",
281 /// "1": "2"
282 /// }));
283 ///
284 /// // Now the error instance contains the specified extra data
285 /// }
286 /// ```
287 ///
288 /// This method is useful when you want to enrich error objects with additional information
289 /// relevant to the context in which the error occurred. It ensures that relevant data is
290 /// available for analysis when handling errors in your Rust application.
291 pub fn with_extra_data(mut self, extra_data: Value) -> Self {
292 self.is_default = false;
293 self.extra_data.push(extra_data);
294 self
295 }
296 /// Adds environment variables to the TracebackError.
297 ///
298 /// This method populates the `project`, `computer`, and `user` fields of the `TracebackError`
299 /// based on the values of specific environment variables. If any of these environment variables
300 /// are not found, default values are used, and the error message reflects that the information
301 /// is unknown due to the missing environment variables.
302 ///
303 /// # Example:
304 ///
305 /// ```
306 /// use traceback_error::TracebackError;
307 ///
308 /// // Create a new TracebackError and populate environment variables
309 /// let error = TracebackError::new("An error occurred".to_string(), file!().to_string(), line!())
310 /// .with_env_vars();
311 ///
312 /// // The error now contains information about the project, computer, and user from
313 /// // environment variables, or default values if the environment variables are missing.
314 /// ```
315 ///
316 /// # Environment Variables Used:
317 ///
318 /// - `CARGO_PKG_NAME`: Used to set the `project` field.
319 /// - `COMPUTERNAME`: Used to set the `computer` field.
320 /// - `USERNAME`: Used to set the `user` field.
321 ///
322 /// # Returns:
323 ///
324 /// A modified `TracebackError` with updated `project`, `computer`, and `user` fields.
325 pub fn with_env_vars(mut self) -> Self {
326 // get project name using the CARGO_PKG_NAME env variable
327 let project_name = match std::env::var("CARGO_PKG_NAME") {
328 Ok(p) => p,
329 Err(_) => "Unknown due to CARGO_PKG_NAME missing".to_string(),
330 };
331 // get computer name using the COMPUTERNAME env variable
332 let computer_name = match std::env::var("COMPUTERNAME") {
333 Ok(c) => c,
334 Err(_) => "Unknown due to COMPUTERNAME missing".to_string(),
335 };
336 // get username using the USERNAME env variable
337 let username = match std::env::var("USERNAME") {
338 Ok(u) => u,
339 Err(_) => "Unknown due to USERNAME missing".to_string(),
340 };
341 self.is_default = false;
342 self.project = Some(project_name);
343 self.computer = Some(computer_name);
344 self.user = Some(username);
345 self
346 }
347 /// The `with_parent` method allows you to associate a parent error with the current `TracebackError` instance.
348 /// This can be useful when you want to create a hierarchical structure of errors, where one error is considered the parent of another.
349 ///
350 /// ## Parameters:
351 /// - `parent`: A `TracebackError` instance that you want to set as the parent of the current error.
352 ///
353 /// ## Return Value:
354 /// - Returns a modified `TracebackError` instance with the specified parent error.
355 ///
356 /// ## Example:
357 /// ```rs
358 /// use traceback_error::TracebackError;
359 ///
360 /// fn main() {
361 /// // Create a new TracebackError
362 /// let parent_error = TracebackError::new("Parent error".to_string(), file!().to_string(), line!());
363 ///
364 /// // Create a child error with the parent error
365 /// let child_error = TracebackError::new("Child error".to_string(), file!().to_string(), line!())
366 /// .with_parent(parent_error);
367 ///
368 /// // Now, `child_error` has `parent_error` as its parent
369 /// }
370 /// ```
371 ///
372 /// The with_parent method is particularly useful when you want to establish relationships between errors,
373 /// making it easier to understand error hierarchies and diagnose issues.
374 pub fn with_parent(mut self, parent: TracebackError) -> Self {
375 self.is_default = false;
376 self.parent = Some(Box::new(parent.with_is_parent(true)));
377 self
378 }
379 fn with_is_parent(mut self, is_parent: bool) -> Self {
380 self.is_default = false;
381 self.is_parent = is_parent;
382 self
383 }
384}
385
386/// This display implementation is recursive, and will print the error and all its parents
387/// with a tab in front of each parent.
388impl Display for TracebackError {
389 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
390 let mut parent = self.parent.as_ref();
391 let mut first = true;
392 let mut amount_tabs = 0;
393 while let Some(p) = parent {
394 if first {
395 first = false;
396 } else {
397 write!(f, "\n")?;
398 }
399 for _ in 0..amount_tabs {
400 write!(f, "\t")?;
401 }
402 write!(f, "{}", p)?;
403 amount_tabs += 1;
404 parent = p.parent.as_ref();
405 }
406 write!(f, "\n")?;
407 for _ in 0..amount_tabs {
408 write!(f, "\t")?;
409 }
410 write!(f, "{}:{}: {}", self.file, self.line, self.message)
411 }
412}
413
414impl Error for TracebackError {}
415
416impl serde::de::Error for TracebackError {
417 fn custom<T: std::fmt::Display>(msg: T) -> Self {
418 // Create a new TracebackError with the provided message
419 TracebackError {
420 message: msg.to_string(),
421 file: String::new(),
422 line: 0,
423 parent: None,
424 time_created: Utc::now(),
425 extra_data: vec![json!({
426 "error_type": "serde::de::Error",
427 "error_message": msg.to_string()
428 })],
429 project: None,
430 computer: None,
431 user: None,
432 is_parent: false,
433 is_handled: false,
434 is_default: false,
435 }
436 }
437}
438
439/// # Default Traceback Error Callback
440///
441/// The `default_callback` function is a built-in error handling callback used
442/// when `TRACEBACK_ERROR_CALLBACK` is set to `None`. This callback is responsible
443/// for handling and reporting `TracebackError` instances in a default manner.
444///
445/// ## Behavior
446///
447/// When a `TracebackError` goes out of scope and `TRACEBACK_ERROR_CALLBACK` is not
448/// set to a custom callback, the `default_callback` function is used. This function
449/// performs the following actions:
450///
451/// 1. Retrieves the current time in UTC and creates a timestamp string.
452/// 2. Checks if the "errors" folder exists and creates it if it doesn't.
453/// 3. Generates a unique filename based on the current timestamp.
454/// 4. Writes the error information in JSON format to a file with the generated filename
455/// in the "errors" folder.
456/// 5. Logs any encountered errors during the above steps.
457///
458/// This default behavior ensures that unhandled errors are captured, timestamped,
459/// and saved as JSON files for later analysis.
460///
461/// ## Usage
462///
463/// Typically, you don't need to call the `default_callback` function directly. Instead,
464/// it is automatically used as the error handler when `TRACEBACK_ERROR_CALLBACK` is not
465/// set to a custom callback.
466///
467/// Example of using the default behavior when `TRACEBACK_ERROR_CALLBACK` is not set:
468///
469/// ```rust
470/// // No custom callback set, so the default_callback will be used
471/// traceback_error::set_traceback!(None);
472///
473/// // Any TracebackErrors will now be handled by the default_callback when dropped
474/// ```
475///
476/// To customize error handling, you can set a custom callback using the `set_traceback!`
477/// macro as shown in the documentation for `TRACEBACK_ERROR_CALLBACK`.
478pub fn default_callback(err: TracebackError) {
479 // get current time
480 let current_time = chrono::Utc::now();
481 let current_time_string = current_time.format("%Y-%m-%d.%H-%M-%S").to_string();
482 let nanosecs = current_time.timestamp_nanos();
483 let current_time_string = format!("{}.{}", current_time_string, nanosecs);
484 // check if errors folder exists
485 match std::fs::read_dir("errors") {
486 Ok(_) => {}
487 Err(_) => {
488 // if not, create it
489 match std::fs::create_dir("errors") {
490 Ok(_) => {}
491 Err(e) => {
492 println!("Error when creating directory: {}", e);
493 return;
494 }
495 };
496 }
497 };
498 // create {current_time_string}.json
499 let filename = format!("./errors/{current_time_string}.json");
500 println!("Writing error to file: {}", filename);
501 let mut file = match File::create(filename) {
502 Ok(f) => f,
503 Err(e) => {
504 println!("Error when creating file: {}", e);
505 return;
506 }
507 };
508 // parse error to json
509 let err = match serde_json::to_string_pretty(&err) {
510 Ok(e) => e,
511 Err(e) => {
512 println!("Error when parsing error: {}", e);
513 return;
514 }
515 };
516 // write json to file
517 match file.write_all(err.as_bytes()) {
518 Ok(_) => {}
519 Err(e) => {
520 println!("Error when writing to file: {}", e);
521 return;
522 }
523 };
524}
525/// A macro for creating instances of the `TracebackError` struct with various options.
526///
527/// The `traceback!` macro simplifies the creation of `TracebackError` instances by providing
528/// convenient syntax for specifying error messages and handling different error types.
529///
530/// # Examples
531///
532/// Creating a new `TracebackError` with a custom message:
533///
534/// ```rust
535/// let error = traceback_error::traceback!("Custom error message");
536/// println!("{:?}", error);
537/// ```
538///
539/// Creating a new `TracebackError` from a generic error:
540///
541/// ```rust
542/// fn custom_function() -> Result<(), traceback_error::TracebackError> {
543/// // ...
544/// // Some error occurred
545/// let generic_error: Box<dyn std::error::Error> = Box::new(std::io::Error::new(std::io::ErrorKind::Other, "Generic error"));
546/// Err(traceback_error::traceback!(err generic_error))
547/// }
548/// ```
549///
550/// Creating a new `TracebackError` from a generic error with a custom message:
551///
552/// ```rust
553/// fn custom_function() -> Result<(), traceback_error::TracebackError> {
554/// // ...
555/// // Some error occurred
556/// let generic_error: Box<dyn std::error::Error> = Box::new(std::io::Error::new(std::io::ErrorKind::Other, "Generic error"));
557/// Err(traceback_error::traceback!(err generic_error, "Custom error message"))
558/// }
559/// ```
560///
561/// Tracing an error:
562/// ```rust
563/// fn main() {
564/// match caller_of_tasks() {
565/// Ok(_) => {}
566/// Err(e) => {
567/// traceback_error::traceback!(err e, "One of the tasks failed");
568/// }
569/// }
570/// }
571///
572/// fn task_that_may_fail() -> Result<(), traceback_error::TracebackError> {
573/// return Err(traceback_error::traceback!("task_that_may_fail failed"));
574/// }
575///
576/// fn other_task_that_may_fail() -> Result<(), traceback_error::TracebackError> {
577/// return Err(traceback_error::traceback!("other_task_that_may_fail failed"));
578/// }
579///
580/// fn caller_of_tasks() -> Result<(), traceback_error::TracebackError> {
581/// match task_that_may_fail() {
582/// Ok(_) => {}
583/// Err(e) => {
584/// return Err(traceback_error::traceback!(err e));
585/// }
586/// };
587/// match other_task_that_may_fail() {
588/// Ok(_) => {}
589/// Err(e) => {
590/// return Err(traceback_error::traceback!(err e));
591/// }
592/// };
593/// Ok(())
594/// }
595/// ```
596/// When the error is dropped at the end of main() in the above example, the default callback
597/// function generates the following JSON error file:
598/// ```json
599/// {
600/// "message": "One of the tasks failed",
601/// "file": "src\\main.rs",
602/// "line": 7,
603/// "parent": {
604/// "message": "task_that_may_fail failed",
605/// "file": "src\\main.rs",
606/// "line": 24,
607/// "parent": {
608/// "message": "task_that_may_fail failed",
609/// "file": "src\\main.rs",
610/// "line": 13,
611/// "parent": null,
612/// "time_created": "2023-09-11T10:27:25.195697400Z",
613/// "extra_data": null,
614/// "project": null,
615/// "computer": null,
616/// "user": null,
617/// "is_parent": true,
618/// "is_handled": true,
619/// "is_default": false
620/// },
621/// "time_created": "2023-09-11T10:27:25.195789100Z",
622/// "extra_data": null,
623/// "project": null,
624/// "computer": null,
625/// "user": null,
626/// "is_parent": true,
627/// "is_handled": true,
628/// "is_default": false
629/// },
630/// "time_created": "2023-09-11T10:27:25.195836Z",
631/// "extra_data": null,
632/// "project": "traceback_test",
633/// "computer": "tommypc",
634/// "user": "tommy",
635/// "is_parent": false,
636/// "is_handled": true,
637/// "is_default": false
638/// }
639/// ```
640///
641/// # Syntax
642///
643/// The `traceback!` macro supports the following syntax variations:
644///
645/// - `traceback!()`: Creates a `TracebackError` with an empty message, using the current file
646/// and line number.
647///
648/// - `traceback!($msg:expr)`: Creates a `TracebackError` with the specified error message,
649/// using the current file and line number.
650///
651/// - `traceback!(err $e:expr)`: Attempts to downcast the provided error (`$e`) to a
652/// `TracebackError`. If successful, it marks the error as handled and creates a new
653/// `TracebackError` instance based on the downcasted error. If the downcast fails, it
654/// creates a `TracebackError` with an empty message and includes the original error's
655/// description in the extra data field.
656///
657/// - `traceback!(err $e:expr, $msg:expr)`: Similar to the previous variation but allows specifying
658/// a custom error message for the new `TracebackError` instance.
659///
660/// # Error Handling
661///
662/// When using the `traceback!` macro to create `TracebackError` instances from other error types,
663/// it automatically sets the `is_handled` flag to `true` for the original error to indicate that
664/// it has been handled. This prevents the `TRACEBACK_ERROR_CALLBACK` function to be called on it.
665///
666/// # Environment Variables
667///
668/// Environment variables such as `CARGO_PKG_NAME`, `COMPUTERNAME`, and `USERNAME` are automatically
669/// added to the `project`, `computer`, and `user` fields when the error is being handled.
670///
671#[macro_export]
672macro_rules! traceback {
673 () => {
674 $crate::TracebackError::new("".to_string(), file!().to_string(), line!())
675 };
676 ($msg:expr) => {
677 $crate::TracebackError::new($msg.to_string(), file!().to_string(), line!())
678 };
679 (err $e:expr) => {{
680 use $crate::serde_json::json;
681 let err_string = $e.to_string();
682 let mut boxed: Box<dyn std::any::Any> = Box::new($e);
683 if let Some(traceback_err) = boxed.downcast_mut::<$crate::TracebackError>() {
684 traceback_err.is_handled = true;
685 $crate::TracebackError::new(
686 traceback_err.message.to_string(),
687 file!().to_string(),
688 line!(),
689 )
690 .with_parent(traceback_err.clone())
691 } else {
692 $crate::TracebackError::new(String::from(""), file!().to_string(), line!())
693 .with_extra_data(json!({
694 "error": err_string
695 }))
696 }
697 }};
698 (err $e:expr, $msg:expr) => {{
699 use $crate::serde_json::json;
700 let err_string = $e.to_string();
701 let mut boxed: Box<dyn std::any::Any> = Box::new($e);
702 if let Some(traceback_err) = boxed.downcast_mut::<$crate::TracebackError>() {
703 traceback_err.is_handled = true;
704 $crate::TracebackError::new(
705 $msg.to_string(),
706 file!().to_string(),
707 line!(),
708 )
709 .with_parent(traceback_err.clone())
710 } else {
711 $crate::TracebackError::new(String::from(""), file!().to_string(), line!())
712 .with_extra_data(json!({
713 "error": err_string
714 }))
715 }
716 }};
717}