1use std::convert::Infallible;
9
10use axum::response::{IntoResponseParts, ResponseParts};
11use sentry::types::Uuid;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub struct SentryEventID(Uuid);
16
17impl SentryEventID {
18 pub fn for_last_event() -> Option<Self> {
23 sentry::last_event_id().filter(|id| !id.is_nil()).map(Self)
24 }
25}
26
27impl IntoResponseParts for SentryEventID {
28 type Error = Infallible;
29 fn into_response_parts(self, mut res: ResponseParts) -> Result<ResponseParts, Self::Error> {
30 res.headers_mut()
31 .insert("X-Sentry-Event-ID", self.0.to_string().parse().unwrap());
32
33 Ok(res)
34 }
35}
36
37#[macro_export]
41macro_rules! record_error {
42 ($error:expr, !) => {{
43 let error = &$error;
44 tracing::warn!(error = error as &dyn std::error::Error, "{error}");
45 Option::<$crate::sentry::SentryEventID>::None
46 }};
47
48 ($error:expr) => {{
49 let error = &$error;
50 tracing::error!(error = error as &dyn std::error::Error, "{error}");
51
52 $crate::sentry::SentryEventID::for_last_event()
56 }};
57
58 ($error:expr, $pattern:pat) => {
59 if let $pattern = $error {
60 record_error!($error)
61 } else {
62 record_error!($error, !)
63 }
64 };
65}