Describe the feature or problem you'd like to solve
Copilot CLI's OpenTelemetry support (shipped in copilot monitoring, closed via #2471 / #1911 / #1565) only exports OTLP over HTTP as application/json. The standard OTEL_EXPORTER_OTLP_PROTOCOL env var is silently ignored, and COPILOT_OTEL_EXPORTER_TYPE only accepts otlp-http or file. There's no way to switch to application/x-protobuf without forking the CLI.
Confirmed empirically with a local OTLP listener and Copilot CLI 1.0.34:
env -u OTEL_EXPORTER_OTLP_PROTOCOL … → Content-Type: application/json
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf … → Content-Type: application/json (identical)
User-Agent OTel-OTLP-Exporter-JavaScript/0.213.0 on both runs pins the bundled package to @opentelemetry/exporter-trace-otlp-http@0.213.0 — the JSON-only HTTP exporter. Switching to @opentelemetry/exporter-trace-otlp-proto@0.213.0 (same version, sibling package) is a near-one-line change that would make any of the three protocol env vars above take effect.
Why it matters
OTLP backends vary in what they accept on HTTP:
- Protobuf-only or protobuf-preferred: many OTel Collectors behind strict load balancers, some enterprise telemetry ingestion paths, and specific vendor endpoints. Without a protobuf option, clients can't send to these targets from Copilot CLI at all.
- Both: Jaeger, Grafana OTLP, Datadog, New Relic, Azure Monitor accept both formats. No regression risk if protobuf is made opt-in.
Even for backends that nominally accept JSON, some JSON parsers are non-spec-compliant in ways that silently corrupt OTLP IDs (e.g. proto3-default base64 decoding applied to OTel's spec-required hex traceId/spanId, per OTLP 1.10.0 §JSON encoding). Protobuf sidesteps that class of bug entirely because the IDs are transported as raw bytes.
Today the only workaround is a local JSON→protobuf transcoding proxy per user — real operational overhead for what is fundamentally a one-line SDK package swap.
Proposed solution
Option A (minimal): accept a new value for COPILOT_OTEL_EXPORTER_TYPE, e.g. otlp-http-proto (or otlp-http-protobuf), that selects @opentelemetry/exporter-trace-otlp-proto and @opentelemetry/exporter-metrics-otlp-proto instead of the -http variants. Same endpoint/URL semantics, just different Content-Type: application/x-protobuf.
Option B (standards-aligned): honor the standard OTEL_EXPORTER_OTLP_PROTOCOL / OTEL_EXPORTER_OTLP_TRACES_PROTOCOL / OTEL_EXPORTER_OTLP_METRICS_PROTOCOL env vars with values http/json (current default) and http/protobuf. This matches the Python OTel SDK's behavior and what users coming from other ecosystems expect. The OTel spec documents this as the canonical protocol selector: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-options
Both options are small code changes — the exporter packages are designed to be interchangeable drop-ins. Option B has more future-proofing value; Option A is faster to ship.
Example
OTEL_EXPORTER_OTLP_ENDPOINT=https://my-otel-collector.example.com \
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf \
OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer $TOKEN" \
copilot -p "hello"
Expected: OTLP POSTs leave the CLI with Content-Type: application/x-protobuf and the serialized ExportTraceServiceRequest / ExportMetricsServiceRequest protobuf messages in the body.
Additional context
Affected version: 1.0.34 (verified) — bundled npm @opentelemetry/exporter-trace-otlp-http@0.213.0.
Describe the feature or problem you'd like to solve
Copilot CLI's OpenTelemetry support (shipped in
copilot monitoring, closed via #2471 / #1911 / #1565) only exports OTLP over HTTP asapplication/json. The standardOTEL_EXPORTER_OTLP_PROTOCOLenv var is silently ignored, andCOPILOT_OTEL_EXPORTER_TYPEonly acceptsotlp-httporfile. There's no way to switch toapplication/x-protobufwithout forking the CLI.Confirmed empirically with a local OTLP listener and Copilot CLI 1.0.34:
env -u OTEL_EXPORTER_OTLP_PROTOCOL …→Content-Type: application/jsonOTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf …→Content-Type: application/json(identical)User-Agent
OTel-OTLP-Exporter-JavaScript/0.213.0on both runs pins the bundled package to@opentelemetry/exporter-trace-otlp-http@0.213.0— the JSON-only HTTP exporter. Switching to@opentelemetry/exporter-trace-otlp-proto@0.213.0(same version, sibling package) is a near-one-line change that would make any of the three protocol env vars above take effect.Why it matters
OTLP backends vary in what they accept on HTTP:
Even for backends that nominally accept JSON, some JSON parsers are non-spec-compliant in ways that silently corrupt OTLP IDs (e.g. proto3-default base64 decoding applied to OTel's spec-required hex
traceId/spanId, per OTLP 1.10.0 §JSON encoding). Protobuf sidesteps that class of bug entirely because the IDs are transported as raw bytes.Today the only workaround is a local JSON→protobuf transcoding proxy per user — real operational overhead for what is fundamentally a one-line SDK package swap.
Proposed solution
Option A (minimal): accept a new value for
COPILOT_OTEL_EXPORTER_TYPE, e.g.otlp-http-proto(orotlp-http-protobuf), that selects@opentelemetry/exporter-trace-otlp-protoand@opentelemetry/exporter-metrics-otlp-protoinstead of the-httpvariants. Same endpoint/URL semantics, just differentContent-Type: application/x-protobuf.Option B (standards-aligned): honor the standard
OTEL_EXPORTER_OTLP_PROTOCOL/OTEL_EXPORTER_OTLP_TRACES_PROTOCOL/OTEL_EXPORTER_OTLP_METRICS_PROTOCOLenv vars with valueshttp/json(current default) andhttp/protobuf. This matches the Python OTel SDK's behavior and what users coming from other ecosystems expect. The OTel spec documents this as the canonical protocol selector: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md#configuration-optionsBoth options are small code changes — the exporter packages are designed to be interchangeable drop-ins. Option B has more future-proofing value; Option A is faster to ship.
Example
Expected: OTLP POSTs leave the CLI with
Content-Type: application/x-protobufand the serializedExportTraceServiceRequest/ExportMetricsServiceRequestprotobuf messages in the body.Additional context
copilot help monitoring) listsCOPILOT_OTEL_EXPORTER_TYPEbut noOTEL_EXPORTER_OTLP_PROTOCOL.gen_ai.client.operation.duration,github.copilot.tool.call.*) — any fix should cover both signals.Affected version: 1.0.34 (verified) — bundled npm
@opentelemetry/exporter-trace-otlp-http@0.213.0.