66from sentry_sdk ._types import MYPY
77from sentry_sdk .utils import logger , capture_internal_exceptions
88from sentry_sdk .tracing import Transaction
9+ from sentry_sdk .attachments import Attachment
910
1011if MYPY :
1112 from typing import Any
@@ -90,6 +91,7 @@ class Scope(object):
9091 "_should_capture" ,
9192 "_span" ,
9293 "_session" ,
94+ "_attachments" ,
9395 "_force_auto_session_tracking" ,
9496 )
9597
@@ -112,6 +114,7 @@ def clear(self):
112114 self ._tags = {} # type: Dict[str, Any]
113115 self ._contexts = {} # type: Dict[str, Dict[str, Any]]
114116 self ._extras = {} # type: Dict[str, Any]
117+ self ._attachments = [] # type: List[Attachment]
115118
116119 self .clear_breadcrumbs ()
117120 self ._should_capture = True
@@ -251,6 +254,26 @@ def clear_breadcrumbs(self):
251254 """Clears breadcrumb buffer."""
252255 self ._breadcrumbs = deque () # type: Deque[Breadcrumb]
253256
257+ def add_attachment (
258+ self ,
259+ bytes = None , # type: Optional[bytes]
260+ filename = None , # type: Optional[str]
261+ path = None , # type: Optional[str]
262+ content_type = None , # type: Optional[str]
263+ add_to_transactions = False , # type: bool
264+ ):
265+ # type: (...) -> None
266+ """Adds an attachment to future events sent."""
267+ self ._attachments .append (
268+ Attachment (
269+ bytes = bytes ,
270+ path = path ,
271+ filename = filename ,
272+ content_type = content_type ,
273+ add_to_transactions = add_to_transactions ,
274+ )
275+ )
276+
254277 def add_event_processor (
255278 self , func # type: EventProcessor
256279 ):
@@ -310,10 +333,21 @@ def _drop(event, cause, ty):
310333 logger .info ("%s (%s) dropped event (%s)" , ty , cause , event )
311334 return None
312335
336+ is_transaction = event .get ("type" ) == "transaction"
337+
338+ # put all attachments into the hint. This lets callbacks play around
339+ # with attachments. We also later pull this out of the hint when we
340+ # create the envelope.
341+ attachments_to_send = hint .get ("attachments" ) or []
342+ for attachment in self ._attachments :
343+ if not is_transaction or attachment .add_to_transactions :
344+ attachments_to_send .append (attachment )
345+ hint ["attachments" ] = attachments_to_send
346+
313347 if self ._level is not None :
314348 event ["level" ] = self ._level
315349
316- if event . get ( "type" ) != "transaction" :
350+ if not is_transaction :
317351 event .setdefault ("breadcrumbs" , {}).setdefault ("values" , []).extend (
318352 self ._breadcrumbs
319353 )
@@ -379,6 +413,8 @@ def update_from_scope(self, scope):
379413 self ._breadcrumbs .extend (scope ._breadcrumbs )
380414 if scope ._span :
381415 self ._span = scope ._span
416+ if scope ._attachments :
417+ self ._attachments .extend (scope ._attachments )
382418
383419 def update_from_kwargs (
384420 self ,
@@ -425,6 +461,7 @@ def __copy__(self):
425461 rv ._span = self ._span
426462 rv ._session = self ._session
427463 rv ._force_auto_session_tracking = self ._force_auto_session_tracking
464+ rv ._attachments = list (self ._attachments )
428465
429466 return rv
430467
0 commit comments