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