Skip to content

feat(server): allow custom headers on OTLP export (T3CODE_OTLP_HEADERS) #4040

Description

@ephraimduncan

Problem

I'm trying to export t3code traces to telemetry.dev. Its OTLP endpoint requires auth on every request:

export T3CODE_OTLP_TRACES_URL=https://ingest.telemetry.dev/v1/traces
export T3CODE_OTLP_METRICS_URL=https://ingest.telemetry.dev/v1/metrics
# ...but there is no way to send the required header:
# Authorization: Bearer td_live_...

The exporters can only talk to unauthenticated endpoints. apps/server/src/observability/Layers/Observability.ts calls OtlpTracer.make and OtlpMetrics.layer with just url, exportInterval, and resource. Both APIs accept a headers option, but nothing in apps/server/src/cli/config.ts exposes it, and Effect's OTEL_EXPORTER_OTLP_HEADERS env support only applies to layerFromConfig, which isn't used here.

This isn't specific to telemetry.dev — Honeycomb, Grafana Cloud, and Dash0 all authenticate with a header too. The local Grafana LGTM flow in the docs works because it skips auth entirely. For any hosted backend, the only workaround today is running a local OTel Collector whose sole job is injecting the header:

t3code ──OTLP──▶ collector (adds Authorization) ──OTLP──▶ hosted backend

That's a lot of infrastructure for one HTTP header.

Proposal

Add a T3CODE_OTLP_HEADERS env var using the OTEL_EXPORTER_OTLP_HEADERS wire format (comma-separated key=value pairs):

export T3CODE_OTLP_HEADERS="Authorization=Bearer td_live_..."
  • Parse it in EnvServerConfig (apps/server/src/cli/config.ts), consistent with the existing T3CODE_OTLP_* vars
  • Thread it through ServerConfig and spread headers into both the OtlpTracer.make and OtlpMetrics.layer calls
  • Document it in docs/operations/observability.md next to the other OTLP vars

Notes

  • No behavior change when the var is unset; the local LGTM/Tempo flow is unaffected.

Happy to send a PR for this if the approach sounds right.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions