Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bring back last_event_id #3057

Closed
wants to merge 5 commits into from
Closed
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 sentry_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"is_initialized",
"isolation_scope",
"new_scope",
"last_event_id",
"push_scope",
"set_context",
"set_extra",
Expand Down
7 changes: 7 additions & 0 deletions sentry_sdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def overload(x):
"is_initialized",
"isolation_scope",
"new_scope",
"last_event_id",
"push_scope",
"set_context",
"set_extra",
Expand Down Expand Up @@ -375,3 +376,9 @@ def continue_trace(environ_or_headers, op=None, name=None, source=None):
return Scope.get_isolation_scope().continue_trace(
environ_or_headers, op, name, source
)


@clientmethod
def last_event_id():
# type: () -> Optional[str]
return get_client().last_event_id()
20 changes: 20 additions & 0 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,16 @@ def flush(self, *args, **kwargs):
# type: (*Any, **Any) -> None
return None

def last_event_id(self):
# type: () -> Optional[str]
"""
.. versionadded:: 2.1.2

Returns the most recently captured error event's ID. If this client has
not captured an error event yet, returns `None`.
"""
return None

def __enter__(self):
# type: () -> BaseClient
return self
Expand Down Expand Up @@ -379,6 +389,8 @@ def _capture_envelope(envelope):
except Exception as e:
logger.debug("Can not set up profiler. (%s)", e)

self._last_event_id = None # type: Optional[str]

finally:
_client_init_debug.set(old_debug)

Expand Down Expand Up @@ -709,6 +721,7 @@ def capture_event(

is_transaction = event_opt.get("type") == "transaction"
is_checkin = event_opt.get("type") == "check_in"
is_error = not is_transaction and not is_checkin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this would also include profiles? Maybe make a check similar to the one for transaction?


if (
not is_transaction
Expand Down Expand Up @@ -750,6 +763,9 @@ def capture_event(
if self.transport is None:
return None

if is_error:
self._last_event_id = event_id
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want last_event_id only to return the ID of the most recent error event? Or, should we expand it to all events? Error event seems like the better option to align with #3049

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think only errors is fine. Because the error ID is important for user feedback form.


self.transport.capture_envelope(envelope)

return event_id
Expand Down Expand Up @@ -820,6 +836,10 @@ def flush(
self.metrics_aggregator.flush()
self.transport.flush(timeout=timeout, callback=callback)

def last_event_id(self):
# type: () -> Optional[str]
return self._last_event_id

def __enter__(self):
# type: () -> _Client
return self
Expand Down
22 changes: 22 additions & 0 deletions tests/test_basics.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
add_breadcrumb,
Hub,
Scope,
last_event_id,
)
from sentry_sdk.integrations import (
_AUTO_ENABLING_INTEGRATIONS,
Expand Down Expand Up @@ -778,3 +779,24 @@ 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


def test_last_event_id(sentry_init):
sentry_init()

assert last_event_id() is None

capture_exception(ValueError("foo"))

assert last_event_id() is not None


def test_last_event_id_transaction(sentry_init):
sentry_init()

assert last_event_id() is None

with start_transaction():
pass

assert last_event_id() is None
65 changes: 65 additions & 0 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
capture_exception,
capture_event,
set_tag,
get_client,
)
from sentry_sdk.client import NonRecordingClient
from sentry_sdk.integrations.executing import ExecutingIntegration
from sentry_sdk.transport import Transport
from sentry_sdk.serializer import MAX_DATABAG_BREADTH
Expand Down Expand Up @@ -1205,3 +1207,66 @@ def test_uwsgi_warnings(sentry_init, recwarn, opt, missing_flags):
assert flag in str(record.message)
else:
assert not recwarn


def test_last_event_id_non_recording():
client = NonRecordingClient()

assert client.last_event_id() is None


def test_last_event_id_nothing_sent(sentry_init):
sentry_init()
client = get_client()

assert client.last_event_id() is None


def test_last_event_id_manually_set(sentry_init):
sentry_init()
client = get_client()

client.capture_event({"event_id": "42"})

assert client.last_event_id() == "42"


def test_last_event_id_auto_generated(sentry_init):
sentry_init()
client = get_client()

client.capture_event({})

# We can't predict the event ID, but it should be set
assert client.last_event_id() is not None


def test_last_event_id_no_transport(sentry_init):
sentry_init()
client = get_client()
client.transport = None

client.capture_event({"event_id": "42"})

assert client.last_event_id() is None


@pytest.mark.parametrize("type", ("check_in", "transaction"))
def test_last_event_id_not_error(type, sentry_init):
sentry_init()
client = get_client()

client.capture_event({"type": type, "event_id": "42"})

assert client.last_event_id() is None


@pytest.mark.parametrize("type", ("check_in", "transaction"))
def test_last_event_id_not_error_after_error(type, sentry_init):
sentry_init()
client = get_client()

client.capture_event({"event_id": "error_id"})
client.capture_event({"type": type, "event_id": "not_error_id"})

assert client.last_event_id() == "error_id"
Loading