feat: Added cycle detection (#236) · pythonthings/sentry-python@fe9fa1d · GitHub
Skip to content

Commit fe9fa1d

Browse files
mitsuhikountitaker
authored andcommitted
feat: Added cycle detection (getsentry#236)
* feat: Added cycle detection * fix: Bugs in cycle detector * test: Simple cycle test * test: Better test * fix: Implement cycle detector for frame vars * fix: Linting
1 parent d5e0680 commit fe9fa1d

3 files changed

Lines changed: 88 additions & 8 deletions

File tree

sentry_sdk/client.py

Lines changed: 10 additions & 7 deletions

sentry_sdk/utils.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
# The logger is created here but initialized in the debug support module
3232
logger = logging.getLogger("sentry_sdk.errors")
3333

34+
CYCLE_MARKER = object()
35+
3436

3537
def _get_debug_hub():
3638
# This function is replaced by debug.py
@@ -312,9 +314,13 @@ def _walk(obj, depth):
312314
return [_walk(x, depth + 1) for x in obj]
313315
if isinstance(obj, Mapping):
314316
return {safe_str(k): _walk(v, depth + 1) for k, v in obj.items()}
317+
318+
if obj is CYCLE_MARKER:
319+
return obj
320+
315321
return safe_repr(obj)
316322

317-
return _walk(obj, 0)
323+
return _walk(break_cycles(obj), 0)
318324

319325

320326
def extract_locals(frame):
@@ -615,7 +621,26 @@ def strip_frame_mut(frame):
615621
frame["vars"] = strip_databag(frame["vars"])
616622

617623

624+
def break_cycles(obj, memo=None):
625+
if memo is None:
626+
memo = {}
627+
if id(obj) in memo:
628+
return CYCLE_MARKER
629+
memo[id(obj)] = obj
630+
631+
try:
632+
if isinstance(obj, Mapping):
633+
return {k: break_cycles(v, memo) for k, v in obj.items()}
634+
if isinstance(obj, Sequence) and not isinstance(obj, (text_type, bytes)):
635+
return [break_cycles(v, memo) for v in obj]
636+
return obj
637+
finally:
638+
del memo[id(obj)]
639+
640+
618641
def convert_types(obj):
642+
if obj is CYCLE_MARKER:
643+
return u"<cyclic>"
619644
if isinstance(obj, datetime):
620645
return obj.strftime("%Y-%m-%dT%H:%M:%SZ")
621646
if isinstance(obj, Mapping):

tests/test_client.py

Lines changed: 52 additions & 0 deletions

0 commit comments

Comments
 (0)