diff --git a/ddtrace/debugging/_exception/replay.py b/ddtrace/debugging/_exception/replay.py index 080b4cbfc61..c9da69bb5b2 100644 --- a/ddtrace/debugging/_exception/replay.py +++ b/ddtrace/debugging/_exception/replay.py @@ -21,6 +21,7 @@ from ddtrace.internal.rate_limiter import BudgetRateLimiterWithJitter as RateLimiter from ddtrace.internal.rate_limiter import RateLimitExceeded from ddtrace.internal.utils.time import HourGlass +from ddtrace.settings.exception_replay import config log = get_logger(__name__) @@ -225,7 +226,9 @@ def on_span_exception( seq = count(1) # 1-based sequence number - while chain: + frames_captured = 0 + + while chain and frames_captured <= config.max_frames: exc, _tb = chain.pop() # LIFO: reverse the chain if _tb is None or _tb.tb_frame is None: @@ -233,7 +236,7 @@ def on_span_exception( continue # DEV: We go from the handler up to the root exception - while _tb: + while _tb and frames_captured <= config.max_frames: frame = _tb.tb_frame code = frame.f_code seq_nr = next(seq) @@ -263,6 +266,9 @@ def on_span_exception( # Memoize frame.f_locals[SNAPSHOT_KEY] = snapshot_id = snapshot.uuid + # Count + frames_captured += 1 + # Add correlation tags on the span span.set_tag_str(FRAME_SNAPSHOT_ID_TAG % seq_nr, snapshot_id) span.set_tag_str(FRAME_FUNCTION_TAG % seq_nr, code.co_name) diff --git a/ddtrace/settings/exception_replay.py b/ddtrace/settings/exception_replay.py index c78ae29b73d..d714e623481 100644 --- a/ddtrace/settings/exception_replay.py +++ b/ddtrace/settings/exception_replay.py @@ -14,6 +14,12 @@ class ExceptionReplayConfig(En): help="Enable automatic capturing of exception debugging information", deprecations=[("debugging.enabled", None, "3.0")], ) + max_frames = En.v( + "replay.capture_max_frames", + default=float("inf"), + help_type="int", + help="The maximum number of frames to capture for each exception", + ) config = ExceptionReplayConfig()