foundations_sentry/
panic.rs1use std::any::Any;
4use std::panic::{self, PanicHookInfo};
5use std::sync::Once;
6
7use sentry_core::protocol::{Event, Exception, Level, Mechanism};
8use sentry_core::{ClientOptions, Integration};
9
10use crate::backtrace::unresolved_stacktrace;
11
12#[derive(Debug, Default)]
18pub struct NoFlushPanicIntegration {
19 inner: sentry_panic::PanicIntegration,
20}
21
22impl NoFlushPanicIntegration {
23 pub fn new() -> Self {
25 Self::default()
26 }
27
28 #[must_use]
35 pub fn with_unresolved_stacktraces(mut self) -> Self {
36 self.inner = self.inner.add_extractor(|info| {
37 Some(Event {
38 exception: vec![Exception {
39 ty: "panic".into(),
40 mechanism: Some(Mechanism {
41 ty: "panic".into(),
42 handled: Some(false),
43 ..Default::default()
44 }),
45 value: Some(sentry_panic::message_from_panic_info(info).to_owned()),
46 stacktrace: unresolved_stacktrace(),
47 ..Default::default()
48 }]
49 .into(),
50 level: Level::Fatal,
51 ..Default::default()
52 })
53 });
54 self
55 }
56}
57
58static INIT: Once = Once::new();
59
60impl Integration for NoFlushPanicIntegration {
61 fn name(&self) -> &'static str {
62 self.inner.name()
63 }
64
65 fn setup(&self, cfg: &mut ClientOptions) {
66 let upstream_integration: Option<&sentry_panic::PanicIntegration> = cfg
69 .integrations
70 .iter()
71 .find_map(|i| <dyn Any>::downcast_ref(i));
72
73 if let Some(integ) = upstream_integration {
74 panic!(
75 "Found an upstream `sentry_panic::PanicIntegration` while installing `NoFlushPanicIntegration`: {integ:?}. This defeats the purpose of NoFlushPanicIntegration and will cause duplicate events."
76 );
77 }
78
79 INIT.call_once(|| {
80 let next = panic::take_hook();
81 panic::set_hook(Box::new(move |info| {
82 panic_handler(info);
83 next(info)
84 }));
85 });
86 }
87}
88
89fn panic_handler(info: &PanicHookInfo) {
90 sentry_core::with_integration(|integration: &NoFlushPanicIntegration, hub| {
91 hub.capture_event(integration.inner.event_from_panic_info(info));
92 });
94}