drcode_rust/
lib.rs

1
2use sentry::ClientInitGuard;
3use std::panic;
4use tokio::task;
5
6/// Configuration for the Nadeem Rust error reporting.
7pub struct Config {
8    pub public_key: String,
9    pub project_id: String,
10}
11
12/// Initialize the Sentry client with the provided configuration and set up automatic error reporting.
13///
14/// # Arguments
15///
16/// * `config` - The configuration containing the public key and project ID.
17///
18/// # Returns
19///
20/// A `ClientInitGuard` which, when dropped, will flush all events.
21pub fn init(config: Config) -> ClientInitGuard {
22    let dsn = format!(
23        "https://{}@pulse.drcode.ai:443/{}",
24        config.public_key, config.project_id
25    );
26
27    let guard = sentry::init((
28        dsn,
29        sentry::ClientOptions {
30            release: sentry::release_name!(),
31            attach_stacktrace: true,
32            ..Default::default()
33        },
34    ));
35
36    // Set up custom panic hook for automatic reporting
37    let default_panic = panic::take_hook();
38    panic::set_hook(Box::new(move |panic_info| {
39        let payload = panic_info.payload().downcast_ref::<String>();
40        let message = payload.map(|s| s.as_str()).unwrap_or("Unknown panic");
41        
42        sentry::capture_message(message, sentry::Level::Fatal);
43
44        default_panic(panic_info);
45    }));
46
47    guard
48}
49
50/// Report an error to Sentry manually.
51///
52/// # Arguments
53///
54/// * `error` - The error to report.
55pub fn report_error<E: std::error::Error + Send + Sync + 'static>(error: E) {
56    sentry::capture_error(&error);
57}
58
59/// Run an asynchronous task with automatic error reporting.
60///
61/// # Arguments
62///
63/// * `future` - The future to run.
64///
65/// # Returns
66///
67/// The result of the future.
68pub async fn run_with_error_reporting<F, T, E>(future: F) -> Result<T, E>
69where
70    F: std::future::Future<Output = Result<T, E>> + Send + 'static,
71    T: Send + 'static,
72    E: std::error::Error + Send + Sync + 'static,
73{
74    task::spawn(async move {
75        match future.await {
76            Ok(result) => Ok(result),
77            Err(e) => {
78                sentry::capture_error(&e);
79                Err(e)
80            }
81        }
82    }).await.unwrap_or_else(|e| {
83        sentry::capture_error(&e);
84        panic!("Task panicked: {:?}", e);
85    })
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91
92    #[test]
93    fn test_init() {
94        let config = Config {
95            public_key: "test_key".to_string(),
96            project_id: "test_project".to_string(),
97        };
98        let _guard = init(config);
99    }
100
101    #[tokio::test]
102    async fn test_run_with_error_reporting() {
103        let config = Config {
104            public_key: "test_key".to_string(),
105            project_id: "test_project".to_string(),
106        };
107        let _guard = init(config);
108
109        let result = run_with_error_reporting(async {
110            Ok::<_, std::io::Error>(())
111        }).await;
112        assert!(result.is_ok());
113
114        let error_result = run_with_error_reporting(async {
115            Err::<(), _>(std::io::Error::new(std::io::ErrorKind::Other, "Test error"))
116        }).await;
117        assert!(error_result.is_err());
118    }
119}