Skip to content

Commit 22f62b0

Browse files
authored
fix(breadcrumbs): Fix sorting (#3511)
- best-effort coerce string timestamps into datetimes before sorting - ignore errors while breadcrumb sorting (better to have unsorted crumbs than breaking anything)
1 parent 0fb04be commit 22f62b0

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

sentry_sdk/scope.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
capture_internal_exception,
3131
capture_internal_exceptions,
3232
ContextVar,
33+
datetime_from_isoformat,
3334
disable_capture_event,
3435
event_from_exception,
3536
exc_info_from_error,
@@ -1307,7 +1308,16 @@ def _apply_breadcrumbs_to_event(self, event, hint, options):
13071308
event.setdefault("breadcrumbs", {}).setdefault("values", []).extend(
13081309
self._breadcrumbs
13091310
)
1310-
event["breadcrumbs"]["values"].sort(key=lambda crumb: crumb["timestamp"])
1311+
1312+
# Attempt to sort timestamps
1313+
try:
1314+
for crumb in event["breadcrumbs"]["values"]:
1315+
if isinstance(crumb["timestamp"], str):
1316+
crumb["timestamp"] = datetime_from_isoformat(crumb["timestamp"])
1317+
1318+
event["breadcrumbs"]["values"].sort(key=lambda crumb: crumb["timestamp"])
1319+
except Exception:
1320+
pass
13111321

13121322
def _apply_user_to_event(self, event, hint, options):
13131323
# type: (Event, Hint, Optional[Dict[str, Any]]) -> None

sentry_sdk/utils.py

+9
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,15 @@ def format_timestamp(value):
239239
return utctime.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
240240

241241

242+
def datetime_from_isoformat(value):
243+
# type: (str) -> datetime
244+
try:
245+
return datetime.fromisoformat(value)
246+
except AttributeError:
247+
# py 3.6
248+
return datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%f")
249+
250+
242251
def event_hint_with_exc_info(exc_info=None):
243252
# type: (Optional[ExcInfo]) -> Dict[str, Optional[ExcInfo]]
244253
"""Creates a hint with the exc info filled in."""

tests/test_basics.py

+31
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,37 @@ def test_breadcrumb_ordering(sentry_init, capture_events):
425425
assert timestamps_from_event == sorted(timestamps)
426426

427427

428+
def test_breadcrumb_ordering_different_types(sentry_init, capture_events):
429+
sentry_init()
430+
events = capture_events()
431+
432+
timestamps = [
433+
datetime.datetime.now() - datetime.timedelta(days=10),
434+
datetime.datetime.now() - datetime.timedelta(days=8),
435+
datetime.datetime.now() - datetime.timedelta(days=12),
436+
]
437+
438+
for i, timestamp in enumerate(timestamps):
439+
add_breadcrumb(
440+
message="Authenticated at %s" % timestamp,
441+
category="auth",
442+
level="info",
443+
timestamp=timestamp if i % 2 == 0 else timestamp.isoformat(),
444+
)
445+
446+
capture_exception(ValueError())
447+
(event,) = events
448+
449+
assert len(event["breadcrumbs"]["values"]) == len(timestamps)
450+
timestamps_from_event = [
451+
datetime.datetime.strptime(
452+
x["timestamp"].replace("Z", ""), "%Y-%m-%dT%H:%M:%S.%f"
453+
)
454+
for x in event["breadcrumbs"]["values"]
455+
]
456+
assert timestamps_from_event == sorted(timestamps)
457+
458+
428459
def test_attachments(sentry_init, capture_envelopes):
429460
sentry_init()
430461
envelopes = capture_envelopes()

0 commit comments

Comments
 (0)