sentry_backtrace/
integration.rs

1use std::thread;
2
3use sentry_core::protocol::{Event, Thread};
4use sentry_core::{ClientOptions, Integration};
5
6use crate::current_stacktrace;
7use crate::process::process_event_stacktrace;
8
9/// Integration to process Event stacktraces.
10///
11/// This integration will trim backtraces, depending on the `trim_backtraces`
12/// and `extra_border_frames` options.
13/// It will then classify each frame according to the `in_app_include` and
14/// `in_app_exclude` options.
15#[derive(Debug, Default)]
16pub struct ProcessStacktraceIntegration;
17
18impl ProcessStacktraceIntegration {
19    /// Creates a new Integration to process stacktraces.
20    pub fn new() -> Self {
21        Self
22    }
23}
24
25impl Integration for ProcessStacktraceIntegration {
26    fn name(&self) -> &'static str {
27        "process-stacktrace"
28    }
29
30    fn process_event(
31        &self,
32        mut event: Event<'static>,
33        options: &ClientOptions,
34    ) -> Option<Event<'static>> {
35        for exc in &mut event.exception {
36            if let Some(ref mut stacktrace) = exc.stacktrace {
37                process_event_stacktrace(stacktrace, options);
38            }
39        }
40        for th in &mut event.threads {
41            if let Some(ref mut stacktrace) = th.stacktrace {
42                process_event_stacktrace(stacktrace, options);
43            }
44        }
45        if let Some(ref mut stacktrace) = event.stacktrace {
46            process_event_stacktrace(stacktrace, options);
47        }
48        Some(event)
49    }
50}
51
52/// Integration to attach stacktraces to Events.
53///
54/// This integration will add an additional thread backtrace to captured
55/// messages, respecting the `attach_stacktrace` option.
56#[derive(Debug, Default)]
57pub struct AttachStacktraceIntegration;
58
59impl AttachStacktraceIntegration {
60    /// Creates a new Integration to attach stacktraces to Events.
61    pub fn new() -> Self {
62        Self
63    }
64}
65
66impl Integration for AttachStacktraceIntegration {
67    fn name(&self) -> &'static str {
68        "attach-stacktrace"
69    }
70
71    fn process_event(
72        &self,
73        mut event: Event<'static>,
74        options: &ClientOptions,
75    ) -> Option<Event<'static>> {
76        if options.attach_stacktrace && !has_stacktrace(&event) {
77            let thread = current_thread(true);
78            if thread.stacktrace.is_some() {
79                event.threads.values.push(thread);
80            }
81        }
82        Some(event)
83    }
84}
85
86fn has_stacktrace(event: &Event) -> bool {
87    event.stacktrace.is_some()
88        || event.exception.iter().any(|exc| exc.stacktrace.is_some())
89        || event.threads.iter().any(|thrd| thrd.stacktrace.is_some())
90}
91
92/// Captures information about the current thread.
93///
94/// If `with_stack` is set to `true` the current stacktrace is
95/// attached.
96pub fn current_thread(with_stack: bool) -> Thread {
97    // NOTE: `as_u64` is nightly only
98    // See https://github.com/rust-lang/rust/issues/67939
99    let thread_id: u64 = unsafe { std::mem::transmute(thread::current().id()) };
100    Thread {
101        id: Some(thread_id.to_string().into()),
102        name: thread::current().name().map(str::to_owned),
103        current: true,
104        stacktrace: if with_stack {
105            current_stacktrace()
106        } else {
107            None
108        },
109        ..Default::default()
110    }
111}