1use std::borrow::Cow;
2use std::collections::{HashMap, VecDeque};
3use std::fmt;
4use std::sync::{Arc, Mutex, PoisonError, RwLock};
5
6use crate::performance::TransactionOrSpan;
7use crate::protocol::{Attachment, Breadcrumb, Context, Event, Level, Transaction, User, Value};
8use crate::session::Session;
9use crate::Client;
10
11#[derive(Debug)]
12pub struct Stack {
13 top: StackLayer,
14 layers: Vec<StackLayer>,
15}
16
17pub type EventProcessor = Arc<dyn Fn(Event<'static>) -> Option<Event<'static>> + Send + Sync>;
18
19#[derive(Clone, Default)]
38pub struct Scope {
39 pub(crate) level: Option<Level>,
40 pub(crate) fingerprint: Option<Arc<[Cow<'static, str>]>>,
41 pub(crate) transaction: Option<Arc<str>>,
42 pub(crate) breadcrumbs: Arc<VecDeque<Breadcrumb>>,
43 pub(crate) user: Option<Arc<User>>,
44 pub(crate) extra: Arc<HashMap<String, Value>>,
45 pub(crate) tags: Arc<HashMap<String, String>>,
46 pub(crate) contexts: Arc<HashMap<String, Context>>,
47 pub(crate) event_processors: Arc<Vec<EventProcessor>>,
48 pub(crate) session: Arc<Mutex<Option<Session>>>,
49 pub(crate) span: Arc<Option<TransactionOrSpan>>,
50 pub(crate) attachments: Arc<Vec<Attachment>>,
51}
52
53impl fmt::Debug for Scope {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.debug_struct("Scope")
56 .field("level", &self.level)
57 .field("fingerprint", &self.fingerprint)
58 .field("transaction", &self.transaction)
59 .field("breadcrumbs", &self.breadcrumbs)
60 .field("user", &self.user)
61 .field("extra", &self.extra)
62 .field("tags", &self.tags)
63 .field("contexts", &self.contexts)
64 .field("event_processors", &self.event_processors.len())
65 .field("session", &self.session)
66 .field("span", &self.span)
67 .field("attachments", &self.attachments.len())
68 .finish()
69 }
70}
71
72#[derive(Debug, Clone)]
73pub struct StackLayer {
74 pub client: Option<Arc<Client>>,
75 pub scope: Arc<Scope>,
76}
77
78impl Stack {
79 pub fn from_client_and_scope(client: Option<Arc<Client>>, scope: Arc<Scope>) -> Stack {
80 Stack {
81 top: StackLayer { client, scope },
82 layers: vec![],
83 }
84 }
85
86 pub fn push(&mut self) {
87 let layer = self.top.clone();
88 self.layers.push(layer);
89 }
90
91 pub fn pop(&mut self) {
92 if self.layers.is_empty() {
93 panic!("Pop from empty stack");
94 }
95 self.top = self.layers.pop().unwrap();
96 }
97
98 #[inline(always)]
99 pub fn top(&self) -> &StackLayer {
100 &self.top
101 }
102
103 #[inline(always)]
104 pub fn top_mut(&mut self) -> &mut StackLayer {
105 &mut self.top
106 }
107
108 pub fn depth(&self) -> usize {
109 self.layers.len()
110 }
111}
112
113#[derive(Default)]
120pub struct ScopeGuard(pub(crate) Option<(Arc<RwLock<Stack>>, usize)>);
121
122impl fmt::Debug for ScopeGuard {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 write!(f, "ScopeGuard")
125 }
126}
127
128impl Drop for ScopeGuard {
129 fn drop(&mut self) {
130 if let Some((stack, depth)) = self.0.take() {
131 let popped_depth = {
132 let mut stack = stack.write().unwrap_or_else(PoisonError::into_inner);
133 let popped_depth = stack.depth();
134 stack.pop();
135 popped_depth
136 };
137 if popped_depth != depth {
147 panic!("Popped scope guard out of order");
148 }
149 }
150 }
151}
152
153impl Scope {
154 pub fn clear(&mut self) {
160 *self = Default::default();
161 }
162
163 pub fn clear_breadcrumbs(&mut self) {
165 self.breadcrumbs = Default::default();
166 }
167
168 pub fn set_level(&mut self, level: Option<Level>) {
170 self.level = level;
171 }
172
173 pub fn set_fingerprint(&mut self, fingerprint: Option<&[&str]>) {
175 self.fingerprint =
176 fingerprint.map(|fp| fp.iter().map(|s| Cow::Owned((*s).into())).collect())
177 }
178
179 pub fn set_transaction(&mut self, transaction: Option<&str>) {
181 self.transaction = transaction.map(Arc::from);
182 if let Some(name) = transaction {
183 let trx = match self.span.as_ref() {
184 Some(TransactionOrSpan::Span(span)) => &span.transaction,
185 Some(TransactionOrSpan::Transaction(trx)) => &trx.inner,
186 _ => return,
187 };
188
189 if let Some(trx) = trx.lock().unwrap().transaction.as_mut() {
190 trx.name = Some(name.into());
191 }
192 }
193 }
194
195 pub fn set_user(&mut self, user: Option<User>) {
197 self.user = user.map(Arc::new);
198 }
199
200 pub fn user(&self) -> Option<&User> {
202 self.user.as_deref()
203 }
204
205 pub fn set_tag<V: ToString>(&mut self, key: &str, value: V) {
207 Arc::make_mut(&mut self.tags).insert(key.to_string(), value.to_string());
208 }
209
210 pub fn remove_tag(&mut self, key: &str) {
214 Arc::make_mut(&mut self.tags).remove(key);
215 }
216
217 pub fn set_context<C: Into<Context>>(&mut self, key: &str, value: C) {
219 Arc::make_mut(&mut self.contexts).insert(key.to_string(), value.into());
220 }
221
222 pub fn remove_context(&mut self, key: &str) {
224 Arc::make_mut(&mut self.contexts).remove(key);
225 }
226
227 pub fn set_extra(&mut self, key: &str, value: Value) {
229 Arc::make_mut(&mut self.extra).insert(key.to_string(), value);
230 }
231
232 pub fn remove_extra(&mut self, key: &str) {
234 Arc::make_mut(&mut self.extra).remove(key);
235 }
236
237 pub fn add_event_processor<F>(&mut self, f: F)
239 where
240 F: Fn(Event<'static>) -> Option<Event<'static>> + Send + Sync + 'static,
241 {
242 Arc::make_mut(&mut self.event_processors).push(Arc::new(f));
243 }
244
245 pub fn add_attachment(&mut self, attachment: Attachment) {
247 Arc::make_mut(&mut self.attachments).push(attachment);
248 }
249
250 pub fn clear_attachments(&mut self) {
252 Arc::make_mut(&mut self.attachments).clear();
253 }
254
255 pub fn apply_to_event(&self, mut event: Event<'static>) -> Option<Event<'static>> {
257 if self.level.is_some() {
259 event.level = self.level.unwrap();
260 }
261
262 if event.user.is_none() {
263 if let Some(user) = self.user.as_deref() {
264 event.user = Some(user.clone());
265 }
266 }
267
268 event.breadcrumbs.extend(self.breadcrumbs.iter().cloned());
269 event
270 .extra
271 .extend(self.extra.iter().map(|(k, v)| (k.to_owned(), v.to_owned())));
272 event
273 .tags
274 .extend(self.tags.iter().map(|(k, v)| (k.to_owned(), v.to_owned())));
275 event.contexts.extend(
276 self.contexts
277 .iter()
278 .map(|(k, v)| (k.to_owned(), v.to_owned())),
279 );
280
281 if let Some(span) = self.span.as_ref() {
282 span.apply_to_event(&mut event);
283 }
284
285 if event.transaction.is_none() {
286 if let Some(txn) = self.transaction.as_deref() {
287 event.transaction = Some(txn.to_owned());
288 }
289 }
290
291 if event.fingerprint.len() == 1
292 && (event.fingerprint[0] == "{{ default }}" || event.fingerprint[0] == "{{default}}")
293 {
294 if let Some(fp) = self.fingerprint.as_deref() {
295 event.fingerprint = Cow::Owned(fp.to_owned());
296 }
297 }
298
299 for processor in self.event_processors.as_ref() {
300 let id = event.event_id;
301 event = match processor(event) {
302 Some(event) => event,
303 None => {
304 sentry_debug!("event processor dropped event {}", id);
305 return None;
306 }
307 }
308 }
309
310 Some(event)
311 }
312
313 pub fn apply_to_transaction(&self, transaction: &mut Transaction<'static>) {
315 if transaction.user.is_none() {
316 if let Some(user) = self.user.as_deref() {
317 transaction.user = Some(user.clone());
318 }
319 }
320
321 transaction
322 .extra
323 .extend(self.extra.iter().map(|(k, v)| (k.to_owned(), v.to_owned())));
324 transaction
325 .tags
326 .extend(self.tags.iter().map(|(k, v)| (k.to_owned(), v.to_owned())));
327 transaction.contexts.extend(
328 self.contexts
329 .iter()
330 .map(|(k, v)| (k.to_owned(), v.to_owned())),
331 );
332 }
333
334 pub fn set_span(&mut self, span: Option<TransactionOrSpan>) {
336 self.span = Arc::new(span);
337 }
338
339 pub fn get_span(&self) -> Option<TransactionOrSpan> {
341 self.span.as_ref().clone()
342 }
343
344 pub(crate) fn update_session_from_event(&self, event: &Event<'static>) {
345 if let Some(session) = self.session.lock().unwrap().as_mut() {
346 session.update_from_event(event);
347 }
348 }
349}