Repository navigation
fix(rum): report an unattributed replayed crash in a session of its own - #84
Merged
Merged
Conversation
A crash, native crash or freeze replayed on the next launch that nothing attributes to the run it happened in (no original session, no usable last-view snapshot) fell back to the current session whenever that session was collected: written at the current time, counted in whichever view was current, so a session the crash did not happen in read as crashed. With a sample rate of 100 every such crash took this path. Only a withheld (on-error) current session turned it away to a standalone session. Such a crash now always goes to the standalone session written by writeStandaloneCrash (one ApplicationLaunch view plus the error, at the real crash time, ids derived from the incident), and the current session is never touched. The standalone session is drawn independently, as a new session would be at that moment: RumApplicationScope.drawDetachedSession reuses the resolution startNewSession uses (console rate or init value, console sessionOnError, beforeSampling hook, forced sessions). Drawn by the rate it is an ordinary session with the drawn rate and rc_version; kept only by sessionOnError it is marked sampled_for_error with rate 0; otherwise the crash is dropped as sampling drops it and marked handled. The coin is derived from the incident, so a retry after a partial write draws the same way. The inherited-error plumbing (RumRawEvent.inherited, refusedBy, countInView and the matching reportError parameters) is removed: nothing reports an error of a previous run into the scope tree any more. Tests: new cases for a tracked current session, a released on-error session, independent draws through the hook, console settings, no draw without the switch, and retry stability at a fractional rate. Updated tests that encoded the old behaviour: aLaunchCrashStillJoinsACollectedSessionOrFollowsSampling (replaced), aPreviousLaunchCrashInAViewGapStaysOffThisLaunchsViews, and the retry test now also runs with a tracked draw.
… view A JS crash in a session that had not opened a view yet left an incident naming the session but no view. The next launch replayed the error into that session, which had no view document, and the backend builds sessions only from view documents: the crash belonged to a session that never appeared, and a session kept on error released nothing it could join. Before anything snapshots the RUM context for a JS fault, the session now opens the ApplicationLaunch view if it has never had a view. The incident names that view, markCrash counts the crash on it, the replay joins it, and a withheld session releases it with the crash. Live crashes (REPORT_AND_CONTINUE, or no crash module) and OBSERVE_ONLY errors are written in it instead of as viewless errors. It is not remembered as the last view, mints no session, and the app's first view replaces it. A session between two views keeps counting on its last view.
A session that expired (15 minutes idle) without ever opening a view still published its id when a JS fault arrived. The crash incident named it, the fault's own events then expired it with no view document, and the replayed error went into a session that never appears. An unsampled session that had ended left session.sampled=false behind, so a crash after it was dropped as sampled out although it belonged to no session. openLaunchView now withdraws the id of a session that expired without a view before the crash feature snapshots the context, so the crash takes the path of a crash with no session of its own (a session drawn for it). That expired session discards what it held instead of releasing it for a crash that is not its own. The crash feature takes session.sampled into account only while a session id is published.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A crash, native crash or app freeze replayed on the next launch that cannot be attributed to the run it happened in (no original session id, and no usable last-view snapshot — typically a fault during launch before the first view, or an incident past the intake's 24 h window) was injected into the current session whenever that session was collected: written at the current time, counted in whichever view was current. That session did not crash, but read as crashed. With a sample rate of 100 every such crash took this path. Only a withheld (
sessionOnError) current session turned it away to the standalone session added in 0.7.9.Now such a crash always goes to the standalone session written by
writeStandaloneCrash(oneApplicationLaunchview counting the crash + theis_crasherror, real crash time unless past 24 h, ids derived from the incident, view before error, incident deleted only when both land; mapper and consent handling unchanged). The current session is never touched.Sampling of the standalone session
Drawn independently, as a new session would be at that moment.
RumApplicationScope.drawDetachedSessionreuses the resolutionstartNewSessionuses (extracted asresolveNow()/carried()): console rate or init value, consolesessionOnError, thebeforeSamplinghook, forced sessions. It does not touchlastResolved,onSessionStartedor the current session.session.sampled_for_error,_dd.configuration.session_sample_rate= drawn rate,rc_versionas usual;sessionOnError→session.sampled_for_error: true, rate 0 (the 0.7.9 behaviour);sessionOnError→ not reported, marked handled (as sampling did before).The coin comes from the incident (a hash of its identity), so a retry after a partial write draws the same way. Otherwise, at a fractional rate, a retry could drop an incident whose view had already landed.
Removed (dead after this change)
RumRawEvent.inherited,refusedBy,countInView, the inherited-error branch inRumSessionScope, and thetimestampMs/countInView/inheritedparameters and return value ofDefaultRumMonitor.reportError. No other caller used them.Known limitation
Such a crash carries the current launch's application version, OS, user and connectivity. Nothing in the incident says what the crashed run's were.
Tests
node scripts/unit-node/run.mjs— all pass.New:
aLaunchCrashNeverJoinsATrackedCurrentSession,aLaunchCrashLeavesAReleasedCurrentSessionAlone,aSessionOfItsOwnIsDrawnLikeANewSessionNotLikeTheCurrentOne,aSessionOfItsOwnIsDrawnUnderTheConsoleSettings,aLaunchCrashWithNoSessionDrawnAndNoSwitchIsNotReported,aRetryAtAFractionalRateDrawsTheSameWay.Updated because they encoded the old behaviour:
aLaunchCrashStillJoinsACollectedSessionOrFollowsSamplingwas replaced by the tests above;aPreviousLaunchCrashInAViewGapStaysOffThisLaunchsViewsnow expects the crash in its ownApplicationLaunchview;aRetryAfterAPartialWriteRewritesTheSameDocumentsnow also runs with a tracked draw;aCrashReplayedFromTheLastViewCarriesTheCrashedRunsContextandaFaultOlderThanTheLastViewIsNotAttributedToItsRun.Negative control: against the unfixed source, the new and updated tests fail (6 failures). With a random coin instead of the incident-derived one,
aRetryAtAFractionalRateDrawsTheSameWayfails.This is the change on
mainfor the 0.7.10 patch release. There is no version bump here; the fix is recorded under## 0.7.10inflashcat-rum/CHANGELOG.md.Also: a crash before the first view of its session
A JS crash in a session that had not opened a view yet left an incident naming the session but no view. The replay wrote the error into that session, which had no view document — and the backend builds a session only from view documents, so the crash belonged to a session that never appeared (and a session kept on error released nothing it could join).
Before anything snapshots the RUM context for a JS fault, a session that has never had a view now opens the
ApplicationLaunchview (RumSessionScope.openLaunchView, dispatched fromRumFeature.reportObservedErrorahead of the crash-module callback). The incident names that view,markCrashcounts the crash on it, the replay joins it, and a withheld session releases it with the crash. Live crashes (REPORT_AND_CONTINUE, or no crash module) andOBSERVE_ONLYerrors are written in it instead of as viewless errors.It mints no session, is not the view a later session restores, and the app's first view replaces it. A session between two views keeps counting on its last view; a crash with no session at all still goes to the session of its own above.
Tests (
rum-crash-before-first-view): persisted crash names and is counted on the launch view; withheld session releases it withsampled_for_error; live crash written in it and replaced by the first view; a second fault opens no second launch view; the replay joins it without counting again; no launch view between two views, with no session, or in an unsampled session. Negative control: against the unfixed source the three behaviour tests fail.scripts/ci-check.shpasses.Review follow-up
openLaunchViewwithdraws its id before the crash feature snapshots the context, so the crash is reported as one with no session of its own (a session drawn for it), and the expired session discards what it held instead of releasing it. The crash feature now readssession.sampledonly while a session id is published, so a crash after an unsampled session ended is drawn instead of dropped as sampled out. Tests:aSessionThatExpiredWithoutAViewGivesTheCrashUp(with a one-minute negative control) and two crash-feature tests; against the unfixed source the two behaviour tests fail.