drcode_go/
lib.rs

1use sentry::ClientOptions;
2use sentry_types::Dsn;
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum DrCodeError {
7    #[error("Missing required configuration field: {0}")]
8    MissingField(String),
9    #[error("Failed to initialize Sentry: {0}")]
10    InitializationError(String),
11}
12
13pub struct Config {
14    pub public_key: String,
15    pub project_id: String,
16    pub traces_sample_rate: f32,
17    pub profiles_sample_rate: f32,
18}
19
20pub struct DrCode {
21    config: Config,
22    dsn: Dsn,
23}
24
25#[derive(Debug, Clone, Copy)]
26pub enum Level {
27    Debug,
28    Info,
29    Warning,
30    Error,
31    Fatal,
32}
33
34impl From<Level> for sentry::Level {
35    fn from(level: Level) -> Self {
36        match level {
37            Level::Debug => sentry::Level::Debug,
38            Level::Info => sentry::Level::Info,
39            Level::Warning => sentry::Level::Warning,
40            Level::Error => sentry::Level::Error,
41            Level::Fatal => sentry::Level::Fatal,
42        }
43    }
44}
45
46impl DrCode {
47    pub fn new(config: Config) -> Result<Self, DrCodeError> {
48        Self::validate_config(&config)?;
49        let dsn = Self::construct_dsn(&config)?;
50        Ok(Self { config, dsn })
51    }
52
53    fn validate_config(config: &Config) -> Result<(), DrCodeError> {
54        if config.public_key.is_empty() {
55            return Err(DrCodeError::MissingField("publicKey".to_string()));
56        }
57        if config.project_id.is_empty() {
58            return Err(DrCodeError::MissingField("projectId".to_string()));
59        }
60        Ok(())
61    }
62
63    fn construct_dsn(config: &Config) -> Result<Dsn, DrCodeError> {
64        let dsn_string = format!(
65            "https://{}@pulse.drcode.ai:443/{}",
66            config.public_key, config.project_id
67        );
68        dsn_string.parse::<Dsn>().map_err(|e| DrCodeError::InitializationError(e.to_string()))
69    }
70
71    pub fn init(&self) -> Result<(), DrCodeError> {
72        let options = ClientOptions {
73            dsn: Some(self.dsn.clone()),
74            traces_sample_rate: self.config.traces_sample_rate,
75            ..Default::default()
76        };
77
78        let _guard = sentry::init(options);
79        Ok(())
80    }
81
82    pub fn capture_message(&self, message: &str, level: Level) {
83        sentry::capture_message(message, level.into());
84    }
85
86    pub fn capture_exception<E>(&self, error: &E)
87    where
88        E: std::error::Error + Send + Sync + 'static,
89    {
90        sentry::capture_error(error);
91    }
92}
93
94pub fn error_handler<E>(err: E)
95where
96    E: std::error::Error + Send + Sync + 'static,
97{
98    sentry::capture_error(&err);
99}