Skip to content

✨ add global context to the main process - #192

Open
rgaignault wants to merge 7 commits into
mainfrom
roman.gaignault/RUM-15524/global-context
Open

✨ add global context to the main process#192
rgaignault wants to merge 7 commits into
mainfrom
roman.gaignault/RUM-15524/global-context

Conversation

@rgaignault

Copy link
Copy Markdown
Contributor

Motivation

Renderer processes can attach custom attributes through the Browser SDK's setGlobalContext, but the
main process has no equivalent, so main-process RUM events cannot carry app-level attributes such as a
build id or a feature flag.

Changes

Adds five APIs mirroring the Browser SDK, since customers already use those names in the renderer:

setGlobalContext({ team: 'checkout' });
setGlobalContextProperty('build', '1.2.3');
removeGlobalContextProperty('build');
clearGlobalContext();
getGlobalContext();

Attributes are sent in the event's context field. GlobalContext reuses ContextManager, so it gets
the same disk-backed history as user and account, meaning a crash from a previous run is enriched with
the attributes that were active at the time. The RUM hook that user, account and global context all
register was identical three times, so it moved to the base class.

Renderer events also receive the main-process context. combine already merged the two objects; this
sets the precedence so the renderer wins on a conflicting key.

A few decisions worth a look:

  • setGlobalContextProperty(key, null) removes the property, matching addUserExtraInfo. The Browser
    SDK keeps the null.
  • Attributes go on RUM events only, not on spans, matching the Browser and mobile SDKs. Note user and
    account do enrich spans, so this is inconsistent within the SDK.
  • Renderer merging is per key, whereas usr and account are replaced wholesale. Free-form attributes
    have no single owner, and a wholesale rule would drop main-process attributes from any event that
    happens to carry event-level context.
  • There is no way to tell a webview from a first-party renderer yet, so webview events receive
    main-process attributes too.
  • Calls made before init() are dropped silently, as with duration vitals. Rationalising that is
    RUM-17397.
  • Every mutation appends a history entry and rewrites the history file. That is cheap for user and
    account, which change at login, but global context is likely to be called far more often.

Test instructions

In the playground, use the Global Context buttons and check that following events carry the attributes
in context. Setting a key in a renderer through datadogRum.setGlobalContext should win over the same
key set in the main process.

Checklist

  • Tested locally (playground)
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.
  • Updated related documentation.
  • Agentic code review findings addressed or explicitly dismissed.

@rgaignault
rgaignault requested a review from a team as a code owner August 4, 2026 09:40
@rgaignault
rgaignault marked this pull request as draft August 4, 2026 09:41
@rgaignault

Copy link
Copy Markdown
Contributor Author

@codex review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale comment

PR Review — Score: 4.6 / 5

This is a well-structured feature addition that mirrors the Browser SDK surface, reuses ContextManager cleanly (including the setFlatContext / extraInfo edge case), and DRYs the duplicated RUM hook registration. Test coverage spans unit, assembly, and e2e, documentation is thorough, and the PR description documents the intentional tradeoffs clearly. I would approve.

Why 4.6: Solid API design with validation/sanitization at the public boundary, thoughtful renderer merge semantics, crash-attribution history parity with user/account, and comprehensive tests plus README updates.

Why not 5: Disk-backed history rewrites on every property mutation may be costly for high-frequency global-context updates (acknowledged in the PR body), pre-init calls are silently ignored without feedback (tracked as RUM-17397), and null property semantics intentionally diverge from the Browser SDK (also documented).


Findings

  • [Minor] Disk history on every mutationsetProperty/removeProperty trigger a full history close-and-persist cycle, which may be expensive if global context is updated frequently.
  • [Nit] Silent pre-init no-ops — API calls before init() are dropped without warning; consistent with duration vitals but easy to misconfigure during startup.

Architectural flow

sequenceDiagram
    participant App as Main app
    participant API as Public API
    participant GC as GlobalContext
    participant Disk as DiskValueHistory
    participant Hooks as FormatHooks
    participant Pipe as RendererPipeline
    participant Intake as EventManager

    App->>API: setGlobalContext / setGlobalContextProperty
    API->>GC: sanitize then setFlatContext / setProperty
    GC->>Disk: closeAndAdd / pruneAndPersist

    Note over Hooks: Main-process RUM events
    Hooks->>GC: getContext via registerRumHook
    GC-->>Hooks: context attributes
    Hooks->>Intake: RumEvent with context field

    Note over Pipe: Renderer RUM events
    Pipe->>Hooks: triggerRum for main-process context
    Hooks->>GC: getContext
    GC-->>Pipe: main-process context
    Note over Pipe: Per-key merge, renderer wins on conflict
    Pipe->>Intake: ServerRumEvent
Loading

Before: Only renderer processes could attach free-form context attributes via the Browser SDK; main-process RUM events had no equivalent, and renderer events did not inherit main-process attributes.

After: The main process exposes five Browser-SDK-aligned APIs backed by GlobalContext (disk-persisted history for crash attribution). A shared registerRumHook injects context into all RUM events. For renderer events, RendererPipeline merges main-process and renderer context per key, with renderer values taking precedence on conflicts.

Note: GitLab CI jobs were still pending when this review was posted.

Open in Web View Automation 

Sent by Cursor Automation: electron-sdk reviews

Comment thread src/domain/customer-context/contextManager.ts
Comment thread src/api.ts
Comment thread src/assembly/RendererPipeline.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale comment

PR Review — Score: 4.6 / 5

This is a well-executed feature addition that mirrors the Browser SDK global-context API, reuses the existing ContextManager infrastructure cleanly, and includes solid unit, pipeline, and e2e coverage plus documentation. I would approve.

Why 4.6: The implementation follows established SDK patterns (callMonitored, input validation/sanitization, disk-backed crash attribution), extracts the duplicated RUM hook into the base class, and handles the renderer merge with the right per-key precedence. Tests exercise the important edge cases (extraInfo key handling, historical attribution, renderer-wins merge).

Why not 5: Two known trade-offs remain — frequent property updates will hit disk on every mutation (acceptable for crash attribution but worth watching), and pre-init calls are silently dropped (tracked separately in RUM-17397). Global context also intentionally skips span enrichment, which is documented but leaves a small internal inconsistency with user/account.

CI had several dd-gitlab/* jobs still pending when this review was posted; that is noted separately and not factored into the score.


Findings

  • [Minor] History rewrite on every mutation — Each setGlobalContextProperty closes the active history entry and rewrites the disk file; fine for login-time user/account updates but potentially costly for high-frequency callers.
  • [Minor] Pre-init calls silently droppedglobalContextApi?.… no-ops before init() with no warning; same pattern as duration vitals, tracked in RUM-17397.
  • [Nit] RUM-only enrichment — Global context is intentionally omitted from spans to match Browser/mobile SDKs, unlike user/account in this SDK.

Architectural flow

sequenceDiagram
    participant App as Main process app
    participant API as Public API
    participant GC as GlobalContext
    participant Hooks as FormatHooks
    participant RP as RendererPipeline
    participant EM as EventManager

    App->>API: setGlobalContext / setGlobalContextProperty
    API->>GC: setContext / setProperty
    GC->>GC: record history and persist
    GC->>Hooks: registerRumHook injects context

    Note over RP: Renderer RUM event arrives
    RP->>Hooks: triggerRum
    Hooks-->>RP: main-process context override
    RP->>RP: per-key merge renderer wins on conflicts
    RP->>EM: ServerRumEvent with combined context
Loading

Before: Only user/account context lived in the main process; renderer global context was Browser SDK-only and was not merged with main-process attributes.

After: Main process exposes five global-context APIs backed by GlobalContext (disk history + RUM hook). Main-process events get context from the hook. Renderer events still carry Browser SDK context, but RendererPipeline now merges main-process attributes in per-key with renderer precedence — unlike usr/account, which are replaced wholesale when the renderer already has them.

Open in Web View Automation 

Sent by Cursor Automation: electron-sdk reviews

Comment thread src/domain/customer-context/contextManager.ts
Comment thread src/api.ts
Comment thread src/domain/customer-context/globalContext.ts
Comment thread src/assembly/RendererPipeline.ts
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 30b52fb0b9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@rgaignault
rgaignault marked this pull request as ready for review August 31, 2026 15:07
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T15:15:14.804228Z 1ed5bc4 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

PR Review — Score: 4.7 / 5

This is a well-executed feature addition that mirrors the Browser SDK global-context API, reuses ContextManager cleanly (including the extraInfo key edge case), and DRYs the duplicated RUM hook into the base class. The merge from main integrated cleanly — usage telemetry was added for all five APIs and getGlobalContext is now wrapped in callMonitored. Test coverage spans unit, pipeline, and e2e, documentation is thorough, and the author provided sound rationale for the disk-persistence trade-off. I would approve.

Why 4.7: Solid API design with validation/sanitization at the public boundary, thoughtful renderer per-key merge semantics, crash-attribution history parity with user/account, comprehensive tests plus README updates, and prior disk-I/O concern addressed with intentional design rationale.

Why not 5: Pre-init calls are still silently dropped without feedback (tracked in RUM-17397), and global context intentionally skips span enrichment — documented but a small internal inconsistency with user/account.

Several dd-gitlab/* jobs were still pending when this review was posted; that is noted separately and not factored into the score.


Findings

  • [Minor] Pre-init calls silently droppedglobalContextApi?.… no-ops before init() with no warning; same pattern as duration vitals, tracked in RUM-17397.
  • [Nit] RUM-only enrichment — Global context registers only the RUM hook, unlike user/account which also enrich spans; intentional Browser/mobile SDK parity.

Architectural flow

sequenceDiagram
    participant App as Main process app
    participant API as Public API
    participant GC as GlobalContext
    participant Disk as DiskValueHistory
    participant Hooks as FormatHooks
    participant RP as RendererPipeline
    participant EM as EventManager

    App->>API: setGlobalContext / setGlobalContextProperty
    API->>GC: setFlatContext / setProperty
    GC->>Disk: closeAndAdd / pruneAndPersist
    GC->>Hooks: registerRumHook

    Note over Hooks: Main-process RUM events
    Hooks->>GC: getContext
    GC-->>Hooks: context attributes

    Note over RP: Renderer RUM events
    RP->>Hooks: triggerRum
    Hooks-->>RP: main-process context
    Note over RP: Per-key merge, renderer wins on conflicts
    RP->>EM: ServerRumEvent
Loading

Before: Only renderer processes could attach free-form context attributes via the Browser SDK; main-process RUM events had no equivalent, and renderer events did not inherit main-process attributes.

After: The main process exposes five Browser-SDK-aligned APIs backed by GlobalContext (disk-persisted history for crash attribution). A shared registerRumHook injects context into all RUM events. For renderer events, RendererPipeline merges main-process and renderer context per key, with renderer values taking precedence on conflicts.

Open in Web View Automation 

Sent by Cursor Automation: electron-sdk reviews

Comment thread src/api.ts
Comment thread src/domain/customer-context/globalContext.ts
Comment thread src/assembly/RendererPipeline.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1ed5bc4a1c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

*/
export class GlobalContext extends ContextManager<Context> {
static init(hooks: FormatHooks): Promise<GlobalContext> {
return initContextWithHistory((history) => new GlobalContext(hooks, history), GLOBAL_CONTEXT_HISTORY_FILE_NAME);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Bound disk-history work for global-context mutations

When an application updates global context repeatedly—for example, changing a feature flag on each navigation—initializing it with disk-backed history here makes every mutation append a full context copy, synchronously serialize the entire four-hour history, and enqueue another full-file write. The history and queued snapshots therefore grow rapidly and total serialization/write work is quadratic; the main process can stall or consume substantial memory, while a crash during the backlog is attributed using stale on-disk context. Coalesce or otherwise bound global-context persistence rather than using the infrequent user/account write strategy unchanged.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Persistence is intentional for crash attribution, and Global Context is not expected to be updated on every navigation.

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.

1 participant