diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index a89a63bf5d..1df73bab30 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -655,11 +655,15 @@ def get_errno(exc_value): def get_error_message(exc_value): # type: (Optional[BaseException]) -> str - return ( + value = ( getattr(exc_value, "message", "") or getattr(exc_value, "detail", "") or safe_str(exc_value) ) + notes = getattr(exc_value, "__notes__", []) + if notes: + value = "\n".join([value] + [safe_str(note) for note in notes]) + return value def single_exception_from_error_tuple( diff --git a/tests/test_basics.py b/tests/test_basics.py index bf42634710..0e3ad0668d 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -778,3 +778,47 @@ def test_classmethod_tracing(sentry_init): with patch_start_tracing_child() as fake_start_child: assert instance_or_class.class_(1) == (TracingTestClass, 1) assert fake_start_child.call_count == 1 + + +@pytest.mark.skipif(sys.version_info < (3, 11), reason="add_note() not supported") +def test_notes(sentry_init, capture_events): + sentry_init() + events = capture_events() + try: + e = ValueError("aha!") + e.add_note("Test 123") + raise e + except Exception: + capture_exception() + + (event,) = events + + assert event["exception"]["values"][0]["value"] == "aha!\nTest 123" + + +@pytest.mark.skipif(sys.version_info < (3, 11), reason="add_note() not supported") +def test_notes_safe_str(sentry_init, capture_events): + class Note2: + def __repr__(self): + raise TypeError + + def __str__(self): + raise TypeError + + sentry_init() + events = capture_events() + try: + e = ValueError("aha!") + e.add_note("note 1") + e.__notes__.append(Note2()) # type: ignore + e.add_note("note 3") + raise e + except Exception: + capture_exception() + + (event,) = events + + assert ( + event["exception"]["values"][0]["value"] + == "aha!\nnote 1\n\nnote 3" + )