Skip to content

Commit 5ae51f8

Browse files
authored
fix: Port exception chains from raven (getsentry#244)
1 parent 45c5d6f commit 5ae51f8

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

sentry_sdk/utils.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -435,18 +435,40 @@ def single_exception_from_error_tuple(
435435
}
436436

437437

438-
def walk_exception_chain(exc_info):
439-
exc_type, exc_value, tb = exc_info
438+
HAS_CHAINED_EXCEPTIONS = hasattr(Exception, "__suppress_context__")
439+
440+
if HAS_CHAINED_EXCEPTIONS:
441+
442+
def walk_exception_chain(exc_info):
443+
exc_type, exc_value, tb = exc_info
444+
445+
seen_exceptions = []
446+
seen_exception_ids = set()
447+
448+
while exc_type is not None and id(exc_value) not in seen_exception_ids:
449+
yield exc_type, exc_value, tb
440450

441-
while exc_type is not None:
442-
yield exc_type, exc_value, tb
451+
# Avoid hashing random types we don't know anything
452+
# about. Use the list to keep a ref so that the `id` is
453+
# not used for another object.
454+
seen_exceptions.append(exc_value)
455+
seen_exception_ids.add(id(exc_value))
456+
457+
if exc_value.__suppress_context__:
458+
cause = exc_value.__cause__
459+
else:
460+
cause = exc_value.__context__
461+
if cause is None:
462+
break
463+
exc_type = type(cause)
464+
exc_value = cause
465+
tb = getattr(cause, "__traceback__", None)
466+
467+
468+
else:
443469

444-
cause = getattr(exc_value, "__cause__", None)
445-
if cause is None:
446-
break
447-
exc_type = type(cause)
448-
exc_value = cause
449-
tb = getattr(cause, "__traceback__", None)
470+
def walk_exception_chain(exc_info):
471+
yield exc_info
450472

451473

452474
def exceptions_from_error_tuple(exc_info, client_options=None, mechanism=None):

tests/test_client.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from sentry_sdk.hub import HubMeta
2020
from sentry_sdk.transport import Transport
2121
from sentry_sdk._compat import reraise, text_type
22+
from sentry_sdk.utils import HAS_CHAINED_EXCEPTIONS
2223

2324

2425
class EventCaptured(Exception):
@@ -365,3 +366,21 @@ def test_databag_stripping(sentry_init, capture_events):
365366
event, = events
366367

367368
assert len(json.dumps(event)) < 10000
369+
370+
371+
@pytest.mark.skipif(not HAS_CHAINED_EXCEPTIONS, reason="Only works on 3.3+")
372+
def test_chained_exceptions(sentry_init, capture_events):
373+
sentry_init()
374+
events = capture_events()
375+
376+
try:
377+
try:
378+
1 / 0
379+
except Exception:
380+
1 / 0
381+
except Exception:
382+
capture_exception()
383+
384+
event, = events
385+
386+
assert len(event["exception"]["values"]) == 2

0 commit comments

Comments
 (0)