Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Looking to upgrade from Sentry SDK 2.x to 3.x? Here's a comprehensive list of wh
- The `@trace` decorator doesn't accept a `template` parameter anymore.
- The option `attach_stacktrace` is now `True` by default, meaning the SDK will attach stack traces to messages.
- `add_attachment` no longer accepts an `add_to_transactions` argument.
- Cron check-ins no longer go through `before_send`. Use the new `before_send_check_in` option to modify or drop check-ins before they're sent.
- If a `before_breadcrumb` callback, an event processor, or an error processor raises an exception, the breadcrumb or event is now dropped. Previously, the SDK would log the exception and continue processing the unmodified breadcrumb or event.
- The top-level manual tracing API is now wired to span streaming tracing:
- `sentry_sdk.start_transaction` doesn't exist anymore. Use `sentry_sdk.start_span` instead.
Expand Down
12 changes: 10 additions & 2 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,13 @@ def _prepare_event(
),
)

before_send = self.options["before_send"]
if is_checkin:
before_send = self.options["before_send_check_in"]
data_category: "EventDataCategory" = "monitor"
else:
before_send = self.options["before_send"]
data_category = "error"

if before_send is not None and event is not None:
new_event = None
exception_raised_in_before_send = False
Expand All @@ -565,7 +571,9 @@ def _prepare_event(
if exception_raised_in_before_send
else "before_send"
)
self.transport.record_lost_event(reason, data_category="error")
self.transport.record_lost_event(
reason, data_category=data_category
)

event = new_event

Expand Down
5 changes: 5 additions & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,7 @@ def __init__(
before_send_log: "Optional[Callable[[Log, Hint], Optional[Log]]]" = None,
before_send_metric: "Optional[Callable[[Metric, Hint], Optional[Metric]]]" = None,
before_send_span: "Optional[Callable[[SpanJSON, Hint], Optional[SpanJSON]]]" = None,
before_send_check_in: "Optional[EventProcessor]" = None,
org_id: "Optional[str]" = None,
strict_trace_continuation: bool = False,
) -> None:
Expand Down Expand Up @@ -1968,6 +1969,10 @@ def __init__(
Modifications to the span's attributes and name will be retained. Unlike ``before_send_log``
and ``before_send_metric``, spans cannot be dropped by returning None.

:param before_send_check_in: An optional function to modify or filter out cron check-ins before they're
sent to Sentry. Check-ins don't go through `before_send`. Any modifications to the check-in in this
function will be retained. If the function returns None, the check-in will not be sent to Sentry.

:param ignore_spans: A sequence of span-matching rules. Matching spans are ignored.

:param _experiments: Dictionary of experimental, opt-in features that are not yet stable.
Expand Down
55 changes: 51 additions & 4 deletions tests/test_crons.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,22 +325,69 @@ def test_capture_checkin_sdk_not_initialized():
assert check_in_id is None


def test_capture_checkin_dropped_by_before_send(sentry_init, capture_envelopes):
sentry_init(before_send=lambda event, hint: None)
def test_capture_checkin_dropped_by_before_send_check_in(
sentry_init, capture_envelopes, capture_record_lost_event_calls
):
sentry_init(before_send_check_in=lambda check_in, hint: None)
envelopes = capture_envelopes()
record_lost_event_calls = capture_record_lost_event_calls()

check_in_id = capture_checkin(monitor_slug="abc123", status="in_progress")

assert check_in_id is None
assert envelopes == []
assert record_lost_event_calls == [("before_send", "monitor", None, 1)]


def test_before_send_check_in_only_applies_to_check_ins(sentry_init, capture_envelopes):
def before_send(event, hint):
event["extra"] = {"before_send_called": True}
return event

def before_send_check_in(check_in, hint):
check_in["environment"] = "from_before_send_check_in"
return check_in

sentry_init(before_send=before_send, before_send_check_in=before_send_check_in)
envelopes = capture_envelopes()

capture_checkin(monitor_slug="abc123", status="ok")
sentry_sdk.capture_message("hello")

check_in_envelope, event_envelope = envelopes

check_in = check_in_envelope.items[0].payload.json
assert check_in["monitor_slug"] == "abc123"
assert check_in["environment"] == "from_before_send_check_in"
assert "extra" not in check_in

event = event_envelope.items[0].payload.json
assert event["message"] == "hello"
assert event["extra"] == {"before_send_called": True}
assert event["environment"] != "from_before_send_check_in"


def test_event_processors_not_applied_to_check_ins(sentry_init, capture_envelopes):
def event_processor(event, hint):
event["extra"] = {"event_processor_called": True}
return event

sentry_init()
sentry_sdk.get_isolation_scope().add_event_processor(event_processor)
envelopes = capture_envelopes()

capture_checkin(monitor_slug="abc123", status="ok")

(envelope,) = envelopes
assert "extra" not in envelope.items[0].payload.json


def test_context_monitor_exit_successfully_sends_checkin_when_enter_checkin_dropped(
sentry_init, capture_envelopes
):
sentry_init(
before_send=lambda event, hint: (
None if event.get("status") == "in_progress" else event
before_send_check_in=lambda check_in, hint: (
None if check_in.get("status") == "in_progress" else check_in
)
)
envelopes = capture_envelopes()
Expand Down
Loading