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