Skip to content

Add Live Debugger package#4449

Merged
watson merged 31 commits into
mainfrom
watson/DEBUG-5296/add-live-debugger
May 12, 2026
Merged

Add Live Debugger package#4449
watson merged 31 commits into
mainfrom
watson/DEBUG-5296/add-live-debugger

Conversation

@watson
Copy link
Copy Markdown
Collaborator

@watson watson commented Apr 7, 2026

Motivation

Introduce the @datadog/browser-debugger package to enable Live Debugger in browser applications. This gives frontend developers the ability to add log probes to running applications, evaluate conditions, and inspect runtime state — all without redeploying or modifying source code.

Note: This package is intended for internal Datadog use only until validated in production. It follows the same convention as @datadog/browser-core, @datadog/browser-rum-core, and @datadog/browser-worker — published to npm with each release (to keep versions in sync), but excluded from generated documentation via typedoc.json.

Changes

New package: packages/debugger

A new @datadog/browser-debugger package that provides the full probe execution pipeline:

  • domain/api.ts — Core instrumentation hooks (onEntry, onReturn, onThrow) that execute probes when instrumented functions are called, including condition evaluation, snapshot capture, template message rendering, and rate limiting.
  • domain/activeEntries.ts — Tracks per-probe execution stacks for correlating entry/return/throw events, extracted to break the dependency cycle between api.ts and probes.ts.
  • domain/probes.ts — Probe lifecycle management (add, remove, clear) with per-probe and global snapshot rate limiting. Compiles probe conditions and template segments on registration.
  • domain/capture.ts — Deep value capture for arguments, locals, return values, and thrown errors with configurable reference depth, collection size limits, and string length limits.
  • domain/expression.ts — Expression compiler that parses JSON expression trees (comparisons, logical operators, member access, string operations, etc.) into executable functions.
  • domain/condition.ts — Probe condition evaluator that compiles and caches condition expressions.
  • domain/template.ts — Template segment compiler and evaluator for rendering dynamic probe messages with runtime context.
  • domain/stacktrace.ts — Stack trace capture and parsing from Error objects.
  • domain/deliveryApi.ts — Polling-based probe delivery client that fetches probe updates/deletions from the Delivery API using a cursor for incremental sync.
  • transport/startDebuggerBatch.ts — Transport layer that reuses @datadog/browser-core's batch/flush infrastructure to send debugger snapshots to the logs intake.
  • entries/main.ts — Public API surface (datadogDebugger.init()). Exposes $dd_entry/$dd_return/$dd_throw/$dd_probes hooks on globalThis for instrumented code. Defines the global DD_DEBUGGER object.

Changes to @datadog/browser-core

  • Added 'dd_debugger' as a valid source in configuration and transport types, mapped to 'browser' for the SDK source.
  • Exported computeTransportConfiguration and the Batch type so the debugger package can create its own transport.

E2E test framework and scenarios

  • test/e2e/scenario/debugger.scenario.ts — 7 E2E test scenarios covering: basic snapshot sending, argument/return value capture, exception capture on throw, template message evaluation with expression segments, condition evaluation (both met and not met), and RUM correlation.
  • E2E framework extensions — Added .withDebugger() builder method to createTest(), DebuggerIntakeRequest type and intakeRegistry.debuggerEvents for asserting on debugger events, debugger page setups for CDN/bundle/npm modes, and default debugger configuration.
  • test/apps/vanilla/app.ts — Added @datadog/browser-debugger import and DEBUGGER_INIT support so debugger E2E tests work in the npm setup.

Performance benchmarks

  • test/apps/instrumentation-overhead/ — Webpack test app for measuring instrumentation overhead with instrumented vs. uninstrumented function variants.
  • test/performance/scenarios/instrumentationOverhead.scenario.ts — Benchmark scenario that stress-tests 10M function calls to measure the overhead of debugger instrumentation hooks.
  • test/performance/createBenchmarkTest.ts — Extended with instrumented_no_probes and instrumented_with_probes scenario configurations and a dedicated injectDebugger function.

Tooling

  • Updated scripts/build/build-test-apps.ts to include the new test app and to use resolution paths when installing peer dependencies (needed for unpublished packages like @datadog/browser-debugger that only exist locally as .tgz files).
  • Updated scripts/dev-server/lib/server.ts to serve the debugger bundle.
  • Added debugger entry point to ESLint side-effects allowlist.

Test instructions

  1. Unit tests: yarn test:unit --spec "packages/debugger/src/**/*.spec.ts"
  2. E2E tests: yarn test:e2e:init && yarn test:e2e -g "debugger"
  3. Performance testing: yarn build:apps && yarn test:performance

Checklist

  • Tested locally
  • Tested on staging — N/A, this is a new pre-production package not yet deployed to any environment
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.
  • Updated documentation and/or relevant AGENTS.md file

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 7, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

Copy link
Copy Markdown
Collaborator Author

watson commented Apr 7, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@datadog-datadog-prod-us1
Copy link
Copy Markdown

datadog-datadog-prod-us1 Bot commented Apr 7, 2026

Tests

🎉 All green!

❄️ No new flaky tests detected
🧪 All tests passed

🎯 Code Coverage (details)
Patch Coverage: 72.33%
Overall Coverage: 76.70% (-0.31%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: a310727 | Docs | Datadog PR Page | Give us feedback!

@watson watson force-pushed the watson/DEBUG-5296/add-live-debugger branch from 4df303f to b539c14 Compare April 7, 2026 13:30
@cit-pr-commenter-54b7da
Copy link
Copy Markdown

cit-pr-commenter-54b7da Bot commented Apr 7, 2026

Bundles Sizes Evolution

📦 Bundle Name Base Size Local Size 𝚫 𝚫% Status
Rum 179.65 KiB 179.69 KiB +40 B +0.02%
Rum Profiler 6.17 KiB 6.17 KiB 0 B 0.00%
Rum Recorder 27.03 KiB 27.03 KiB 0 B 0.00%
Logs 56.78 KiB 56.82 KiB +40 B +0.07%
Rum Slim 135.50 KiB 135.54 KiB +40 B +0.03%
Worker 23.63 KiB 23.63 KiB 0 B 0.00%
🚀 CPU Performance
Action Name Base CPU Time (ms) Local CPU Time (ms) 𝚫%
RUM - add global context 0.0039 0.004 +2.56%
RUM - add action 0.0131 0.0133 +1.53%
RUM - add error 0.0117 0.0131 +11.97%
RUM - add timing 0.0025 0.0026 +4.00%
RUM - start view 0.0119 0.014 +17.65%
RUM - start/stop session replay recording 0.0006 0.0008 +33.33%
Logs - log message 0.0138 0.0189 +36.96%
🧠 Memory Performance
Action Name Base Memory Consumption Local Memory Consumption 𝚫
RUM - add global context 31.78 KiB 30.51 KiB -1.27 KiB
RUM - add action 56.94 KiB 55.55 KiB -1.40 KiB
RUM - add timing 32.72 KiB 33.15 KiB +436 B
RUM - add error 60.80 KiB 59.38 KiB -1.42 KiB
RUM - start/stop session replay recording 32.10 KiB 32.39 KiB +290 B
RUM - start view 484.29 KiB 482.94 KiB -1.36 KiB
Logs - log message 95.66 KiB 91.44 KiB -4.22 KiB

🔗 RealWorld

@watson
Copy link
Copy Markdown
Collaborator Author

watson commented Apr 7, 2026

I have read the CLA Document and I hereby sign the CLA

@watson watson force-pushed the watson/DEBUG-5296/add-live-debugger branch 6 times, most recently from 3042bfe to 98490f7 Compare April 7, 2026 15:45
@watson watson marked this pull request as ready for review April 7, 2026 15:56
@watson watson requested a review from a team as a code owner April 7, 2026 15:56
Copy link
Copy Markdown

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

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: 98490f775f

ℹ️ 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".

Comment thread packages/debugger/src/domain/capture.ts Outdated
Comment thread packages/debugger/src/domain/api.ts Outdated
watson added 14 commits May 7, 2026 11:27
Ensure we don't publish it while WIP
In the browser there's no trace or span id
Replace the hand-rolled `$dd_*` stub hooks with the actual published SDK
so the benchmark measures real per-call instrumentation overhead, not
the cost of counter-incrementing stubs. With the stubs the
`instrumented_with_probes` configuration came in at roughly the same
cost as `none`; with the real SDK it's ~1.65 µs per call, which is the
number we actually want to track.

For the measurement to be statistically sound the SDK has to be fully
ready before the warmup loop runs, otherwise V8 JIT-optimizes against
an intermediate `$dd_probes`-undefined shape and then deopts mid-flight
once probes appear. To get there:

- Inline the built debugger bundle via `addInitScript({ path })` so
  `DD_DEBUGGER` is defined before the test app's script tag executes.
- Mock the SDK's same-origin probe-delivery endpoint on the perf
  server, routing off the request body's `service` field so parallel
  benchmark workers stay isolated.
- Gate the scenario's warmup on a `__benchmarkReady` flag that the
  injector flips only after `init()` returns and (for
  `instrumented_with_probes`) the first poll has populated the registry.

The probe used for `instrumented_with_probes` is a typical low-impact
`LOG_PROBE` (`captureSnapshot: false`, `snapshotsPerSecond: 1`), so
measurement stays focused on probe-lookup + sampling-check cost rather
than intake traffic. The SDK's `pollInterval` is set to one day so
re-polls can't perturb the measurement window.
Previously, the Debugger SDK set `source: 'dd_debugger'` on its init
configuration so it would flow into the `ddsource` URL parameter, which
forced `validateAndBuildConfiguration` to convert it back to 'browser'
via a `toSdkSource` helper before storing on `Configuration.source`
(used as the SDK source on RUM events). The round-trip was confusing
because the same field was playing two roles: URL routing source and
RUM event SDK source.

Split them apart:

- `InitConfiguration.source` no longer accepts 'dd_debugger'.
- `computeTransportConfiguration` takes an optional `sourceOverride`
  parameter (typed `TransportSource`, includes 'dd_debugger') used only
  for URL building. The Debugger SDK passes 'dd_debugger' there.
- Function overloads narrow the return type when no override is given,
  so `Configuration.source` is `SdkSource` without a runtime conversion.
- `toSdkSource` is removed.

Wire behavior is unchanged: URLs still go out with
`?ddsource=dd_debugger&...&dd-evp-origin=browser`, RUM events still
carry a valid `SdkSource`, and downstream `source:dd_debugger` queries
keep working.
@watson watson force-pushed the watson/DEBUG-5296/add-live-debugger branch from ce9f93d to 09376b1 Compare May 7, 2026 09:28
@watson watson force-pushed the watson/DEBUG-5296/add-live-debugger branch 2 times, most recently from 273842f to b297a1b Compare May 11, 2026 12:18
Comment thread packages/core/src/domain/configuration/configuration.ts Outdated
The previous commit (09376b1) widened `TransportConfiguration.source`
to `TransportSource` so the `dd_debugger` override could ride through
it. That forced `Configuration` to redeclare `source: SdkSource` to
narrow the inherited type back down for consumers like
`defaultContext.ts` (where `RumEvent.source` does not accept
`dd_debugger`), and it required overload signatures on
`computeTransportConfiguration` to preserve that narrowing at the
return-type boundary.

None of that is actually necessary: nothing reads `source` off a
`TransportConfiguration` outside of `validateAndBuildConfiguration`
spreading it into `Configuration`. The override only needs to reach the
endpoint builders so the `ddsource` URL parameter gets the right value.

Keep the override strictly internal to URL building:

- `TransportConfiguration.source` is back to `SdkSource`, matching its
  pre-09376b12b shape.
- `computeTransportConfiguration` drops the overload pair and exposes a
  single signature with optional `sourceOverride`.
- The override is plumbed into `ResolvedSourceInitConfiguration` and
  flows to the endpoint builders, but the returned struct's `source`
  is always the validated `SdkSource`.
- The redundant `source: SdkSource` redeclaration on `Configuration`
  is removed.

Wire behavior is unchanged: URLs still go out with
`?ddsource=dd_debugger&...&dd-evp-origin=browser`.
@watson watson force-pushed the watson/DEBUG-5296/add-live-debugger branch from b297a1b to 0f3dfe2 Compare May 11, 2026 13:12
watson and others added 5 commits May 11, 2026 15:53
As we are adding more tests, Karma is sending more messages from the
browser to the node process. Those tests are piling up sometimes in
browserstack, and it takes some time for them to reach the node process.

Increasing the timeout should help.
Json schemas where parsed every time an event was emitted, which was
very ineficient in Firefox 67 and triggered a LOT of GC pauses, which
might be the root cause of timeouts.
@watson watson merged commit e739e7e into main May 12, 2026
21 of 22 checks passed
@watson watson deleted the watson/DEBUG-5296/add-live-debugger branch May 12, 2026 09:09
@github-actions github-actions Bot locked and limited conversation to collaborators May 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants