Skip to content

✨ Support { includeDefaults: true } in trackResourceHeaders#4825

Open
bdibon wants to merge 1 commit into
mainfrom
boris.dibon/track-resource-headers-include-defaults
Open

✨ Support { includeDefaults: true } in trackResourceHeaders#4825
bdibon wants to merge 1 commit into
mainfrom
boris.dibon/track-resource-headers-include-defaults

Conversation

@bdibon

@bdibon bdibon commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Motivation

Enabling trackResourceHeaders with custom matchers while still collecting the built-in defaults previously required spreading DEFAULT_TRACKED_RESOURCE_HEADERS manually:

trackResourceHeaders: [
  ...DEFAULT_TRACKED_RESOURCE_HEADERS.map((name) => ({ name })),
  { name: 'x-request-id' },
]

This is verbose and forces customers to import (NPM) or reference (CDN) the DEFAULT_TRACKED_RESOURCE_HEADERS constant. This change adds an ergonomic sentinel so the defaults can be pulled in inline.

Changes

  • Validation (configuration.ts): validateAndBuildTrackResourceHeaders now expands a { includeDefaults: true } array entry into DEFAULT_TRACKED_RESOURCE_HEADERS in place, preserving array order so it can be combined with custom matchers. A typed shouldIncludeDefaultHeaders predicate keeps the union narrowing intact.
  • TSDoc: documented the new { includeDefaults: true } entry and updated the example to use it.
  • Deprecation: marked the DEFAULT_TRACKED_RESOURCE_HEADERS field on the DD_RUM public API as @deprecated in favor of the new sentinel. The field/value is kept to avoid a breaking change.
  • Tests: added cases for the sentinel alone and combined with a custom matcher.

New usage:

trackResourceHeaders: [{ includeDefaults: true }, { name: 'x-request-id' }]

Test instructions

Automated

yarn test:unit --spec packages/browser-rum-core/src/domain/configuration/configuration.spec.ts
yarn typecheck
yarn lint

All trackResourceHeaders tests pass (89/89), typecheck and lint are clean.

Manual (end-to-end)

Start the dev server and create a temporary sandbox page that combines the sentinel with a custom matcher:

yarn dev-server start

cat > sandbox/test-include-defaults.html << 'HTML'
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Test includeDefaults</title>
    <script src="/datadog-rum.js"></script>
    <script>
      DD_RUM.init({
        clientToken: 'xxx',
        applicationId: 'xxx',
        proxy: '/proxy',
        trackResources: true,
        trackResourceHeaders: [{ includeDefaults: true }, { name: 'x-custom-header' }],
      })
      function makeRequest() {
        fetch('/datadog-rum.js', { headers: { 'x-custom-header': 'hello' } })
      }
    </script>
  </head>
  <body>
    <button id="fetch-btn" onclick="makeRequest()">Fetch</button>
  </body>
</html>
HTML

Then exercise it (dev-server URL from yarn dev-server status):

yarn dev-server intake clear
agent-browser open http://localhost:8081/test-include-defaults.html
agent-browser click '#fetch-btn'
# wait for the fetch's PerformanceResourceTiming, then flush
agent-browser reload
yarn dev-server intake rum-resources \
  | jq -c 'select(.resource.type=="fetch") | {request_headers: .resource.request.headers, response_headers: .resource.response.headers}'

Expected output — the custom matcher (x-custom-header) is captured on the request and the expanded defaults (content-type, content-length, …) are captured on the response:

{"request_headers":{"x-custom-header":"hello"},"response_headers":{"content-type":"text/javascript; charset=utf-8","content-length":"2429864"}}

Cleanup:

yarn dev-server stop
rm sandbox/test-include-defaults.html

Checklist

  • Tested locally
  • Tested on staging
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.
  • Updated documentation and/or relevant AGENTS.md file

@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Jun 26, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 50.00%
Overall Coverage: 77.19% (-0.01%)

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

Allow including the default tracked resource headers within a custom
trackResourceHeaders array via a `{ includeDefaults: true }` entry,
removing the need to spread DEFAULT_TRACKED_RESOURCE_HEADERS manually.

Deprecate the DEFAULT_TRACKED_RESOURCE_HEADERS field on the DD_RUM
public
API in favor of the new sentinel (kept to avoid a breaking change).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@bdibon bdibon force-pushed the boris.dibon/track-resource-headers-include-defaults branch from 2e08107 to 0cd0389 Compare June 26, 2026 14:45
@cit-pr-commenter-54b7da

Copy link
Copy Markdown

Bundles Sizes Evolution

📦 Bundle Name Base Size Local Size 𝚫 𝚫% Status
Rum 172.75 KiB 172.84 KiB +91 B +0.05%
Rum Profiler 8.22 KiB 8.22 KiB 0 B 0.00%
Rum Recorder 21.14 KiB 21.14 KiB 0 B 0.00%
Logs 54.44 KiB 54.44 KiB 0 B 0.00%
Rum Slim 130.27 KiB 130.35 KiB +85 B +0.06%
Worker 22.96 KiB 22.96 KiB 0 B 0.00%

* trackResourceHeaders: [{ url: /\/api\//, name: 'server-timing', extractor: /dur=(\d+)/, location: 'response' }]
*/
trackResourceHeaders?: boolean | MatchHeader[] | undefined
trackResourceHeaders?: boolean | Array<MatchHeader | { includeDefaults: true }> | undefined

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

suggestion: make includeDefaults a MatchHeader option?

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.

I don't think it's a good idea, if we want to do this we either have to:

A)

Add includeDefaults field on type MatchHeader, then we may end up with non-sensical entries such as { name: 'x-my-header', includeDefaults: true}, we could make name optional, but we will have to handle possibly undefined matchHeader.name

What's nice in the current design is that validateAndBuildTrackResourceHeaders always resolves entries of the configuration option to a MatchHeader, which the rest of the SDK uses.

B)

We do something like type MatchHeader = HeaderMatcher | IncludeDefaultsOption, SDK uses internally the HeaderMatcher type. It adds a type whose name will be hard to not be confusing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I like the optional MatchHeader.name because:

  • it is more powerful, i.e. the user can include default headers for a specific URL only, or specific "location". Solution B only allows to include the default headers on all URLs and locations

  • it doesn't add a new data model/concept into the mix

What's nice in the current design is that validateAndBuildTrackResourceHeaders always resolves entries of the configuration option to a MatchHeader, which the rest of the SDK uses.

Having an optional name is trivial to handle, I would argue that it makes things even simpler. See this commit for illustration.

@bdibon bdibon marked this pull request as ready for review June 30, 2026 07:09
@bdibon bdibon requested a review from a team as a code owner June 30, 2026 07:09
@bdibon bdibon requested a review from BenoitZugmeyer June 30, 2026 07:10
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.

2 participants