1use std::fmt;
6use std::path::Path;
7
8#[cfg(unix)]
9mod native {
10 #![allow(warnings, clippy::all)]
13
14 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
15}
16
17pub type Transport = fn(envelope: &[u8]);
19
20#[cfg(unix)]
22unsafe extern "C" fn transport_proxy(
23 envelope: *const native::sentry_envelope_s,
24 tx_pointer: *mut std::ffi::c_void,
25) {
26 if envelope.is_null() || tx_pointer.is_null() {
27 return;
28 }
29
30 let mut len = 0;
31 let buf = unsafe { native::sentry_envelope_serialize(envelope, &mut len) };
32
33 if !buf.is_null() && len > 0 {
34 let transport: Transport = unsafe { std::mem::transmute(tx_pointer) };
35 transport(unsafe { std::slice::from_raw_parts(buf as *const u8, len) });
36 }
37
38 unsafe {
39 native::sentry_free(buf as _);
40 }
41}
42
43#[derive(Default)]
51#[cfg_attr(not(unix), allow(dead_code))]
52pub struct CrashHandler<'a> {
53 dsn: &'a str,
54 database: &'a str,
55 transport: Option<Transport>,
56 release: Option<&'a str>,
57 environment: Option<&'a str>,
58}
59
60impl fmt::Debug for CrashHandler<'_> {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 let transport = match self.transport {
63 Some(_) => "Some(fn)",
64 None => "None",
65 };
66
67 f.debug_struct("CrashHandler")
68 .field("dsn", &self.dsn)
69 .field("database", &self.database)
70 .field("transport", &format_args!("{transport}"))
71 .field("release", &self.release)
72 .field("environment", &self.environment)
73 .finish()
74 }
75}
76
77impl<'a> CrashHandler<'a> {
78 pub fn new(dsn: &'a str, database: &'a Path) -> Self {
82 Self {
83 dsn,
84 database: database.to_str().unwrap(),
85 transport: None,
86 release: None,
87 environment: None,
88 }
89 }
90
91 pub fn transport(&mut self, transport: Transport) -> &mut Self {
97 self.transport = Some(transport);
98 self
99 }
100
101 pub fn release(&mut self, release: Option<&'a str>) -> &mut Self {
105 self.release = release;
106 self
107 }
108
109 pub fn environment(&mut self, environment: Option<&'a str>) -> &mut Self {
113 self.environment = environment;
114 self
115 }
116
117 #[cfg(unix)]
119 pub fn install(&self) {
120 use std::ffi::CString;
121
122 unsafe {
123 let options = native::sentry_options_new();
124
125 let dsn_cstr = CString::new(self.dsn).unwrap();
126 native::sentry_options_set_dsn(options, dsn_cstr.as_ptr());
127
128 let db_cstr = CString::new(self.database).unwrap();
129 native::sentry_options_set_database_path(options, db_cstr.as_ptr());
130
131 if let Some(release) = self.release {
132 let release_cstr = CString::new(release).unwrap();
133 native::sentry_options_set_release(options, release_cstr.as_ptr());
134 }
135
136 if let Some(environment) = self.environment {
137 let env_cstr = CString::new(environment).unwrap();
138 native::sentry_options_set_environment(options, env_cstr.as_ptr());
139 }
140
141 if let Some(f) = self.transport {
142 let tx = native::sentry_new_function_transport(Some(transport_proxy), f as _);
143 native::sentry_options_set_transport(options, tx);
144 }
145
146 native::sentry_init(options);
147 }
148 }
149
150 #[cfg(not(unix))]
151 pub fn install(&self) {
152 unimplemented!("crash handler not supported on this platform");
153 }
154}