From 79dc55a2274d9baa460839f68ee8a27682f4b2b1 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Mon, 10 Feb 2025 10:20:24 +0100 Subject: [PATCH 1/3] Don't set transaction status to error on sys.exit(0) --- sentry_sdk/tracing.py | 3 ++- sentry_sdk/utils.py | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sentry_sdk/tracing.py b/sentry_sdk/tracing.py index 86456b8964..59473d752c 100644 --- a/sentry_sdk/tracing.py +++ b/sentry_sdk/tracing.py @@ -11,6 +11,7 @@ is_valid_sample_rate, logger, nanosecond_time, + should_be_treated_as_error, ) from typing import TYPE_CHECKING @@ -374,7 +375,7 @@ def __enter__(self): def __exit__(self, ty, value, tb): # type: (Optional[Any], Optional[Any], Optional[Any]) -> None - if value is not None: + if value is not None and should_be_treated_as_error(ty, value): self.set_status(SPANSTATUS.INTERNAL_ERROR) scope, old_span = self._context_manager_state diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 6a0e4579a1..a5faad3b8f 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -1879,3 +1879,11 @@ def get_current_thread_meta(thread=None): # we've tried everything, time to give up return None, None + + +def should_be_treated_as_error(ty, value): + # (Any, Any) -> bool + if ty == SystemExit and value == 0: + return False + + return True From 33d563e0771759df767f650b3831a4dc0d8ad3df Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Mon, 10 Feb 2025 10:46:21 +0100 Subject: [PATCH 2/3] add tests --- sentry_sdk/utils.py | 3 +- tests/tracing/test_integration_tests.py | 58 ++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index a5faad3b8f..e874f60e7a 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -1883,7 +1883,8 @@ def get_current_thread_meta(thread=None): def should_be_treated_as_error(ty, value): # (Any, Any) -> bool - if ty == SystemExit and value == 0: + if ty == SystemExit and hasattr(value, "code") and value.code in (0, None): + # https://docs.python.org/3/library/exceptions.html#SystemExit return False return True diff --git a/tests/tracing/test_integration_tests.py b/tests/tracing/test_integration_tests.py index da3efef9eb..f269023f87 100644 --- a/tests/tracing/test_integration_tests.py +++ b/tests/tracing/test_integration_tests.py @@ -1,8 +1,10 @@ -import weakref import gc +import random import re +import sys +import weakref + import pytest -import random import sentry_sdk from sentry_sdk import ( @@ -297,3 +299,55 @@ def test_trace_propagation_meta_head_sdk(sentry_init): assert 'meta name="baggage"' in baggage baggage_content = re.findall('content="([^"]*)"', baggage)[0] assert baggage_content == transaction.get_baggage().serialize() + + +@pytest.mark.parametrize( + "exception_cls,exception_value", + [ + (SystemExit, 0), + ], +) +def test_non_error_exceptions( + sentry_init, capture_events, exception_cls, exception_value +): + sentry_init(traces_sample_rate=1.0) + events = capture_events() + + with start_transaction(name="hi") as transaction: + transaction.set_status(SPANSTATUS.OK) + with pytest.raises(exception_cls): + with start_span(op="foo", name="foodesc"): + raise exception_cls(exception_value) + + assert len(events) == 1 + event = events[0] + + span = event["spans"][0] + assert "status" not in span.get("tags", {}) + assert "status" not in event["tags"] + assert event["contexts"]["trace"]["status"] == "ok" + + +@pytest.mark.parametrize("exception_value", [None, 0, False]) +def test_good_sysexit_doesnt_fail_transaction( + sentry_init, capture_events, exception_value +): + sentry_init(traces_sample_rate=1.0) + events = capture_events() + + with start_transaction(name="hi") as transaction: + transaction.set_status(SPANSTATUS.OK) + with pytest.raises(SystemExit): + with start_span(op="foo", name="foodesc"): + if exception_value is not False: + sys.exit(exception_value) + else: + sys.exit() + + assert len(events) == 1 + event = events[0] + + span = event["spans"][0] + assert "status" not in span.get("tags", {}) + assert "status" not in event["tags"] + assert event["contexts"]["trace"]["status"] == "ok" From 6ae8b51d1ea745b7d726709ea378a9bd1c8fb6e6 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Mon, 10 Feb 2025 10:50:44 +0100 Subject: [PATCH 3/3] fix type --- sentry_sdk/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index e874f60e7a..f60c31e676 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -1882,7 +1882,7 @@ def get_current_thread_meta(thread=None): def should_be_treated_as_error(ty, value): - # (Any, Any) -> bool + # type: (Any, Any) -> bool if ty == SystemExit and hasattr(value, "code") and value.code in (0, None): # https://docs.python.org/3/library/exceptions.html#SystemExit return False