Skip to content

feat(otlp-exporter-base): support gzip compression in browser OTLP HTTP exporters - #7166

Open
YangJonghun wants to merge 10 commits into
open-telemetry:mainfrom
YangJonghun:feat/browser-otlp-gzip
Open

YangJonghun wants to merge 10 commits into
open-telemetry:mainfrom
YangJonghun:feat/browser-otlp-gzip

Conversation

@YangJonghun

@YangJonghun YangJonghun commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Which problem is this PR solving?

Browser OTLP HTTP exporters ignore the compression option that the OTLP exporter spec requires.

Refs #5686

Short description of the changes

  • The fetch transport gzips request bodies with the built-in CompressionStream API and charges the keepalive budget with the compressed size, so more telemetry fits into requests that survive page unload.
  • Values other than gzip/none, or runtimes that connot gzip (older browsers, some edge runtimes), fall back to uncompressed requests with a warning.
  • Browser exporters pass compression through: it moves from OTLPExporterNodeConfigBase to OTLPExporterConfigBase.

Notes:

  • [otlp-exporter-base] come up with plan for implementing the compression option for browser exporters #5686 suggested not extending the legacy config. The exporters' published types still describe the Node.js implementation, so browser TS users can already pass compression (it was silently ignored), Node.js has the option, and the new interface has not landed yet. The transport change can be split out from exposing the option if preferred.

  • Measured with Playwright 1.63 (Chromium 153, Firefox 155, WebKit 26.6) on synthetic OTLP trace bodies:

    Body gzip Time per export
    JSON, 100 spans (82.5 KB) 7.7-8.6 KB 0.30-0.35ms
    JSON, 512 spans (421 KB) 36-41 KB 1.3-1.8ms

    A 100-span JSON batch exported from pagehide/visibilitychange reached the collector 0/10 times uncompressed in WebKit (over the keepalive budget) and 10/10 gzipped. Chromium and Firefox delivered both.

  • Cross-origin collectors must allow the Content-Encoding header.

Type of change

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

How Has This Been Tested?

  • Unit tests
  • Playwright 1.63 with Chromium 153, Firefox 155 and WebKit 26.6: gzip exports started from pagehide / visibilitychange were delivered

Checklist:

  • Followed the style guidelines of this project
  • Unit tests have been added
  • Documentation has been updated

transport

- gzip the body with `CompressionStream`, read with a stream reader so
  that exports started on page unload still reach `fetch`
- charge the keepalive budget with the compressed size
- the deprecated `createOtlpSendBeaconExportDelegate()` now applies the
  `compression` option it is given
…LP HTTP exporters

- move `compression` and `CompressionAlgorithm` to the shared legacy configuration
- pass `compression` through `convertLegacyBrowserHttpOptions`
- document browser behavior and CORS requirements in the READMEs
@YangJonghun
YangJonghun requested review from a team as code owners October 5, 2026 16:43
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Pull request dashboard status

Waiting on reviewers · refreshed 2026-10-23 21:26 UTC

Review the latest changes.

Also blocked by: Merge conflicts.

Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Anything look wrong? Report it with what you expected; it helps us improve the dashboard.

@codecov

codecov Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.01%. Comparing base (e5db961) to head (1ec50b4).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7166      +/-   ##
==========================================
- Coverage   95.07%   95.01%   -0.07%     
==========================================
  Files         384      387       +3     
  Lines       13548    13619      +71     
  Branches     3127     3140      +13     
==========================================
+ Hits        12881    12940      +59     
- Misses        667      679      +12     
Files with missing lines Coverage Δ
...nfiguration/convert-legacy-browser-http-options.ts 100.00% <ø> (ø)
.../src/platform/browser/transport/fetch-transport.ts 96.66% <100.00%> (+1.48%) ⬆️

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- expect lowercase header names from `Headers`
- run the page unload regression test with gzip
- import `createOtlpSendBeaconExportDelegate` from the public entry
compression

- keep comments within 80 columns
- fix a typo in the README
- Next.js fails Edge Runtime builds on a bare `CompressionStream`
  reference
CompressionAlgorithm

- drop the duplicate enum from the base configuration, so the enum
  exported from the root matches the option type
- remove the unused import from the Node.js configuration
// would not survive.
const suppressedContext = suppressTracing(context.active());

// Compressed first so that the keepalive budget counts the bytes sent.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we make the timeout cover compression too? Right now, gzip runs before the timer starts, so slow or stalled compression can exceed the timeout or hang flushing.

@YangJonghun YangJonghun Oct 11, 2026 •

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.

Thanks for the review, fixed in 1ec50b4

- Start the abort timer before compressing, so compression time counts
  toward the timeout
- Pass the timeout signal to the compression pipe, so a stalled
  compressor fails the export instead of hanging

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

browser Browser-specific additions or benefits

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants