2025-12-01
This commit is contained in:
@@ -9,6 +9,7 @@ from datetime import datetime, timezone
|
||||
from functools import wraps
|
||||
from itertools import chain
|
||||
|
||||
from sentry_sdk._types import AnnotatedValue
|
||||
from sentry_sdk.attachments import Attachment
|
||||
from sentry_sdk.consts import DEFAULT_MAX_BREADCRUMBS, FALSE_VALUES, INSTRUMENTER
|
||||
from sentry_sdk.feature_flags import FlagBuffer, DEFAULT_FLAG_CAPACITY
|
||||
@@ -43,10 +44,11 @@ from sentry_sdk.utils import (
|
||||
logger,
|
||||
)
|
||||
|
||||
import typing
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Mapping, MutableMapping
|
||||
from collections.abc import Mapping
|
||||
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
@@ -185,6 +187,8 @@ class Scope:
|
||||
"_contexts",
|
||||
"_extras",
|
||||
"_breadcrumbs",
|
||||
"_n_breadcrumbs_truncated",
|
||||
"_gen_ai_original_message_count",
|
||||
"_event_processors",
|
||||
"_error_processors",
|
||||
"_should_capture",
|
||||
@@ -209,6 +213,8 @@ class Scope:
|
||||
|
||||
self._name = None # type: Optional[str]
|
||||
self._propagation_context = None # type: Optional[PropagationContext]
|
||||
self._n_breadcrumbs_truncated = 0 # type: int
|
||||
self._gen_ai_original_message_count = {} # type: Dict[str, int]
|
||||
|
||||
self.client = NonRecordingClient() # type: sentry_sdk.client.BaseClient
|
||||
|
||||
@@ -234,23 +240,25 @@ class Scope:
|
||||
rv._name = self._name
|
||||
rv._fingerprint = self._fingerprint
|
||||
rv._transaction = self._transaction
|
||||
rv._transaction_info = dict(self._transaction_info)
|
||||
rv._transaction_info = self._transaction_info.copy()
|
||||
rv._user = self._user
|
||||
|
||||
rv._tags = dict(self._tags)
|
||||
rv._contexts = dict(self._contexts)
|
||||
rv._extras = dict(self._extras)
|
||||
rv._tags = self._tags.copy()
|
||||
rv._contexts = self._contexts.copy()
|
||||
rv._extras = self._extras.copy()
|
||||
|
||||
rv._breadcrumbs = copy(self._breadcrumbs)
|
||||
rv._event_processors = list(self._event_processors)
|
||||
rv._error_processors = list(self._error_processors)
|
||||
rv._n_breadcrumbs_truncated = self._n_breadcrumbs_truncated
|
||||
rv._gen_ai_original_message_count = self._gen_ai_original_message_count.copy()
|
||||
rv._event_processors = self._event_processors.copy()
|
||||
rv._error_processors = self._error_processors.copy()
|
||||
rv._propagation_context = self._propagation_context
|
||||
|
||||
rv._should_capture = self._should_capture
|
||||
rv._span = self._span
|
||||
rv._session = self._session
|
||||
rv._force_auto_session_tracking = self._force_auto_session_tracking
|
||||
rv._attachments = list(self._attachments)
|
||||
rv._attachments = self._attachments.copy()
|
||||
|
||||
rv._profile = self._profile
|
||||
|
||||
@@ -678,12 +686,12 @@ class Scope:
|
||||
self._level = None # type: Optional[LogLevelStr]
|
||||
self._fingerprint = None # type: Optional[List[str]]
|
||||
self._transaction = None # type: Optional[str]
|
||||
self._transaction_info = {} # type: MutableMapping[str, str]
|
||||
self._transaction_info = {} # type: dict[str, str]
|
||||
self._user = None # type: Optional[Dict[str, Any]]
|
||||
|
||||
self._tags = {} # type: Dict[str, Any]
|
||||
self._contexts = {} # type: Dict[str, Dict[str, Any]]
|
||||
self._extras = {} # type: MutableMapping[str, Any]
|
||||
self._extras = {} # type: dict[str, Any]
|
||||
self._attachments = [] # type: List[Attachment]
|
||||
|
||||
self.clear_breadcrumbs()
|
||||
@@ -793,6 +801,11 @@ class Scope:
|
||||
def user(self, value):
|
||||
# type: (Optional[Dict[str, Any]]) -> None
|
||||
"""When set a specific user is bound to the scope. Deprecated in favor of set_user."""
|
||||
warnings.warn(
|
||||
"The `Scope.user` setter is deprecated in favor of `Scope.set_user()`.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
self.set_user(value)
|
||||
|
||||
def set_user(self, value):
|
||||
@@ -884,7 +897,8 @@ class Scope:
|
||||
self._contexts[key] = value
|
||||
|
||||
def remove_context(
|
||||
self, key # type: str
|
||||
self,
|
||||
key, # type: str
|
||||
):
|
||||
# type: (...) -> None
|
||||
"""Removes a context."""
|
||||
@@ -900,7 +914,8 @@ class Scope:
|
||||
self._extras[key] = value
|
||||
|
||||
def remove_extra(
|
||||
self, key # type: str
|
||||
self,
|
||||
key, # type: str
|
||||
):
|
||||
# type: (...) -> None
|
||||
"""Removes a specific extra key."""
|
||||
@@ -910,6 +925,7 @@ class Scope:
|
||||
# type: () -> None
|
||||
"""Clears breadcrumb buffer."""
|
||||
self._breadcrumbs = deque() # type: Deque[Breadcrumb]
|
||||
self._n_breadcrumbs_truncated = 0
|
||||
|
||||
def add_attachment(
|
||||
self,
|
||||
@@ -977,6 +993,7 @@ class Scope:
|
||||
|
||||
while len(self._breadcrumbs) > max_breadcrumbs:
|
||||
self._breadcrumbs.popleft()
|
||||
self._n_breadcrumbs_truncated += 1
|
||||
|
||||
def start_transaction(
|
||||
self,
|
||||
@@ -1146,8 +1163,20 @@ class Scope:
|
||||
"""
|
||||
self.generate_propagation_context(environ_or_headers)
|
||||
|
||||
# When we generate the propagation context, the sample_rand value is set
|
||||
# if missing or invalid (we use the original value if it's valid).
|
||||
# We want the transaction to use the same sample_rand value. Due to duplicated
|
||||
# propagation logic in the transaction, we pass it in to avoid recomputing it
|
||||
# in the transaction.
|
||||
# TYPE SAFETY: self.generate_propagation_context() ensures that self._propagation_context
|
||||
# is not None.
|
||||
sample_rand = typing.cast(
|
||||
PropagationContext, self._propagation_context
|
||||
)._sample_rand()
|
||||
|
||||
transaction = Transaction.continue_from_headers(
|
||||
normalize_incoming_data(environ_or_headers),
|
||||
_sample_rand=sample_rand,
|
||||
op=op,
|
||||
origin=origin,
|
||||
name=name,
|
||||
@@ -1297,7 +1326,8 @@ class Scope:
|
||||
self._force_auto_session_tracking = None
|
||||
|
||||
def add_event_processor(
|
||||
self, func # type: EventProcessor
|
||||
self,
|
||||
func, # type: EventProcessor
|
||||
):
|
||||
# type: (...) -> None
|
||||
"""Register a scope local event processor on the scope.
|
||||
@@ -1348,17 +1378,23 @@ class Scope:
|
||||
|
||||
def _apply_breadcrumbs_to_event(self, event, hint, options):
|
||||
# type: (Event, Hint, Optional[Dict[str, Any]]) -> None
|
||||
event.setdefault("breadcrumbs", {}).setdefault("values", []).extend(
|
||||
self._breadcrumbs
|
||||
)
|
||||
event.setdefault("breadcrumbs", {})
|
||||
|
||||
# This check is just for mypy -
|
||||
if not isinstance(event["breadcrumbs"], AnnotatedValue):
|
||||
event["breadcrumbs"].setdefault("values", [])
|
||||
event["breadcrumbs"]["values"].extend(self._breadcrumbs)
|
||||
|
||||
# Attempt to sort timestamps
|
||||
try:
|
||||
for crumb in event["breadcrumbs"]["values"]:
|
||||
if isinstance(crumb["timestamp"], str):
|
||||
crumb["timestamp"] = datetime_from_isoformat(crumb["timestamp"])
|
||||
if not isinstance(event["breadcrumbs"], AnnotatedValue):
|
||||
for crumb in event["breadcrumbs"]["values"]:
|
||||
if isinstance(crumb["timestamp"], str):
|
||||
crumb["timestamp"] = datetime_from_isoformat(crumb["timestamp"])
|
||||
|
||||
event["breadcrumbs"]["values"].sort(key=lambda crumb: crumb["timestamp"])
|
||||
event["breadcrumbs"]["values"].sort(
|
||||
key=lambda crumb: crumb["timestamp"]
|
||||
)
|
||||
except Exception as err:
|
||||
logger.debug("Error when sorting breadcrumbs", exc_info=err)
|
||||
pass
|
||||
@@ -1546,6 +1582,14 @@ class Scope:
|
||||
self._extras.update(scope._extras)
|
||||
if scope._breadcrumbs:
|
||||
self._breadcrumbs.extend(scope._breadcrumbs)
|
||||
if scope._n_breadcrumbs_truncated:
|
||||
self._n_breadcrumbs_truncated = (
|
||||
self._n_breadcrumbs_truncated + scope._n_breadcrumbs_truncated
|
||||
)
|
||||
if scope._gen_ai_original_message_count:
|
||||
self._gen_ai_original_message_count.update(
|
||||
scope._gen_ai_original_message_count
|
||||
)
|
||||
if scope._span:
|
||||
self._span = scope._span
|
||||
if scope._attachments:
|
||||
@@ -1568,7 +1612,7 @@ class Scope:
|
||||
user=None, # type: Optional[Any]
|
||||
level=None, # type: Optional[LogLevelStr]
|
||||
extras=None, # type: Optional[Dict[str, Any]]
|
||||
contexts=None, # type: Optional[Dict[str, Any]]
|
||||
contexts=None, # type: Optional[Dict[str, Dict[str, Any]]]
|
||||
tags=None, # type: Optional[Dict[str, str]]
|
||||
fingerprint=None, # type: Optional[List[str]]
|
||||
):
|
||||
@@ -1639,8 +1683,11 @@ def new_scope():
|
||||
yield new_scope
|
||||
|
||||
finally:
|
||||
# restore original scope
|
||||
_current_scope.reset(token)
|
||||
try:
|
||||
# restore original scope
|
||||
_current_scope.reset(token)
|
||||
except (LookupError, ValueError):
|
||||
capture_internal_exception(sys.exc_info())
|
||||
|
||||
|
||||
@contextmanager
|
||||
@@ -1674,8 +1721,11 @@ def use_scope(scope):
|
||||
yield scope
|
||||
|
||||
finally:
|
||||
# restore original scope
|
||||
_current_scope.reset(token)
|
||||
try:
|
||||
# restore original scope
|
||||
_current_scope.reset(token)
|
||||
except (LookupError, ValueError):
|
||||
capture_internal_exception(sys.exc_info())
|
||||
|
||||
|
||||
@contextmanager
|
||||
@@ -1716,8 +1766,15 @@ def isolation_scope():
|
||||
|
||||
finally:
|
||||
# restore original scopes
|
||||
_current_scope.reset(current_token)
|
||||
_isolation_scope.reset(isolation_token)
|
||||
try:
|
||||
_current_scope.reset(current_token)
|
||||
except (LookupError, ValueError):
|
||||
capture_internal_exception(sys.exc_info())
|
||||
|
||||
try:
|
||||
_isolation_scope.reset(isolation_token)
|
||||
except (LookupError, ValueError):
|
||||
capture_internal_exception(sys.exc_info())
|
||||
|
||||
|
||||
@contextmanager
|
||||
@@ -1756,8 +1813,15 @@ def use_isolation_scope(isolation_scope):
|
||||
|
||||
finally:
|
||||
# restore original scopes
|
||||
_current_scope.reset(current_token)
|
||||
_isolation_scope.reset(isolation_token)
|
||||
try:
|
||||
_current_scope.reset(current_token)
|
||||
except (LookupError, ValueError):
|
||||
capture_internal_exception(sys.exc_info())
|
||||
|
||||
try:
|
||||
_isolation_scope.reset(isolation_token)
|
||||
except (LookupError, ValueError):
|
||||
capture_internal_exception(sys.exc_info())
|
||||
|
||||
|
||||
def should_send_default_pii():
|
||||
|
||||
Reference in New Issue
Block a user