Skip to content

[dop] [error-tracking]: derive debug_id from file content - #470

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 5 commits into
masterfrom
hugo.silva/fix-debug-id-key-path
Aug 3, 2026
Merged

[dop] [error-tracking]: derive debug_id from file content#470
gh-worker-dd-mergequeue-cf854d[bot] merged 5 commits into
masterfrom
hugo.silva/fix-debug-id-key-path

Conversation

@jhssilva

@jhssilvajhssilva commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

The RUM plugin injects a debug_id into every built chunk's own JS content. This PR makes the error-tracking plugin extract that debug_id back out of each file when it uploads that file's sourcemap, instead of relying on the previous filename-based coordination between the two plugins.

Why

Previously, error-tracking got the debug_id from a side-channel Map that the RUM plugin populated at injection time, keyed by the chunk's filename. Bundlers (webpack/rspack) rename chunks after injection via realContentHash, so by the time error-tracking looked the value up by the chunk's final filename, the key no longer matched — the debug_id was silently dropped for almost every chunk in a real build.

How

Instead of coordinating through a filename-keyed Map, error-tracking now reads each minified file's own content directly and extracts the debug_id from the ddDebugId literal the RUM plugin already embeds inside it. This works no matter what renaming the bundler does afterward, since the debug_id travels with the file's content, not its name.

  • error-tracking/src/sourcemaps/debugId.ts (new): extractDebugId() — regex-extracts the debug_id from a file's content.
  • error-tracking/src/sourcemaps/sender.ts: reads the minified file's content and extracts the debug_id from it, in place of the old Map lookup.
  • plugins/rum/src/index.ts + getSourceCodeContextSnippet.ts: RUM no longer needs to track debug_ids separately — the value already lives in the code it injects.
  • core/src/helpers/fs.ts: new readFilePrefix() helper, since we only need the first bytes of each file, not the whole thing.
  • plugins/injection/{xpack,esbuild}.ts: keep injected chunk filenames as relative paths for consistency with the rest of the pipeline.

Notes

  • Real end-to-end build against a module-federation-remote entry (mf_apm_runtime_app, rspack), uploaded to staging: each nested chunk's uploaded debug_id matches the ddDebugId literal embedded in that chunk's own file.

@jhssilva
jhssilva requested review from a team as code ownersJuly 28, 2026 17:28
@jhssilva
jhssilva requested review from aananiadis and removed request for a teamJuly 28, 2026 17:28
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2Bot commented Jul 28, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

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

// but the content, and the debug_id embedded in it, is unaffected. Only the file's
// prefix is read, since the RUM plugin's injected snippet always lands near the
// start of the file (see DEBUG_ID_SEARCH_PREFIX_BYTES).
const fileContent = await readFilePrefix(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: With esbuild, this runs before the injection onEnd, so it uploads the pre-injection files without ddDebugId. Should't we defer the upload until injection completes.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

For now, we'll be dogfooding in web-ui. We'll do other iterations as needed in future pr's.
We'll keep this in mind.

Comment threadpackages/core/src/helpers/fs.ts Outdated
@jhssilva
jhssilva changed the base branch from buranmert/rum-debug-id-to-error-tracking to masterJuly 31, 2026 15:03
@jhssilvajhssilva changed the title fix(error-tracking): derive debug_id from file content, not a filename Map[dop] [error-tracking]: derive debug_id from file content, not a filename MapJul 31, 2026
@jhssilvajhssilva changed the title [dop] [error-tracking]: derive debug_id from file content, not a filename Map[dop] [error-tracking]: derive debug_id from file contentJul 31, 2026
@jhssilvajhssilva self-assigned this Jul 31, 2026
Comment threadpackages/plugins/injection/src/xpack.ts Outdated
Comment threadpackages/plugins/injection/src/esbuild.ts Outdated
Comment threadpackages/core/src/helpers/fs.ts Outdated
…e Map
The RUM plugin injects a debug_id into every built chunk's own JS
content. error-tracking's sourcemap uploader now extracts that
debug_id back out of each file when it uploads that file's sourcemap,
instead of relying on filename-based coordination between the two
plugins.
Previously, error-tracking got the debug_id from a side-channel Map
that the RUM plugin populated at injection time, keyed by the chunk's
filename. Bundlers (webpack/rspack) rename chunks after injection via
realContentHash, so by the time error-tracking looked the value up by
the chunk's final filename, the key no longer matched — the debug_id
was silently dropped for almost every chunk in a real build.
Instead of coordinating through a filename-keyed Map, error-tracking
now reads each minified file's own content directly and extracts the
debug_id from the ddDebugId literal the RUM plugin already embeds
inside it. This works no matter what renaming the bundler does
afterward, since the debug_id travels with the file's content, not
its name.
@jhssilva
jhssilvaforce-pushed the hugo.silva/fix-debug-id-key-path branch from 9a8a985 to 9e20c37CompareJuly 31, 2026 15:30
…op unrelated fileName plumbing
extractDebugId now takes a file path and owns the read+regex composition
directly, instead of sender.ts composing readFilePrefix + extractDebugId
itself. Removes the now-unneeded readFilePrefix import from sender.ts.
Also reverts the esbuild.ts/xpack.ts fileName changes back to bare
basenames — that relative-path plumbing was left over from the old
filename-keyed debug_id lookup this PR removes, and nothing in this
diff depends on it anymore.
Per review, readFilePrefix had a single call site (debugId.ts) so it
didn't warrant living in the shared fs helpers. The byte-limited read
is now implemented directly inside debugId.ts.
Since debugId.ts's file read is no longer mockable through the shared
addFixtureFiles fixture system, its tests (and the one sender.ts test
that exercises real debug_id extraction) now write real temp files
instead, matching the pattern already used by fs.test.ts's own
(now-removed) readFilePrefix tests.
commit 52b5952 ("fold debug_id file read into debugId.ts, drop
unrelated fileName plumbing") collapsed `fileName` back down to a bare
basename in both xpack.ts and esbuild.ts, treating the relative-path
computation as unrelated scope creep and removing it along with the
comment explaining why it existed.
It wasn't unrelated: debug_id lookups match chunks by the same
relativePath computed for sourcemap uploads in
error-tracking/src/sourcemaps/files.ts. A bare basename works for
simple single-entry builds, but nested/federated chunks (e.g.
module-federation remotes) can share a basename across different
subdirectories, so collapsing to basename reintroduces collisions
between unrelated chunks during content/debug-id injection.
Restore the relative path (normalized to forward slashes) in both
bundler backends.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@jhssilva@bcaudan@buranmert@sdkennedy2@rgaignault