Skip to content

feat(otel)!: compress span exports with gzip by default - #1954

Merged
hassiebp merged 1 commit into
prepare-v5-releasefrom
lfe-16935-make-gzip-default-for-otel-span-transport
Oct 7, 2026
Merged

hassiebp merged 1 commit into
prepare-v5-releasefrom
lfe-16935-make-gzip-default-for-otel-span-transport

Conversation

@hassiebp

@hassiebp hassiebp commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

What does this PR do?

The default OTLP exporter now gzip-compresses span batches unless configured otherwise, matching the JS SDK (langfuse-js#978). Every Langfuse v4 server accepts gzip, and v5 is v4-only, so the old "gzip requires server v3.30" caveat is gone.

Resolution order (first valid value wins):

  1. the otel_compression client argument
  2. LANGFUSE_OTEL_COMPRESSION
  3. OTEL_EXPORTER_OTLP_TRACES_COMPRESSION
  4. OTEL_EXPORTER_OTLP_COMPRESSION
  5. gzip

Values are case-insensitive (" GZIP " and None work). As in JS, an invalid value falls through to the next setting instead of disabling compression:

  • an invalid argument or LANGFUSE_OTEL_COMPRESSION logs a warning;
  • invalid OTEL variables are skipped silently.

deflate, which the OTEL SDK would otherwise accept, is treated as invalid, because the Langfuse endpoint only decodes gzip. Set any of these to none to send uncompressed. Custom span_exporters are unaffected.

Docstrings for otel_compression (client.py) and LANGFUSE_OTEL_COMPRESSION (environment_variables.py) are updated.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Refactor
  • Documentation update
  • Tooling, CI, or repo maintenance

Verification

uv run --frozen ruff check .                       # All checks passed!
uv run --frozen mypy langfuse --no-error-summary   # clean
uv run --frozen pytest -q tests/unit/test_span_processor.py  # 27 passed (4 new precedence cases failed before the change)
uv run --frozen pytest -n auto tests/unit          # 782 passed, 2 skipped
# against a local Langfuse server (4.53.0, events_only), gzip on the wire:
uv run --frozen pytest -n 4 tests/e2e/test_core_sdk.py tests/e2e/test_experiments.py  # 67 passed; the same 3 experiment tests also fail on the base branch locally

The precedence test checks the Content-Encoding actually sent to a local OTLP HTTP server, for 14 combinations. The batch-size-limit tests now compare decompressed body sizes, since the limit applies to the uncompressed payload.

Checklist

  • I self-reviewed the diff using code_review.md.
  • I added or updated tests for behavior changes.
  • I updated docs, examples, or .env.template if needed.
  • I did not hand-edit generated files; if generated files changed, I used the upstream regeneration path.
  • I did not commit secrets or credentials.
Open in Web Open in Cursor 

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no actionable issues were found.

What we checked:

  • Custom exporters stay unchanged: The server-export setup calls _resolve_compression only when span_exporter is absent. A supplied exporter keeps its own compression settings.
Summary

The default span exporter now uses gzip unless a valid setting selects none.

  • Compression settings follow the documented order and accept mixed case.
  • Invalid settings fall through rather than reaching the OpenTelemetry exporter.
  • Tests add real-request checks for precedence and measure decompressed bodies for batch-size assertions.
  • No actionable issues were found.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Create span processor] --> B{Custom exporter provided?}
  B -->|Yes| C[Keep custom exporter unchanged]
  B -->|No| D[Check otel_compression]
  D --> E{Valid gzip or none?}
  E -->|Yes| J[Configure default exporter]
  E -->|No| F[Check LANGFUSE_OTEL_COMPRESSION]
  F --> G{Valid gzip or none?}
  G -->|Yes| J
  G -->|No| H[Check traces-specific then generic OTEL setting]
  H --> I{Valid gzip or none?}
  I -->|Yes| J
  I -->|No| K[Use gzip]
  K --> J
Loading

Reviews (1) · Last reviewed commit: "feat(otel)!: compress span exports with ..." · Reviewed by Greptile

The default OTLP exporter now gzips span batches unless configured
otherwise. Resolution order: the otel_compression argument,
LANGFUSE_OTEL_COMPRESSION, OTEL_EXPORTER_OTLP_TRACES_COMPRESSION,
OTEL_EXPORTER_OTLP_COMPRESSION, then gzip. Values are case-insensitive
and an invalid value falls through to the next setting, matching the JS
SDK. Set any of them to "none" to send uncompressed.

Co-authored-by: Hassieb Pakzad <hassiebp@users.noreply.github.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 7, 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-10-07T21:04:01.394350Z b2b2a80 PR opened
ℹ️ 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.

@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

@claude review

@claude claude 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.

Claude Code Review

No review was started: this request came from a bot account. Manual reviews can only be requested by someone with write access to this repository. Ask a maintainer to comment @claude review, or have your automation post the comment from a user account with write access.

Tip: disable this comment in your organization's Code Review settings.

@claude claude 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.

LGTM, a focused and well-tested config/behavior change. Reviewed the new _parse_compression/_resolve_compression precedence chain in span_processor.py (argument, LANGFUSE_OTEL_COMPRESSION, OTEL_EXPORTER_OTLP_TRACES_COMPRESSION, OTEL_EXPORTER_OTLP_COMPRESSION, then gzip default) and confirmed it matches the updated docstrings in client.py/environment_variables.py. Checked the expanded precedence test and the batch-size-limit tests' new _uncompressed_size helper, which correctly decompresses gzip bodies before comparing against the uncompressed-payload size limit.

Extended reasoning...

The change touches only compression-resolution logic for the OTLP span exporter in a Python SDK (langfuse/_client/span_processor.py, client.py, environment_variables.py) plus unit tests; no auth, crypto, or data-exposure surface is involved. It is a self-contained, mechanical rework of an existing fallback chain with a well-reasoned default (gzip, matching the JS SDK and documented server-compatibility rationale), and the accompanying test suite was substantially expanded to cover case-insensitivity, precedence ordering, and invalid-value fallthrough for all four sources plus the new default. I traced the implementation against the docstring claims and the PR description and found them consistent, with no logic gaps.

@hassiebp
hassiebp merged commit 6d8c760 into prepare-v5-release Oct 7, 2026
17 checks passed
@hassiebp
hassiebp deleted the lfe-16935-make-gzip-default-for-otel-span-transport branch October 7, 2026 21:20
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