🐛 Fix #3935: Include pre-start context in first view event#4304
🐛 Fix #3935: Include pre-start context in first view event#4304
Conversation
|
I have read the CLA Document and I hereby sign the CLA You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot. |
|
✅ Tests 🎉 All green!❄️ No new flaky tests detected 🎯 Code Coverage (details) 🔗 Commit SHA: 338234a | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or give us feedback! |
Bundles Sizes Evolution
🚀 CPU Performance
🧠 Memory Performance
|
Comparison: This PR vs PR #3597Both PRs fix #3935 (first view event missing pre-start context), but take fundamentally different approaches. This PR: Synchronous context forwardingApproach: Snapshot pre-start context values in Pros:
Cons:
PR #3597: Microtask-delayed first view updateApproach: Wraps the first view update emission in Pros:
Cons:
RecommendationPR #3597's approach is more comprehensive and handles a broader set of edge cases. If the team is comfortable with the async timing change and the test refactoring, it's the stronger long-term solution. This PR's approach is lower-risk and simpler but narrower in scope. |
Capture global, user, and account contexts set before init() and restore them after startRum() so the first view event includes pre-start context. Skip restoring empty account context to avoid triggering a spurious "property id of account is required" warning. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3ac6e4e to
338234a
Compare
| // Initialize context managers with pre-start values so the first view event | ||
| // includes any context set before init() was called (see #3935) | ||
| if (initialContexts) { | ||
| globalContext.setContext(initialContexts.globalContext) |
There was a problem hiding this comment.
There's a regression here for storeContextsAcrossPages users.
When that flag is on, startGlobalContext calls storeContextManager internally, which synchronously loads the previous session's context from localStorage before returning. So by the time we get here, the managers already have that data.
If nothing was set before init(), initialContexts.globalContext and initialContexts.userContext are both {}. Calling setContext({}) wipes what was just loaded — and since changeObservable fires right away, dumpToStorage runs and writes {} back to localStorage. The stored data is gone permanently.
accountContext is fine because the isEmptyObject guard below protects it, but the other two aren't guarded.
For a user with storeContextsAcrossPages who doesn't set any pre-start context:
- before this PR: first view =
{}(the bug), subsequent events ={ storedKey: 'value' } - after this PR: first view =
{}(still wrong), subsequent ={}, localStorage wiped
Adding the same guard to all three should fix it:
if (!isEmptyObject(initialContexts.globalContext)) {
globalContext.setContext(initialContexts.globalContext)
}
if (!isEmptyObject(initialContexts.userContext)) {
userContext.setContext(initialContexts.userContext)
}
if (!isEmptyObject(initialContexts.accountContext)) {
accountContext.setContext(initialContexts.accountContext)
}
RFC: Include Pre-Start Context in First RUM View Event
Status: Complete
Branch:
rick.klein/3935/missing-global-context-initLast updated: 2026-03-10
PR: PR #4304
Summary
The first RUM view event emitted after
DD_RUM.init()is missing global context, user context, and account context that were set before initialization. This RFC describes a fix that passes pre-start context values through the initialization chain so they are applied to the real context managers before the first view event fires.Motivation
Users of the Browser SDK commonly set context before calling
init():The first view event emitted during
init()is missing this context. All subsequent events include it correctly. This is issue #3935.Root cause: During
init(),startRumEventCollection()creates new, empty context managers, then starts assembly (which registers context hooks), then starts view collection. The first view event fires synchronously duringstartViewCollection(). The pre-start buffered API calls (includingsetContext()) are drained afterstartRum()returns — too late for the first view event.The initialization sequence:
tryStartRum()callsdoStartRum()(which callsstartRum()→startRumEventCollection())startRumEventCollection(): new empty context managers are created → assembly hooks registered →startViewCollection()fires the first view event synchronouslydoStartRum()returnsbufferApiCalls.drain()replays bufferedsetContext()calls — but the first view event already shippedSolution
Approach
Snapshot the pre-start context values in
tryStartRum()and pass them through the initialization chain (doStartRum→startRum→startRumEventCollection). The real context managers are initialized with these values beforestartViewCollection()is called, ensuring the first view event includes them.This is a synchronous, forward-pass approach — no timing changes, no microtask delays, no changes to the buffer drain order.
Architecture
The fix threads an
InitialContextsobject through three functions:preStartRum.ts(tryStartRum): Snapshots pre-start context values into anInitialContextsobject and passes it todoStartRum()rumPublicApi.ts: ForwardsinitialContextsfromdoStartRumcallback tostartRum()startRum.ts(startRumEventCollection): After creating context managers but before starting view collection, callssetContext()on each manager with the initial valuesSchema
The
InitialContextsinterface added inpackages/rum-core/src/boot/preStartRum.ts:The
DoStartRumtype signature updated to includeinitialContexts:Testing
Run
yarn test:unit --spec packages/rum-core/src/boot/preStartRum.spec.tsandyarn test:unit --spec packages/rum-core/src/boot/startRum.spec.tsto validate the fix.Unit tests (4 new tests in
preStartRum.spec.ts): Verify thatdoStartRumreceives the correct initial context values for global context, user context, account context, and the empty-context case.Integration tests (2 new tests in
startRum.spec.ts): Verify the first collected view event includes global context (contextfield) and user context (usrfield) wheninitialContextsis passed tostartRumEventCollection.References
enqueueMicroTask()to delay the first view update