diff --git a/codecov.yml b/codecov.yml index 1989f1cd03..1811996ac4 100644 --- a/codecov.yml +++ b/codecov.yml @@ -7,3 +7,6 @@ coverage: python: target: 90% comment: false +ignore: + - "tests" + - "sentry_sdk/_types.py" diff --git a/sentry_sdk/_types.py b/sentry_sdk/_types.py index 3c985f21e9..7064192977 100644 --- a/sentry_sdk/_types.py +++ b/sentry_sdk/_types.py @@ -30,6 +30,7 @@ EventProcessor = Callable[[Event, Hint], Optional[Event]] ErrorProcessor = Callable[[Event, ExcInfo], Optional[Event]] BreadcrumbProcessor = Callable[[Breadcrumb, BreadcrumbHint], Optional[Breadcrumb]] + TransactionProcessor = Callable[[Event, Hint], Optional[Event]] TracesSampler = Callable[[SamplingContext], Union[float, int, bool]] diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index 8af7003156..e5df64fbfb 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -248,6 +248,19 @@ def _prepare_event( ) event = new_event # type: ignore + before_send_transaction = self.options["before_send_transaction"] + if before_send_transaction is not None and event.get("type") == "transaction": + new_event = None + with capture_internal_exceptions(): + new_event = before_send_transaction(event, hint or {}) + if new_event is None: + logger.info("before send transaction dropped event (%s)", event) + if self.transport: + self.transport.record_lost_event( + "before_send", data_category="transaction" + ) + event = new_event # type: ignore + return event def _is_ignored_error(self, event, hint): diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index eeca4cbaf4..db50e058f4 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -20,6 +20,7 @@ Event, EventProcessor, TracesSampler, + TransactionProcessor, ) # Experiments are feature flags to enable and disable certain unstable SDK @@ -117,6 +118,7 @@ def __init__( _experiments={}, # type: Experiments # noqa: B006 proxy_headers=None, # type: Optional[Dict[str, str]] instrumenter=INSTRUMENTER.SENTRY, # type: Optional[str] + before_send_transaction=None, # type: Optional[TransactionProcessor] ): # type: (...) -> None pass diff --git a/tests/test_basics.py b/tests/test_basics.py index 8657231fc9..0d87e049eb 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -91,7 +91,79 @@ def test_event_id(sentry_init, capture_events): assert Hub.current.last_event_id() == event_id -def test_option_callback(sentry_init, capture_events, monkeypatch): +def test_option_before_send(sentry_init, capture_events): + def before_send(event, hint): + event["extra"] = {"before_send_called": True} + return event + + def do_this(): + try: + raise ValueError("aha!") + except Exception: + capture_exception() + + sentry_init(before_send=before_send) + events = capture_events() + + do_this() + + (event,) = events + assert event["extra"] == {"before_send_called": True} + + +def test_option_before_send_discard(sentry_init, capture_events): + def before_send_discard(event, hint): + return None + + def do_this(): + try: + raise ValueError("aha!") + except Exception: + capture_exception() + + sentry_init(before_send=before_send_discard) + events = capture_events() + + do_this() + + assert len(events) == 0 + + +def test_option_before_send_transaction(sentry_init, capture_events): + def before_send_transaction(event, hint): + assert event["type"] == "transaction" + event["extra"] = {"before_send_transaction_called": True} + return event + + sentry_init( + before_send_transaction=before_send_transaction, + traces_sample_rate=1.0, + ) + events = capture_events() + transaction = start_transaction(name="foo") + transaction.finish() + + (event,) = events + assert event["transaction"] == "foo" + assert event["extra"] == {"before_send_transaction_called": True} + + +def test_option_before_send_transaction_discard(sentry_init, capture_events): + def before_send_transaction_discard(event, hint): + return None + + sentry_init( + before_send_transaction=before_send_transaction_discard, + traces_sample_rate=1.0, + ) + events = capture_events() + transaction = start_transaction(name="foo") + transaction.finish() + + assert len(events) == 0 + + +def test_option_before_breadcrumb(sentry_init, capture_events, monkeypatch): drop_events = False drop_breadcrumbs = False reports = []