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}