From faf1d221b80fe2154125145871af941278e9c5a4 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Wed, 29 Jan 2025 16:13:41 +0100 Subject: [PATCH 01/23] feat: add _meta annotations for breadcrumb truncataion --- sentry_sdk/_types.py | 9 ++++++++- sentry_sdk/scope.py | 12 ++++++++++++ sentry_sdk/scrubber.py | 11 ++++++++--- sentry_sdk/utils.py | 2 +- tests/test_client.py | 8 +++++--- tests/test_scrubber.py | 5 ++++- 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index 22b91b202f..6c246ca8bf 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -81,11 +81,18 @@ def substituted_because_contains_sensitive_data(cls): }, ) + @classmethod + def truncated_breadcrumbs(cls, breadcrumbs, n_truncated): + # type: (list[Breadcrumb], int) -> AnnotatedValue + """Breadcrumbs were removed because the number of breadcrumbs exceeded their maximum limit.""" + return AnnotatedValue( + value=breadcrumbs, + metadata={"len": [n_truncated]}, # Remark + ) T = TypeVar("T") Annotated = Union[AnnotatedValue, T] - if TYPE_CHECKING: from collections.abc import Container, MutableMapping, Sequence diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index ce6037e6b6..9794ba8a71 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -33,6 +33,7 @@ Transaction, ) from sentry_sdk.utils import ( + AnnotatedValue, capture_internal_exception, capture_internal_exceptions, ContextVar, @@ -186,6 +187,7 @@ class Scope: "_contexts", "_extras", "_breadcrumbs", + "_breadcrumb_info", "_event_processors", "_error_processors", "_should_capture", @@ -210,6 +212,7 @@ def __init__(self, ty=None, client=None): self._name = None # type: Optional[str] self._propagation_context = None # type: Optional[PropagationContext] + self._breadcrumb_info = 0 # type: int self.client = NonRecordingClient() # type: sentry_sdk.client.BaseClient @@ -243,6 +246,7 @@ def __copy__(self): rv._extras = dict(self._extras) rv._breadcrumbs = copy(self._breadcrumbs) + rv._breadcrumb_info = copy(self._breadcrumb_info) rv._event_processors = list(self._event_processors) rv._error_processors = list(self._error_processors) rv._propagation_context = self._propagation_context @@ -916,6 +920,7 @@ def clear_breadcrumbs(self): # type: () -> None """Clears breadcrumb buffer.""" self._breadcrumbs = deque() # type: Deque[Breadcrumb] + self._breadcrumb_info = 0 def add_attachment( self, @@ -983,6 +988,7 @@ def add_breadcrumb(self, crumb=None, hint=None, **kwargs): while len(self._breadcrumbs) > max_breadcrumbs: self._breadcrumbs.popleft() + self._breadcrumb_info += 1 def start_transaction( self, @@ -1381,6 +1387,12 @@ def _apply_breadcrumbs_to_event(self, event, hint, options): logger.debug("Error when sorting breadcrumbs", exc_info=err) pass + # Add annotation that breadcrumbs were truncated + original_length = len(event["breadcrumbs"]["values"]) + self._breadcrumb_info + event["breadcrumbs"]["values"] = AnnotatedValue.truncated_breadcrumbs( + event["breadcrumbs"]["values"], original_length + ) + def _apply_user_to_event(self, event, hint, options): # type: (Event, Hint, Optional[Dict[str, Any]]) -> None if event.get("user") is None and self._user is not None: diff --git a/sentry_sdk/scrubber.py b/sentry_sdk/scrubber.py index 1df5573798..6f53ae44ef 100644 --- a/sentry_sdk/scrubber.py +++ b/sentry_sdk/scrubber.py @@ -145,9 +145,14 @@ def scrub_breadcrumbs(self, event): with capture_internal_exceptions(): if "breadcrumbs" in event: if "values" in event["breadcrumbs"]: - for value in event["breadcrumbs"]["values"]: - if "data" in value: - self.scrub_dict(value["data"]) + if isinstance(event["breadcrumbs"]["values"], AnnotatedValue): + for value in event["breadcrumbs"]["values"].value: + if "data" in value: + self.scrub_dict(value["data"]) + else: + for value in event["breadcrumbs"]["values"]: + if "data" in value: + self.scrub_dict(value["data"]) def scrub_frames(self, event): # type: (Event) -> None diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 595bbe0cf3..405ef908ed 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -59,7 +59,7 @@ from gevent.hub import Hub - from sentry_sdk._types import Event, ExcInfo + from sentry_sdk._types import Breadcrumb, Event, ExcInfo P = ParamSpec("P") R = TypeVar("R") diff --git a/tests/test_client.py b/tests/test_client.py index 67f53d989a..6af43cfe69 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -22,7 +22,7 @@ set_tag, ) from sentry_sdk.spotlight import DEFAULT_SPOTLIGHT_URL -from sentry_sdk.utils import capture_internal_exception +from sentry_sdk.utils import AnnotatedValue, capture_internal_exception from sentry_sdk.integrations.executing import ExecutingIntegration from sentry_sdk.transport import Transport from sentry_sdk.serializer import MAX_DATABAG_BREADTH @@ -1058,8 +1058,10 @@ def test_max_breadcrumbs_option( add_breadcrumb({"type": "sourdough"}) capture_message("dogs are great") - - assert len(events[0]["breadcrumbs"]["values"]) == expected_breadcrumbs + if isinstance(events[0]["breadcrumbs"]["values"], AnnotatedValue): + assert len(events[0]["breadcrumbs"]["values"].value) == expected_breadcrumbs + else: + assert len(events[0]["breadcrumbs"]["values"]) == expected_breadcrumbs def test_multiple_positional_args(sentry_init): diff --git a/tests/test_scrubber.py b/tests/test_scrubber.py index 2c462153dd..9999d55d95 100644 --- a/tests/test_scrubber.py +++ b/tests/test_scrubber.py @@ -137,7 +137,10 @@ def test_breadcrumb_extra_scrubbing(sentry_init, capture_events): assert event["_meta"]["extra"]["auth"] == {"": {"rem": [["!config", "s"]]}} assert event["_meta"]["breadcrumbs"] == { - "values": {"0": {"data": {"password": {"": {"rem": [["!config", "s"]]}}}}} + "values": { + "": {"len": [1]}, + "0": {"data": {"password": {"": {"rem": [["!config", "s"]]}}}}, + } } From f6f9dc738dac07b018b5a83866188d9e6e170fe5 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Wed, 29 Jan 2025 16:15:31 +0100 Subject: [PATCH 02/23] rename var --- sentry_sdk/scope.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 9794ba8a71..1df8d48f76 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -187,7 +187,7 @@ class Scope: "_contexts", "_extras", "_breadcrumbs", - "_breadcrumb_info", + "_n_breadcrumbs_truncated", "_event_processors", "_error_processors", "_should_capture", @@ -212,7 +212,7 @@ def __init__(self, ty=None, client=None): self._name = None # type: Optional[str] self._propagation_context = None # type: Optional[PropagationContext] - self._breadcrumb_info = 0 # type: int + self._n_breadcrumbs_truncated = 0 # type: int self.client = NonRecordingClient() # type: sentry_sdk.client.BaseClient @@ -246,7 +246,7 @@ def __copy__(self): rv._extras = dict(self._extras) rv._breadcrumbs = copy(self._breadcrumbs) - rv._breadcrumb_info = copy(self._breadcrumb_info) + rv._n_breadcrumbs_truncated = copy(self._n_breadcrumbs_truncated) rv._event_processors = list(self._event_processors) rv._error_processors = list(self._error_processors) rv._propagation_context = self._propagation_context @@ -920,7 +920,7 @@ def clear_breadcrumbs(self): # type: () -> None """Clears breadcrumb buffer.""" self._breadcrumbs = deque() # type: Deque[Breadcrumb] - self._breadcrumb_info = 0 + self._n_breadcrumbs_truncated = 0 def add_attachment( self, @@ -988,7 +988,7 @@ def add_breadcrumb(self, crumb=None, hint=None, **kwargs): while len(self._breadcrumbs) > max_breadcrumbs: self._breadcrumbs.popleft() - self._breadcrumb_info += 1 + self._n_breadcrumbs_truncated += 1 def start_transaction( self, @@ -1388,7 +1388,9 @@ def _apply_breadcrumbs_to_event(self, event, hint, options): pass # Add annotation that breadcrumbs were truncated - original_length = len(event["breadcrumbs"]["values"]) + self._breadcrumb_info + original_length = ( + len(event["breadcrumbs"]["values"]) + self._n_breadcrumbs_truncated + ) event["breadcrumbs"]["values"] = AnnotatedValue.truncated_breadcrumbs( event["breadcrumbs"]["values"], original_length ) From 07b72d4a4f5e1cd76dc0753fb3204073907d2927 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Fri, 31 Jan 2025 13:59:37 +0100 Subject: [PATCH 03/23] add AnnotatedDeque for better handling --- sentry_sdk/_types.py | 53 ++++++++++++++++++++++++++++++++++++-------- sentry_sdk/scope.py | 15 +++++++------ sentry_sdk/utils.py | 4 ++-- 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index 6c246ca8bf..74379e8eeb 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, TypeVar, Union +from typing import TYPE_CHECKING, Deque, TypeVar, Union # Re-exported for compat, since code out there in the wild might use this variable. @@ -81,18 +81,53 @@ def substituted_because_contains_sensitive_data(cls): }, ) +T = TypeVar("T") +Annotated = Union[AnnotatedValue, T] +class AnnotatedDeque(AnnotatedValue): + """ + Meta information for a data field in the event payload. + This is to tell Relay that we have tampered with the fields value. + See: + https://github.com/getsentry/relay/blob/be12cd49a0f06ea932ed9b9f93a655de5d6ad6d1/relay-general/src/types/meta.rs#L407-L423 + """ + + __slots__ = ("value", "metadata") + + def __init__(self, value, metadata): + # type: (Deque[Any], Dict[str, Any]) -> None + self.value = value + self.metadata = metadata + + def __eq__(self, other): + # type: (Any) -> bool + if not isinstance(other, AnnotatedValue): + return False + + return self.value == other.value and self.metadata == other.metadata + + def append(self, other): + # type: (Any) -> None + self.value.append(other) + + def extend(self, other): + # type: (Any) -> None + self.value.extend(other) + + def popleft(self): + self.value.popleft() + + def __len__(self): + return len(self.value) + @classmethod - def truncated_breadcrumbs(cls, breadcrumbs, n_truncated): - # type: (list[Breadcrumb], int) -> AnnotatedValue - """Breadcrumbs were removed because the number of breadcrumbs exceeded their maximum limit.""" - return AnnotatedValue( - value=breadcrumbs, + def truncated(cls, value, n_truncated): + # type: (Deque[Any], int) -> AnnotatedValue + """Data was removed because the number of elements exceeded the maximum limit.""" + return AnnotatedDeque( + value=value, metadata={"len": [n_truncated]}, # Remark ) -T = TypeVar("T") -Annotated = Union[AnnotatedValue, T] - if TYPE_CHECKING: from collections.abc import Container, MutableMapping, Sequence diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 1df8d48f76..4aa53562d1 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -33,7 +33,7 @@ Transaction, ) from sentry_sdk.utils import ( - AnnotatedValue, + AnnotatedDeque, capture_internal_exception, capture_internal_exceptions, ContextVar, @@ -1388,12 +1388,13 @@ def _apply_breadcrumbs_to_event(self, event, hint, options): pass # Add annotation that breadcrumbs were truncated - original_length = ( - len(event["breadcrumbs"]["values"]) + self._n_breadcrumbs_truncated - ) - event["breadcrumbs"]["values"] = AnnotatedValue.truncated_breadcrumbs( - event["breadcrumbs"]["values"], original_length - ) + if self._n_breadcrumbs_truncated: + original_length = ( + len(event["breadcrumbs"]["values"]) + self._n_breadcrumbs_truncated + ) + event["breadcrumbs"]["values"] = AnnotatedDeque.truncated_breadcrumbs( + event["breadcrumbs"]["values"], original_length + ) def _apply_user_to_event(self, event, hint, options): # type: (Event, Hint, Optional[Dict[str, Any]]) -> None diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 405ef908ed..b4bb33154e 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -43,6 +43,7 @@ Callable, cast, ContextManager, + Deque, Dict, Iterator, List, @@ -59,7 +60,7 @@ from gevent.hub import Hub - from sentry_sdk._types import Breadcrumb, Event, ExcInfo + from sentry_sdk._types import Event, ExcInfo P = ParamSpec("P") R = TypeVar("R") @@ -411,7 +412,6 @@ def to_header(self): rv.append(("sentry_secret", self.secret_key)) return "Sentry " + ", ".join("%s=%s" % (key, value) for key, value in rv) - def get_type_name(cls): # type: (Optional[type]) -> Optional[str] return getattr(cls, "__qualname__", None) or getattr(cls, "__name__", None) From bd8e3faae74a56a0813119094b8ede65c6ea94aa Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Fri, 31 Jan 2025 14:02:23 +0100 Subject: [PATCH 04/23] remove special case for test --- tests/test_client.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 6af43cfe69..05632479df 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -22,7 +22,7 @@ set_tag, ) from sentry_sdk.spotlight import DEFAULT_SPOTLIGHT_URL -from sentry_sdk.utils import AnnotatedValue, capture_internal_exception +from sentry_sdk.utils import capture_internal_exception from sentry_sdk.integrations.executing import ExecutingIntegration from sentry_sdk.transport import Transport from sentry_sdk.serializer import MAX_DATABAG_BREADTH @@ -1058,10 +1058,7 @@ def test_max_breadcrumbs_option( add_breadcrumb({"type": "sourdough"}) capture_message("dogs are great") - if isinstance(events[0]["breadcrumbs"]["values"], AnnotatedValue): - assert len(events[0]["breadcrumbs"]["values"].value) == expected_breadcrumbs - else: - assert len(events[0]["breadcrumbs"]["values"]) == expected_breadcrumbs + assert len(events[0]["breadcrumbs"]["values"]) == expected_breadcrumbs def test_multiple_positional_args(sentry_init): From 06216d8a92c6f222f45324d88bdd7d370a38c530 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:08:18 +0200 Subject: [PATCH 05/23] handle scope merging for breadcrumb annotations --- sentry_sdk/_types.py | 13 +++++++++++++ sentry_sdk/client.py | 10 +++++++++- sentry_sdk/scope.py | 27 ++++++++++++++++++++++++--- sentry_sdk/serializer.py | 2 ++ tests/test_scrubber.py | 19 +++++++++++-------- tests/tracing/test_misc.py | 2 +- 6 files changed, 60 insertions(+), 13 deletions(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index 74379e8eeb..418fe7af40 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -30,6 +30,15 @@ def __eq__(self, other): return self.value == other.value and self.metadata == other.metadata + def __str__(self): + return str({"value": str(self.value), "metadata": str(self.metadata)}) + + def __repr__(self): + return str(self) + + def __len__(self): + return len(self.value) + @classmethod def removed_because_raw_data(cls): # type: () -> AnnotatedValue @@ -81,8 +90,11 @@ def substituted_because_contains_sensitive_data(cls): }, ) + T = TypeVar("T") Annotated = Union[AnnotatedValue, T] + + class AnnotatedDeque(AnnotatedValue): """ Meta information for a data field in the event payload. @@ -128,6 +140,7 @@ def truncated(cls, value, n_truncated): metadata={"len": [n_truncated]}, # Remark ) + if TYPE_CHECKING: from collections.abc import Container, MutableMapping, Sequence diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index 0cdf0f7717..e95f3bb82a 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -491,6 +491,7 @@ def _prepare_event( # type: (...) -> Optional[Event] previous_total_spans = None # type: Optional[int] + previous_total_breadcrumbs = None # type: Optional[int] if event.get("timestamp") is None: event["timestamp"] = datetime.now(timezone.utc) @@ -527,6 +528,10 @@ def _prepare_event( dropped_spans = event.pop("_dropped_spans", 0) + spans_delta # type: int if dropped_spans > 0: previous_total_spans = spans_before + dropped_spans + if scope._n_breadcrumbs_truncated > 0: + previous_total_breadcrumbs = ( + len(event["breadcrumbs"]) + scope._n_breadcrumbs_truncated + ) if ( self.options["attach_stacktrace"] @@ -579,7 +584,10 @@ def _prepare_event( event["spans"] = AnnotatedValue( event.get("spans", []), {"len": previous_total_spans} ) - + if previous_total_breadcrumbs is not None: + event["breadcrumbs"] = AnnotatedValue( + event.get("breadcrumbs", []), {"len": previous_total_breadcrumbs} + ) # Postprocess the event here so that annotated types do # generally not surface in before_send if event is not None: diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 4aa53562d1..571e360f84 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -1,3 +1,4 @@ +import logging import os import sys import warnings @@ -9,6 +10,7 @@ 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 @@ -33,7 +35,6 @@ Transaction, ) from sentry_sdk.utils import ( - AnnotatedDeque, capture_internal_exception, capture_internal_exceptions, ContextVar, @@ -987,8 +988,14 @@ def add_breadcrumb(self, crumb=None, hint=None, **kwargs): logger.info("before breadcrumb dropped breadcrumb (%s)", crumb) while len(self._breadcrumbs) > max_breadcrumbs: + logging.debug( + f"i am here in the truncation logic before, {self._n_breadcrumbs_truncated}" + ) self._breadcrumbs.popleft() self._n_breadcrumbs_truncated += 1 + logging.debug( + f"i am here in the truncation logic after, {self._n_breadcrumbs_truncated}" + ) def start_transaction( self, @@ -1388,12 +1395,19 @@ def _apply_breadcrumbs_to_event(self, event, hint, options): pass # Add annotation that breadcrumbs were truncated + logging.debug( + f"i am here outside of the truncated thing, {self._n_breadcrumbs_truncated} and {len(self._breadcrumbs)}" + ) if self._n_breadcrumbs_truncated: + logging.debug("i am here in the truncated thing") original_length = ( len(event["breadcrumbs"]["values"]) + self._n_breadcrumbs_truncated ) - event["breadcrumbs"]["values"] = AnnotatedDeque.truncated_breadcrumbs( - event["breadcrumbs"]["values"], original_length + logging.debug( + f"in the truncated thing, the original_lenght is {original_length}" + ) + event["breadcrumbs"] = AnnotatedValue( + event.get("breadcrumbs", []), {"len": original_length} ) def _apply_user_to_event(self, event, hint, options): @@ -1546,6 +1560,9 @@ def apply_to_event( if not is_transaction and not is_check_in: self._apply_breadcrumbs_to_event(event, hint, options) + # logging.debug(event) + logging.debug(event["breadcrumbs"]) + logging.debug(type(event["breadcrumbs"])) self._apply_flags_to_event(event, hint, options) event = self.run_error_processors(event, hint) @@ -1579,6 +1596,10 @@ def update_from_scope(self, 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._span: self._span = scope._span if scope._attachments: diff --git a/sentry_sdk/serializer.py b/sentry_sdk/serializer.py index bc8e38c631..5bad617c3b 100644 --- a/sentry_sdk/serializer.py +++ b/sentry_sdk/serializer.py @@ -1,3 +1,4 @@ +import logging import sys import math from collections.abc import Mapping, Sequence, Set @@ -230,6 +231,7 @@ def _serialize_node( def _flatten_annotated(obj): # type: (Any) -> Any if isinstance(obj, AnnotatedValue): + logging.debug(obj) _annotate(**obj.metadata) obj = obj.value return obj diff --git a/tests/test_scrubber.py b/tests/test_scrubber.py index 9999d55d95..0b5a5c8f00 100644 --- a/tests/test_scrubber.py +++ b/tests/test_scrubber.py @@ -119,27 +119,30 @@ def test_stack_var_scrubbing(sentry_init, capture_events): def test_breadcrumb_extra_scrubbing(sentry_init, capture_events): - sentry_init() + sentry_init(max_breadcrumbs=2) + breakpoint() events = capture_events() - - logger.info("bread", extra=dict(foo=42, password="secret")) + logger.info("breadcrumb 1", extra=dict(foo=1, password="secret")) + logger.info("breadcrumb 2", extra=dict(bar=2, auth="secret")) + logger.info("breadcrumb 3", extra=dict(foobar=3, password="secret")) logger.critical("whoops", extra=dict(bar=69, auth="secret")) + print(events) (event,) = events assert event["extra"]["bar"] == 69 assert event["extra"]["auth"] == "[Filtered]" - assert event["breadcrumbs"]["values"][0]["data"] == { - "foo": 42, - "password": "[Filtered]", + "bar": 2, + "auth": "[Filtered]", } assert event["_meta"]["extra"]["auth"] == {"": {"rem": [["!config", "s"]]}} assert event["_meta"]["breadcrumbs"] == { "values": { - "": {"len": [1]}, - "0": {"data": {"password": {"": {"rem": [["!config", "s"]]}}}}, + "": {"len": [4]}, + "0": {"data": {"auth": {"": {"rem": [["!config", "s"]]}}}}, + "1": {"data": {"password": {"": {"rem": [["!config", "s"]]}}}}, } } diff --git a/tests/tracing/test_misc.py b/tests/tracing/test_misc.py index 040fb24213..6fadbbf201 100644 --- a/tests/tracing/test_misc.py +++ b/tests/tracing/test_misc.py @@ -40,7 +40,7 @@ def test_span_trimming(sentry_init, capture_events): def test_span_data_scrubbing_and_trimming(sentry_init, capture_events): sentry_init(traces_sample_rate=1.0, _experiments={"max_spans": 3}) events = capture_events() - + breakpoint() with start_transaction(name="hi"): with start_span(op="foo", name="bar") as span: span.set_data("password", "secret") From c45aa01551a4a1086ca57d0d5389292842e9821f Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:25:46 +0200 Subject: [PATCH 06/23] make everything work together and remove annotateddeque --- sentry_sdk/_types.py | 50 ++---------------------------------------- sentry_sdk/client.py | 3 ++- sentry_sdk/scope.py | 17 -------------- tests/test_scrubber.py | 7 +++--- 4 files changed, 7 insertions(+), 70 deletions(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index 418fe7af40..fc38409075 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Deque, TypeVar, Union +from typing import TYPE_CHECKING, TypeVar, Union # Re-exported for compat, since code out there in the wild might use this variable. @@ -34,7 +34,7 @@ def __str__(self): return str({"value": str(self.value), "metadata": str(self.metadata)}) def __repr__(self): - return str(self) + return self def __len__(self): return len(self.value) @@ -95,52 +95,6 @@ def substituted_because_contains_sensitive_data(cls): Annotated = Union[AnnotatedValue, T] -class AnnotatedDeque(AnnotatedValue): - """ - Meta information for a data field in the event payload. - This is to tell Relay that we have tampered with the fields value. - See: - https://github.com/getsentry/relay/blob/be12cd49a0f06ea932ed9b9f93a655de5d6ad6d1/relay-general/src/types/meta.rs#L407-L423 - """ - - __slots__ = ("value", "metadata") - - def __init__(self, value, metadata): - # type: (Deque[Any], Dict[str, Any]) -> None - self.value = value - self.metadata = metadata - - def __eq__(self, other): - # type: (Any) -> bool - if not isinstance(other, AnnotatedValue): - return False - - return self.value == other.value and self.metadata == other.metadata - - def append(self, other): - # type: (Any) -> None - self.value.append(other) - - def extend(self, other): - # type: (Any) -> None - self.value.extend(other) - - def popleft(self): - self.value.popleft() - - def __len__(self): - return len(self.value) - - @classmethod - def truncated(cls, value, n_truncated): - # type: (Deque[Any], int) -> AnnotatedValue - """Data was removed because the number of elements exceeded the maximum limit.""" - return AnnotatedDeque( - value=value, - metadata={"len": [n_truncated]}, # Remark - ) - - if TYPE_CHECKING: from collections.abc import Container, MutableMapping, Sequence diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index e95f3bb82a..14d712bd89 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -530,8 +530,9 @@ def _prepare_event( previous_total_spans = spans_before + dropped_spans if scope._n_breadcrumbs_truncated > 0: previous_total_breadcrumbs = ( - len(event["breadcrumbs"]) + scope._n_breadcrumbs_truncated + len(event["breadcrumbs"]["values"]) + scope._n_breadcrumbs_truncated ) + logging.debug(previous_total_breadcrumbs) if ( self.options["attach_stacktrace"] diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 571e360f84..025e07d8b2 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -10,7 +10,6 @@ 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 @@ -1394,22 +1393,6 @@ def _apply_breadcrumbs_to_event(self, event, hint, options): logger.debug("Error when sorting breadcrumbs", exc_info=err) pass - # Add annotation that breadcrumbs were truncated - logging.debug( - f"i am here outside of the truncated thing, {self._n_breadcrumbs_truncated} and {len(self._breadcrumbs)}" - ) - if self._n_breadcrumbs_truncated: - logging.debug("i am here in the truncated thing") - original_length = ( - len(event["breadcrumbs"]["values"]) + self._n_breadcrumbs_truncated - ) - logging.debug( - f"in the truncated thing, the original_lenght is {original_length}" - ) - event["breadcrumbs"] = AnnotatedValue( - event.get("breadcrumbs", []), {"len": original_length} - ) - def _apply_user_to_event(self, event, hint, options): # type: (Event, Hint, Optional[Dict[str, Any]]) -> None if event.get("user") is None and self._user is not None: diff --git a/tests/test_scrubber.py b/tests/test_scrubber.py index 0b5a5c8f00..0d968586e1 100644 --- a/tests/test_scrubber.py +++ b/tests/test_scrubber.py @@ -120,14 +120,13 @@ def test_stack_var_scrubbing(sentry_init, capture_events): def test_breadcrumb_extra_scrubbing(sentry_init, capture_events): sentry_init(max_breadcrumbs=2) - breakpoint() + # breakpoint() events = capture_events() logger.info("breadcrumb 1", extra=dict(foo=1, password="secret")) logger.info("breadcrumb 2", extra=dict(bar=2, auth="secret")) logger.info("breadcrumb 3", extra=dict(foobar=3, password="secret")) logger.critical("whoops", extra=dict(bar=69, auth="secret")) - print(events) (event,) = events assert event["extra"]["bar"] == 69 @@ -139,11 +138,11 @@ def test_breadcrumb_extra_scrubbing(sentry_init, capture_events): assert event["_meta"]["extra"]["auth"] == {"": {"rem": [["!config", "s"]]}} assert event["_meta"]["breadcrumbs"] == { + "": {"len": 3}, "values": { - "": {"len": [4]}, "0": {"data": {"auth": {"": {"rem": [["!config", "s"]]}}}}, "1": {"data": {"password": {"": {"rem": [["!config", "s"]]}}}}, - } + }, } From ba6634df8a15c0162073c313e6eaa3fd95a2fc5c Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:27:02 +0200 Subject: [PATCH 07/23] add some details to tests --- tests/test_scrubber.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_scrubber.py b/tests/test_scrubber.py index 0d968586e1..6aae197380 100644 --- a/tests/test_scrubber.py +++ b/tests/test_scrubber.py @@ -135,6 +135,10 @@ def test_breadcrumb_extra_scrubbing(sentry_init, capture_events): "bar": 2, "auth": "[Filtered]", } + assert event["breadcrumbs"]["values"][1]["data"] == { + "foobar": 3, + "password": "[Filtered]", + } assert event["_meta"]["extra"]["auth"] == {"": {"rem": [["!config", "s"]]}} assert event["_meta"]["breadcrumbs"] == { From 28ca7e7394a77ba2c975bb7a63ee10c5c4433881 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:27:32 +0200 Subject: [PATCH 08/23] remove breakpoints --- tests/test_scrubber.py | 1 - tests/tracing/test_misc.py | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/test_scrubber.py b/tests/test_scrubber.py index 6aae197380..2cc5f4139f 100644 --- a/tests/test_scrubber.py +++ b/tests/test_scrubber.py @@ -120,7 +120,6 @@ def test_stack_var_scrubbing(sentry_init, capture_events): def test_breadcrumb_extra_scrubbing(sentry_init, capture_events): sentry_init(max_breadcrumbs=2) - # breakpoint() events = capture_events() logger.info("breadcrumb 1", extra=dict(foo=1, password="secret")) logger.info("breadcrumb 2", extra=dict(bar=2, auth="secret")) diff --git a/tests/tracing/test_misc.py b/tests/tracing/test_misc.py index 6fadbbf201..e5486f2295 100644 --- a/tests/tracing/test_misc.py +++ b/tests/tracing/test_misc.py @@ -40,7 +40,6 @@ def test_span_trimming(sentry_init, capture_events): def test_span_data_scrubbing_and_trimming(sentry_init, capture_events): sentry_init(traces_sample_rate=1.0, _experiments={"max_spans": 3}) events = capture_events() - breakpoint() with start_transaction(name="hi"): with start_span(op="foo", name="bar") as span: span.set_data("password", "secret") From 94563485a9dd84c4c997f1e0c16c1a9724939418 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:28:24 +0200 Subject: [PATCH 09/23] remove logging --- sentry_sdk/_types.py | 3 --- sentry_sdk/serializer.py | 2 -- 2 files changed, 5 deletions(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index fc38409075..9dad2ffe08 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -33,9 +33,6 @@ def __eq__(self, other): def __str__(self): return str({"value": str(self.value), "metadata": str(self.metadata)}) - def __repr__(self): - return self - def __len__(self): return len(self.value) diff --git a/sentry_sdk/serializer.py b/sentry_sdk/serializer.py index 5bad617c3b..bc8e38c631 100644 --- a/sentry_sdk/serializer.py +++ b/sentry_sdk/serializer.py @@ -1,4 +1,3 @@ -import logging import sys import math from collections.abc import Mapping, Sequence, Set @@ -231,7 +230,6 @@ def _serialize_node( def _flatten_annotated(obj): # type: (Any) -> Any if isinstance(obj, AnnotatedValue): - logging.debug(obj) _annotate(**obj.metadata) obj = obj.value return obj From b066c3d37251cbe3f741feeb3112aa25e9e3ea7a Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:29:13 +0200 Subject: [PATCH 10/23] wip --- sentry_sdk/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index b4bb33154e..595bbe0cf3 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -43,7 +43,6 @@ Callable, cast, ContextManager, - Deque, Dict, Iterator, List, @@ -412,6 +411,7 @@ def to_header(self): rv.append(("sentry_secret", self.secret_key)) return "Sentry " + ", ".join("%s=%s" % (key, value) for key, value in rv) + def get_type_name(cls): # type: (Optional[type]) -> Optional[str] return getattr(cls, "__qualname__", None) or getattr(cls, "__name__", None) From 0869df7d1547588dbb218d6fe28a50409718ec3a Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:30:22 +0200 Subject: [PATCH 11/23] whitespace --- tests/test_client.py | 1 + tests/tracing/test_misc.py | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/test_client.py b/tests/test_client.py index 05632479df..67f53d989a 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1058,6 +1058,7 @@ def test_max_breadcrumbs_option( add_breadcrumb({"type": "sourdough"}) capture_message("dogs are great") + assert len(events[0]["breadcrumbs"]["values"]) == expected_breadcrumbs diff --git a/tests/tracing/test_misc.py b/tests/tracing/test_misc.py index e5486f2295..040fb24213 100644 --- a/tests/tracing/test_misc.py +++ b/tests/tracing/test_misc.py @@ -40,6 +40,7 @@ def test_span_trimming(sentry_init, capture_events): def test_span_data_scrubbing_and_trimming(sentry_init, capture_events): sentry_init(traces_sample_rate=1.0, _experiments={"max_spans": 3}) events = capture_events() + with start_transaction(name="hi"): with start_span(op="foo", name="bar") as span: span.set_data("password", "secret") From 9e0aead179df01d5f24d4003131db511f9611bf0 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:32:01 +0200 Subject: [PATCH 12/23] remove logging --- sentry_sdk/client.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index 14d712bd89..ed4c83e6e3 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -532,7 +532,6 @@ def _prepare_event( previous_total_breadcrumbs = ( len(event["breadcrumbs"]["values"]) + scope._n_breadcrumbs_truncated ) - logging.debug(previous_total_breadcrumbs) if ( self.options["attach_stacktrace"] From 019a166f69099a81e1806d14beb0774bb89673c7 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:32:34 +0200 Subject: [PATCH 13/23] remove logging --- sentry_sdk/scope.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 025e07d8b2..2cc39fd64e 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -987,14 +987,8 @@ def add_breadcrumb(self, crumb=None, hint=None, **kwargs): logger.info("before breadcrumb dropped breadcrumb (%s)", crumb) while len(self._breadcrumbs) > max_breadcrumbs: - logging.debug( - f"i am here in the truncation logic before, {self._n_breadcrumbs_truncated}" - ) self._breadcrumbs.popleft() self._n_breadcrumbs_truncated += 1 - logging.debug( - f"i am here in the truncation logic after, {self._n_breadcrumbs_truncated}" - ) def start_transaction( self, From 142e88e1525dc834807401174aa2b186f521d4b7 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Mon, 31 Mar 2025 10:33:03 +0200 Subject: [PATCH 14/23] remove logging --- sentry_sdk/scope.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 2cc39fd64e..5a0bbcea80 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -1,4 +1,3 @@ -import logging import os import sys import warnings @@ -1537,9 +1536,6 @@ def apply_to_event( if not is_transaction and not is_check_in: self._apply_breadcrumbs_to_event(event, hint, options) - # logging.debug(event) - logging.debug(event["breadcrumbs"]) - logging.debug(type(event["breadcrumbs"])) self._apply_flags_to_event(event, hint, options) event = self.run_error_processors(event, hint) From 168fc55a341201cf941bf7764c8b4c06aef16791 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Wed, 2 Apr 2025 09:49:38 +0200 Subject: [PATCH 15/23] fix error for older versions without breadcrumbs --- sentry_sdk/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index ed4c83e6e3..303d4f6123 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -530,7 +530,8 @@ def _prepare_event( previous_total_spans = spans_before + dropped_spans if scope._n_breadcrumbs_truncated > 0: previous_total_breadcrumbs = ( - len(event["breadcrumbs"]["values"]) + scope._n_breadcrumbs_truncated + len(event.get("breadcrumbs", {}).get("values", [])) + + scope._n_breadcrumbs_truncated ) if ( From a05707f99abb969800e5d85ad5e086c529b7ae45 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Wed, 2 Apr 2025 13:52:07 +0200 Subject: [PATCH 16/23] fix linter errors --- sentry_sdk/_types.py | 11 ++++++++--- sentry_sdk/scrubber.py | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index 9dad2ffe08..9bcb5a61f9 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -31,10 +31,15 @@ def __eq__(self, other): return self.value == other.value and self.metadata == other.metadata def __str__(self): + # type: (AnnotatedValue) -> str return str({"value": str(self.value), "metadata": str(self.metadata)}) def __len__(self): - return len(self.value) + # type: (AnnotatedValue) -> int + if self.value is not None: + return len(self.value) + else: + return 0 @classmethod def removed_because_raw_data(cls): @@ -158,8 +163,8 @@ class SDKInfo(TypedDict): Event = TypedDict( "Event", { - "breadcrumbs": dict[ - Literal["values"], list[dict[str, Any]] + "breadcrumbs": Annotated[ + dict[Literal["values"], list[dict[str, Any]]] ], # TODO: We can expand on this type "check_in_id": str, "contexts": dict[str, dict[str, object]], diff --git a/sentry_sdk/scrubber.py b/sentry_sdk/scrubber.py index 6f53ae44ef..756440047f 100644 --- a/sentry_sdk/scrubber.py +++ b/sentry_sdk/scrubber.py @@ -145,7 +145,10 @@ def scrub_breadcrumbs(self, event): with capture_internal_exceptions(): if "breadcrumbs" in event: if "values" in event["breadcrumbs"]: - if isinstance(event["breadcrumbs"]["values"], AnnotatedValue): + if ( + isinstance(event["breadcrumbs"]["values"], AnnotatedValue) + and event["breadcrumbs"]["values"].value is not None + ): for value in event["breadcrumbs"]["values"].value: if "data" in value: self.scrub_dict(value["data"]) From a75d5bcd2c82395be0b965f928f0df510e89e4b6 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Thu, 3 Apr 2025 12:18:49 +0200 Subject: [PATCH 17/23] fix check for annotatedvalue in scrubber --- sentry_sdk/scrubber.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/scrubber.py b/sentry_sdk/scrubber.py index 756440047f..e54ddc4450 100644 --- a/sentry_sdk/scrubber.py +++ b/sentry_sdk/scrubber.py @@ -146,7 +146,7 @@ def scrub_breadcrumbs(self, event): if "breadcrumbs" in event: if "values" in event["breadcrumbs"]: if ( - isinstance(event["breadcrumbs"]["values"], AnnotatedValue) + isinstance(event["breadcrumbs"], AnnotatedValue) and event["breadcrumbs"]["values"].value is not None ): for value in event["breadcrumbs"]["values"].value: From 5b04e4fd936c0f038c1c15d826810492165a0d6b Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Thu, 3 Apr 2025 12:20:12 +0200 Subject: [PATCH 18/23] fix check for annotatedvalue in scrubber --- sentry_sdk/scrubber.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/scrubber.py b/sentry_sdk/scrubber.py index e54ddc4450..69e2f02d05 100644 --- a/sentry_sdk/scrubber.py +++ b/sentry_sdk/scrubber.py @@ -149,7 +149,7 @@ def scrub_breadcrumbs(self, event): isinstance(event["breadcrumbs"], AnnotatedValue) and event["breadcrumbs"]["values"].value is not None ): - for value in event["breadcrumbs"]["values"].value: + for value in event["breadcrumbs"].value: if "data" in value: self.scrub_dict(value["data"]) else: From 12cf7dadc3e961a307952b42f445985a952e6fa2 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Thu, 3 Apr 2025 12:21:52 +0200 Subject: [PATCH 19/23] fix check for annotatedvalue in scrubber --- sentry_sdk/scrubber.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sentry_sdk/scrubber.py b/sentry_sdk/scrubber.py index 69e2f02d05..6480032536 100644 --- a/sentry_sdk/scrubber.py +++ b/sentry_sdk/scrubber.py @@ -147,9 +147,9 @@ def scrub_breadcrumbs(self, event): if "values" in event["breadcrumbs"]: if ( isinstance(event["breadcrumbs"], AnnotatedValue) - and event["breadcrumbs"]["values"].value is not None + and event["breadcrumbs"].value["values"] is not None ): - for value in event["breadcrumbs"].value: + for value in event["breadcrumbs"].value["values"]: if "data" in value: self.scrub_dict(value["data"]) else: From de33f6e7ed84c49b7451e1f25bac01400e64bac6 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Thu, 3 Apr 2025 13:30:02 +0200 Subject: [PATCH 20/23] simplify scrubbing of breadcrumbs - annotatedvalue is added afterwards --- sentry_sdk/scrubber.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/sentry_sdk/scrubber.py b/sentry_sdk/scrubber.py index 6480032536..1df5573798 100644 --- a/sentry_sdk/scrubber.py +++ b/sentry_sdk/scrubber.py @@ -145,17 +145,9 @@ def scrub_breadcrumbs(self, event): with capture_internal_exceptions(): if "breadcrumbs" in event: if "values" in event["breadcrumbs"]: - if ( - isinstance(event["breadcrumbs"], AnnotatedValue) - and event["breadcrumbs"].value["values"] is not None - ): - for value in event["breadcrumbs"].value["values"]: - if "data" in value: - self.scrub_dict(value["data"]) - else: - for value in event["breadcrumbs"]["values"]: - if "data" in value: - self.scrub_dict(value["data"]) + for value in event["breadcrumbs"]["values"]: + if "data" in value: + self.scrub_dict(value["data"]) def scrub_frames(self, event): # type: (Event) -> None From 24a4270e1d67b60ca0df19e323580edb05d84431 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Thu, 3 Apr 2025 14:11:22 +0200 Subject: [PATCH 21/23] fix type cohesion --- sentry_sdk/_types.py | 21 +++++++++++++++++++++ sentry_sdk/scrubber.py | 5 ++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index 9bcb5a61f9..01fe243413 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -41,6 +41,27 @@ def __len__(self): else: return 0 + def __getitem__(self, key): + # type: (Any) -> Any + if self.value is not None: + return self.value[key] + raise KeyError(key) + + def setdefault(self, key, default=None): + # type: (str, Any) -> Any + if self.value is not None: + return self.value.setdefault(key, default) + return default + + def get(self, key, default=None): + # type: (Any, Any) -> Any + if self.value is not None: + try: + return self.value[key] + except (KeyError, IndexError, TypeError): + return default + return default + @classmethod def removed_because_raw_data(cls): # type: () -> AnnotatedValue diff --git a/sentry_sdk/scrubber.py b/sentry_sdk/scrubber.py index 1df5573798..b0576c7e95 100644 --- a/sentry_sdk/scrubber.py +++ b/sentry_sdk/scrubber.py @@ -144,7 +144,10 @@ def scrub_breadcrumbs(self, event): # type: (Event) -> None with capture_internal_exceptions(): if "breadcrumbs" in event: - if "values" in event["breadcrumbs"]: + if ( + not isinstance(event["breadcrumbs"], AnnotatedValue) + and "values" in event["breadcrumbs"] + ): for value in event["breadcrumbs"]["values"]: if "data" in value: self.scrub_dict(value["data"]) From b2d297df29dd7bec80c8a480c36104ab5a5ee236 Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Thu, 3 Apr 2025 15:37:04 +0200 Subject: [PATCH 22/23] trying something --- sentry_sdk/_types.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index 01fe243413..9bcb5a61f9 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -41,27 +41,6 @@ def __len__(self): else: return 0 - def __getitem__(self, key): - # type: (Any) -> Any - if self.value is not None: - return self.value[key] - raise KeyError(key) - - def setdefault(self, key, default=None): - # type: (str, Any) -> Any - if self.value is not None: - return self.value.setdefault(key, default) - return default - - def get(self, key, default=None): - # type: (Any, Any) -> Any - if self.value is not None: - try: - return self.value[key] - except (KeyError, IndexError, TypeError): - return default - return default - @classmethod def removed_because_raw_data(cls): # type: () -> AnnotatedValue From e9a5e51a1ab15486954a91a0401134c32dcd61f2 Mon Sep 17 00:00:00 2001 From: Simon Hellmayr Date: Thu, 3 Apr 2025 16:43:31 +0200 Subject: [PATCH 23/23] make mypy happy --- sentry_sdk/client.py | 9 +++++++-- sentry_sdk/scope.py | 21 ++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index ac477593ef..4dfccb3132 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -536,9 +536,14 @@ def _prepare_event( if dropped_spans > 0: previous_total_spans = spans_before + dropped_spans if scope._n_breadcrumbs_truncated > 0: + breadcrumbs = event.get("breadcrumbs", {}) + values = ( + breadcrumbs.get("values", []) + if not isinstance(breadcrumbs, AnnotatedValue) + else [] + ) previous_total_breadcrumbs = ( - len(event.get("breadcrumbs", {}).get("values", [])) - + scope._n_breadcrumbs_truncated + len(values) + scope._n_breadcrumbs_truncated ) if ( diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index 5a0bbcea80..f346569255 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -9,6 +9,7 @@ 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 @@ -1371,17 +1372,23 @@ def _apply_level_to_event(self, event, hint, options): 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