Skip to content

feat(session-replay): embed crash event breadcrumbs into replay recordings#1875

Merged
tustanivsky merged 9 commits into
masterfrom
feat/session-replay-breadcrumbs
Jul 17, 2026
Merged

feat(session-replay): embed crash event breadcrumbs into replay recordings#1875
tustanivsky merged 9 commits into
masterfrom
feat/session-replay-breadcrumbs

Conversation

@tustanivsky

@tustanivsky tustanivsky commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

This PR adds breadcrumbs to session replay recordings: breadcrumbs carried by the crash event that fall inside the replay window are converted into rrweb breadcrumb custom events and embedded into the replay_recording payload, matching how the Cocoa and Android SDKs surface breadcrumbs on the replay timeline.

Key changes

  • New internal sentry__value_from_msgpack_stream decodes append-only msgpack streams (like the breadcrumb ring files) into a list even when the buffer holds a single value; the crash daemon's ring-file reader and report_to_envelope now use it. sentry__value_from_msgpack rejects buffers holding concatenated values instead of implicitly wrapping them in a list, so each call site declares its intent. This also fixes report_to_envelope dropping breadcrumbs when a ring file holds exactly one entry.
  • sentry__session_replay_flush_pending embeds the crash event's in-window breadcrumbs into the rrweb recording as type-5 custom events with tag: "breadcrumb" (outer timestamps in ms, payload timestamps in seconds, chronological order). The breakpad and inproc backends pick this up without further changes since their crash event already carries the scope breadcrumbs.
  • Crashpad: the first-chance handler merges the __sentry-breadcrumb1/2 ring files onto the in-memory crash event before flushing the staged replay; the on-disk __sentry-event and the regular crash delivery path are unaffected.
  • Native crash daemon: applies its existing ring-file merge to the crash event copy used for the replay flush (the __sentry-event snapshot is scope-applied without breadcrumbs).

Testing

  • New value_from_msgpack_stream unit test.
  • The shared replay-envelope assertion now verifies that the example's breadcrumbs are embedded in the recording with the expected payload fields, timestamp units, replay-window bounds, and ordering. This extends the existing replay integration tests covering the crashpad, breakpad, inproc, and native daemon backends.
  • Verified end-to-end via sentry-unreal on Windows: manually added breadcrumbs show up on the replay timeline.

`sentry__value_from_msgpack` decodes a buffer holding a single value to
that bare value, so consumers of append-only files like the breadcrumb
ring files had to wrap single objects manually. Add
`sentry__value_from_msgpack_stream` which always returns a list and use
it in the crash daemon's breadcrumb ring reader.
Convert the breadcrumbs carried by the crash event that fall inside the
replay window into rrweb `breadcrumb` custom events and append them to
the `replay_recording` payload, matching how the Cocoa and Android SDKs
surface breadcrumbs on the replay timeline. The breakpad and inproc
backends already pass a crash event with scope breadcrumbs applied, so
they pick this up without further changes.
The crashpad handler applies the scope to the crash event without
breadcrumbs since those are streamed to the `__sentry-breadcrumb1/2`
ring files on the hot path. Read and merge the ring files onto the
in-memory crash event before flushing the staged session replay, so the
replay recording can embed them. The on-disk `__sentry-event` and the
regular crash delivery path are unaffected.
The crash event the daemon re-reads from `__sentry-event` for the
session replay flush is scope-applied without breadcrumbs; those only
get merged from the `__sentry-breadcrumb1/2` ring files into the
in-memory event used for the crash envelope. Apply the same merge to
the replay flush copy so the replay recording can embed the
breadcrumbs.
The example already adds three breadcrumbs in its default setup before
crashing, so extend the shared replay envelope assertion to verify they
are embedded in the recording as rrweb `breadcrumb` custom events with
correct payload fields, ms/s timestamp duality, replay window bounds,
and chronological ordering. Covers the crashpad, breakpad, inproc and
native daemon backends via the existing replay tests.
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 274a2a8

tustanivsky added a commit to getsentry/sentry-unreal that referenced this pull request Jul 16, 2026
Temporary pin to getsentry/sentry-native#1875 so CI builds binaries
that embed breadcrumbs into crash replay recordings; revert to a
tagged release once it ships.
Comment thread src/sentry_value.h Outdated
Now that stream consumers use sentry__value_from_msgpack_stream, the
implicit wrap-multiple-values-in-a-list behavior only obscures misuse.
Require a single value spanning the whole buffer and decode the
breadcrumb ring files in report_to_envelope with the stream variant,
which also stops dropping breadcrumbs when a ring file holds a single
entry.
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.69903% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.54%. Comparing base (034e49d) to head (274a2a8).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1875   +/-   ##
=======================================
  Coverage   75.54%   75.54%           
=======================================
  Files          90       90           
  Lines       21043    21127   +84     
  Branches     3737     3751   +14     
=======================================
+ Hits        15897    15961   +64     
- Misses       4324     4342   +18     
- Partials      822      824    +2     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/backends/sentry_backend_crashpad.cpp Outdated
The handler runs in-process, so the scope ring buffer is available
directly - no need to read the ring files back; those remain for the
out-of-process daemon and next-launch report processing. This also
matches how breakpad and inproc get breadcrumbs onto crash events.
@tustanivsky
tustanivsky merged commit da09e85 into master Jul 17, 2026
67 checks passed
@tustanivsky
tustanivsky deleted the feat/session-replay-breadcrumbs branch July 17, 2026 09:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants