1
1
import base64
2
+ import functools
2
3
import json
3
4
import linecache
4
5
import logging
77
78
FALSY_ENV_VALUES = frozenset (("false" , "f" , "n" , "no" , "off" , "0" ))
78
79
TRUTHY_ENV_VALUES = frozenset (("true" , "t" , "y" , "yes" , "on" , "1" ))
79
80
81
+ MAX_STACK_FRAMES = 2000
82
+ """Maximum number of stack frames to send to Sentry.
83
+
84
+ If we have more than this number of stack frames, we will stop processing
85
+ the stacktrace to avoid getting stuck in a long-lasting loop. This value
86
+ exceeds the default sys.getrecursionlimit() of 1000, so users will only
87
+ be affected by this limit if they have a custom recursion limit.
88
+ """
89
+
80
90
81
91
def env_to_bool (value , * , strict = False ):
82
92
# type: (Any, Optional[bool]) -> bool | None
@@ -667,7 +677,7 @@ def single_exception_from_error_tuple(
667
677
source = None , # type: Optional[str]
668
678
full_stack = None , # type: Optional[list[dict[str, Any]]]
669
679
):
670
- # type: (...) -> Dict[str, Any]
680
+ # type: (...) -> Annotated[ Dict[str, Any] ]
671
681
"""
672
682
Creates a dict that goes into the events `exception.values` list and is ingestible by Sentry.
673
683
@@ -732,10 +742,15 @@ def single_exception_from_error_tuple(
732
742
max_value_length = max_value_length ,
733
743
custom_repr = custom_repr ,
734
744
)
735
- for tb in iter_stacks (tb )
745
+ for tb , _ in zip ( iter_stacks (tb ), range ( MAX_STACK_FRAMES + 1 ) )
736
746
] # type: List[Dict[str, Any]]
737
747
738
- if frames :
748
+ if len (frames ) > MAX_STACK_FRAMES :
749
+ exception_value ["stacktrace" ] = AnnotatedValue .removed_because_over_size_limit (
750
+ value = {}
751
+ )
752
+
753
+ elif frames :
739
754
if not full_stack :
740
755
new_frames = frames
741
756
else :
@@ -798,7 +813,7 @@ def exceptions_from_error(
798
813
source = None , # type: Optional[str]
799
814
full_stack = None , # type: Optional[list[dict[str, Any]]]
800
815
):
801
- # type: (...) -> Tuple[int, List[Dict[str, Any]]]
816
+ # type: (...) -> Tuple[int, List[Annotated[ Dict[str, Any] ]]]
802
817
"""
803
818
Creates the list of exceptions.
804
819
This can include chained exceptions and exceptions from an ExceptionGroup.
@@ -894,7 +909,7 @@ def exceptions_from_error_tuple(
894
909
mechanism = None , # type: Optional[Dict[str, Any]]
895
910
full_stack = None , # type: Optional[list[dict[str, Any]]]
896
911
):
897
- # type: (...) -> List[Dict[str, Any]]
912
+ # type: (...) -> List[Annotated[ Dict[str, Any] ]]
898
913
exc_type , exc_value , tb = exc_info
899
914
900
915
is_exception_group = BaseExceptionGroup is not None and isinstance (
@@ -941,7 +956,7 @@ def to_string(value):
941
956
942
957
943
958
def iter_event_stacktraces (event ):
944
- # type: (Event) -> Iterator[Dict[str, Any]]
959
+ # type: (Event) -> Iterator[Annotated[ Dict[str, Any] ]]
945
960
if "stacktrace" in event :
946
961
yield event ["stacktrace" ]
947
962
if "threads" in event :
@@ -950,20 +965,26 @@ def iter_event_stacktraces(event):
950
965
yield thread ["stacktrace" ]
951
966
if "exception" in event :
952
967
for exception in event ["exception" ].get ("values" ) or ():
953
- if "stacktrace" in exception :
968
+ if isinstance ( exception , dict ) and "stacktrace" in exception :
954
969
yield exception ["stacktrace" ]
955
970
956
971
957
972
def iter_event_frames (event ):
958
973
# type: (Event) -> Iterator[Dict[str, Any]]
959
974
for stacktrace in iter_event_stacktraces (event ):
975
+ if isinstance (stacktrace , AnnotatedValue ):
976
+ stacktrace = stacktrace .value or {}
977
+
960
978
for frame in stacktrace .get ("frames" ) or ():
961
979
yield frame
962
980
963
981
964
982
def handle_in_app (event , in_app_exclude = None , in_app_include = None , project_root = None ):
965
983
# type: (Event, Optional[List[str]], Optional[List[str]], Optional[str]) -> Event
966
984
for stacktrace in iter_event_stacktraces (event ):
985
+ if isinstance (stacktrace , AnnotatedValue ):
986
+ stacktrace = stacktrace .value or {}
987
+
967
988
set_in_app_in_frames (
968
989
stacktrace .get ("frames" ),
969
990
in_app_exclude = in_app_exclude ,
0 commit comments