Skip to content

feat(observability): export OTLP over HTTP/protobuf to any collector - #5082

Merged
krishicks merged 1 commit into
mainfrom
feat/5067-otlp-http-protocol/krishicks
Nov 2, 2026
Merged

krishicks merged 1 commit into
mainfrom
feat/5067-otlp-http-protocol/krishicks

Conversation

@krishicks

@krishicks krishicks commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Every OTLP export spoke gRPC only, so trace backends that accept only OTLP/HTTP, such as MLflow, needed a translating collector in between. Each [openshell.gateway.otlp] table now takes protocol = "grpc" or "http/protobuf", honored by gateway traces, OCSF logs, supervisor traces, the agent trace relay, and compute drivers' own spans.

Related Issue

Refs #5067. The next PR in this stack, which adds collector headers, closes it.

Changes

  • protocol on [openshell.gateway.otlp] and its traces, ocsf, and agent tables. A table without its own endpoint inherits the whole shared collector; a table with its own endpoint inherits nothing from it.
  • An endpoint with a query string is a configuration error for either protocol. Exporters send no query parameters, so a collector that needs them must take them as headers.
  • Compute drivers take the collectors through one SupervisorOtlpArgs flag set in openshell-core, behind a new clap feature. The flags read the same environment variables that supervisors receive, and the gateway's VM launcher uses the exported flag names. Drivers pass each lane to supervisors through one SupervisorOtlp value (OPENSHELL_OTLP_PROTOCOL, OPENSHELL_OTLP_OCSF_PROTOCOL, OPENSHELL_OTLP_AGENT_PROTOCOL), replacing the per-lane driver fields.
  • One OTLP/HTTP client in openshell-otel, shared by the SDK exporters and the relay, posts to /v1/traces or /v1/logs under the endpoint and bounds each request by the export timeout. A response that is cut short or larger than 64 KiB fails the export rather than counting as success. SDK exporters gzip their requests only when OTEL_EXPORTER_OTLP_COMPRESSION=gzip is set; the relay forwards batches uncompressed.
  • The relay's exporter supports both transports and shares its connect and keepalive settings with the HTTP client.
  • Supervisors log the protocol of each export they start.
  • e2e/rust and tests/suites/features lockfiles pick up opentelemetry-http.
  • Gateway configuration docs, the observability overview and traces pages, the Helm values description, the driver and supervisor READMEs, and the debug-openshell-cluster skill are updated. The Helm description points to gatewayConfig."openshell.gateway.otlp".protocol for an http/protobuf collector.

Release Notes

OTLP export can use OTLP/HTTP: set protocol = "http/protobuf" on [openshell.gateway.otlp] or any of its signal tables. gRPC stays the default. An OTLP endpoint with a query string is now a configuration error.

Testing

  • CI lint locally on this commit: tracked lockfile and alignment checks, cargo fmt --check, and every mise run rust:lint clippy invocation with --locked
  • cargo test -p openshell-otel, -p openshell-supervisor, -p openshell-core --features clap, the gateway VM launcher tests, and the server OTLP and config tests
  • Unit tests added/updated: config parsing and inheritance, query string rejection, the shared driver flags, protocol propagation to every driver and the supervisor, and HTTP export, gzip, header encoding, timeouts and their environment lookup, truncated and oversized responses, an unresponsive collector, and signal URLs against a loopback OTLP/HTTP collector
  • E2E tests added/updated (if applicable)

Tests for the other touched crates ran at the top of the stack.

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

@krishicks krishicks added area:docs Documentation and examples topic:observability Logging, metrics, and observability work area:supervisor Proxy and routing-path work area:gateway Gateway server and control-plane work area:compute labels Oct 30, 2026
@copy-pr-bot

copy-pr-bot Bot commented Oct 30, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@krishicks
krishicks added this pull request to stack #5085 October 30, 2026 22:12
@github-actions

Copy link
Copy Markdown

@krishicks
krishicks marked this pull request as ready for review October 30, 2026 22:14
@krishicks
krishicks force-pushed the feat/5067-otlp-http-protocol/krishicks branch from 0d79a30 to 26f001e Compare October 30, 2026 23:02

@rhuss rhuss left a comment

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.

cc-review Summary

This review comes from an agent-assisted pass (cc-review, with several reviewer agents plus Codex), and the PR holds up well: the new HTTP transport is tightly bounded and the config rules fail closed. All ten findings are Minor and non-blocking. The failure scenarios below were derived by reading the code; none of them were executed.

What Went Well

  • OtlpHttpClient::send wraps each request in AbortOnDrop, bounds it with a timeout and caps the response at 64 KiB through Limited. abandoned_requests_stop, truncated_responses_fail and oversized_responses_fail each pin one of those guarantees directly.
  • TryFrom<RawOtlpConfig> makes a lane inherit the whole shared collector or none of it and rejects a protocol without its own endpoint. OtlpCollectorConfig::checked refuses https with http/protobuf at load time instead of downgrading to plaintext, and otlp_lane_protocol_needs_its_own_endpoint covers every rejection branch.
  • SupervisorOtlp::environment and map_endpoints replace the per-driver env assembly and the Podman loopback-rewrite helpers with one shared type. The _PROTOCOL variable is emitted only for non-gRPC lanes (and vm.rs follows the same rule for CLI flags), so gRPC deployments keep a byte-identical supervisor environment and older supervisors keep working.
  • The relay's Exporter forwards agent batches as opaque pre-encoded bytes on both transports and sets the HTTP client deadline to EXPORT_TIMEOUT + CLIENT_TIMEOUT_MARGIN, so ExportError::Timeout means the same thing for gRPC and HTTP.

Findings

Severity File Description Source
Minor crates/openshell-driver-docker/README.md:13 Docker README and the otel_tracing.rs module doc still describe export as OTLP/gRPC only architecture agent
Minor crates/openshell-driver-docker/src/main.rs:48 OTLP lane flags and supervisor_otlp() are copied into all four driver binaries architecture agent
Minor crates/openshell-otel/src/lib.rs:261 The HttpsUnsupported guard in http_signal_url has no test test-quality agent
Minor crates/openshell-otel/src/logs.rs:39 Forwarded HTTP collector headers are percent-decoded twice codex
Minor crates/openshell-otel/src/transport.rs:4 Module doc says every exporter shares it; connect and keepalive constants are duplicated in the relay architecture agent
Minor crates/openshell-otel/src/transport.rs:32 export_timeout lookup order and fallback are untested test-quality agent
Minor crates/openshell-otel/src/transport.rs:39 Query strings now carry working credentials over HTTP, but endpoints are logged verbatim security agent
Minor crates/openshell-supervisor/src/main.rs:569 Supervisor OTLP startup logs omit the selected protocol (outside the diff) gator agent
Minor crates/openshell-supervisor/src/otlp_relay/exporter.rs:155 No silent-collector test for the HTTP relay exporter test-quality agent
Minor deploy/helm/openshell/values.yaml:395 Helm comment advertises 4318 for http/protobuf, but server.otlp has no way to set a protocol gator agent (also goal-alignment agent)

Outside the diff: The supervisor's OTLP exporting enabled and OTLP OCSF export enabled startup logs (crates/openshell-supervisor/src/main.rs:569 and 574) report only the endpoint, while the gateway's equivalent log now carries *_protocol fields. The protocol comes from an env var that is absent for gRPC (and ignored by older supervisor images), so the log can't tell those cases apart, and a transport mismatch only shows up later as export failures. Adding protocol = %args.otlp_protocol and protocol = %args.otlp_ocsf_protocol to the two info! calls would close the gap; it sits here rather than inline because those lines are not part of the changed hunks.

PR description note: The description says "HTTP exports are gzip-compressed", but SDK exporters compress only with OTEL_EXPORTER_OTLP_COMPRESSION=gzip (supervisors never receive OTEL_* variables) and the relay's export_http never compresses. Suggest rewording, or adding gzip to the relay if intended.

Out of scope here: TLS for http/protobuf (https endpoints, cleartext OCSF headers) is left to #5084.

Nice work overall. These are suggestions, not blockers, and the PR should be ready for a maintainer once they are addressed or answered.

Review Details

  • Findings posted: 10 (9 inline, 1 summary-only)
  • Findings reviewed and not posted: 4
  • Gate outcome: PASS
  • Participating reviewers: architecture, test-quality, security, gator, goal-alignment, codex (CodeRabbit timed out; correctness and production reported no posted findings)

Coverage note: one external reviewer (CodeRabbit) timed out, so this review is marked incomplete.

Comment thread crates/openshell-otel/src/lib.rs Resolved
Comment thread crates/openshell-otel/src/logs.rs Resolved
Comment thread crates/openshell-otel/src/transport.rs Resolved
Comment thread crates/openshell-otel/src/transport.rs Resolved
Comment thread crates/openshell-otel/src/transport.rs Resolved
Comment thread deploy/helm/openshell/values.yaml Resolved
Base automatically changed from chore/upgrade-opentelemetry/krishicks to main November 2, 2026 15:49
@krishicks
krishicks force-pushed the feat/5067-otlp-http-protocol/krishicks branch from 26f001e to c7c70a7 Compare November 2, 2026 15:49
Every OTLP export (gateway traces, OCSF logs, supervisor traces, and the
agent trace relay) spoke gRPC only, so trace backends that accept only
OTLP/HTTP needed a translating collector in between.

Each [openshell.gateway.otlp] table accepts protocol = "grpc" or
"http/protobuf". A table without its own endpoint uses the whole shared
collector; a table with its own endpoint inherits nothing from it. Compute
drivers take the collectors through one shared set of flags, read from
the same environment variables that supervisors receive, and pass them on
through one SupervisorOtlp value that replaces the per-lane driver fields.
OTLP/HTTP goes through a single client in openshell-otel, shared by the
SDK exporters and the relay, that bounds each request by the export
timeout and fails exports whose response is incomplete or larger than
64 KiB. Exporters send no query parameters, so an endpoint with a query
string is a configuration error.

Refs #5067

Signed-off-by: Kris Hicks <khicks@nvidia.com>
@krishicks
krishicks force-pushed the feat/5067-otlp-http-protocol/krishicks branch from c7c70a7 to b1f0313 Compare November 2, 2026 18:47
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

Compatibility review (advisory)

New or updated breaking changes; see the full report for all findings.

1. configuration — No explicit risk acceptance found

Gateway TOML previously accepted OTLP endpoint URIs containing query strings, but now rejects them during configuration loading, including default gRPC configurations.

  • Impact: Existing deployments with an endpoint such as http://collector:4317/?tenant=blue can no longer start the gateway, regardless of whether the collector used those parameters.
  • Action: Keep existing gRPC endpoint configurations loadable in v0.1.7, warning and ignoring unsupported query parameters instead of aborting startup.
  • PR: feat(observability): export OTLP over HTTP/protobuf to any collector #5082
Review details
  • Execution: complete
  • Candidate: PR #5082 (e08cf8489a894cc1f5061b7fcb7b2ec9ef64490d)
  • Baseline: 00528d24a6c361349a3e5d4926c22a5aa4b8a978 (00528d24a6c361349a3e5d4926c22a5aa4b8a978)
  • Reviewed: rust-sdk, python-sdk, go-sdk, typescript-sdk, api-behavior, cli, configuration, policy, helm, state

Advisory review; publication gates are unchanged.

Branch check run

@TaylorMutch TaylorMutch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed the updated head b1f0313, including the shared driver flags, endpoint validation, header escaping, and collector timeout coverage. No blocking findings.

Local validation on this head: all 48 openshell-otel tests passed, along with the targeted sandbox_env tests in openshell-core with the clap feature enabled.

The earlier head c7c70a7 also passed a local Docker sandbox smoke test: three agent export/exit cycles with correct attribution and delivery before completion, plus HTTP/protobuf traces from the gateway, Docker driver, supervisor, and agent, OCSF logs, signal paths, and configured gzip compression. The end-to-end smoke test was not repeated on the updated head.

@rhuss rhuss left a comment

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.

cc-review found no issues at b1f0313.

Merged via the queue into main with commit 9cc5f6e Nov 2, 2026
85 of 90 checks passed
@krishicks
krishicks deleted the feat/5067-otlp-http-protocol/krishicks branch November 2, 2026 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:compute area:docs Documentation and examples area:gateway Gateway server and control-plane work area:supervisor Proxy and routing-path work topic:observability Logging, metrics, and observability work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants