Skip to content

Point Claude Code's telemetry at the local collector - #69

Merged
esnible merged 1 commit into
mainfrom
claude-otel-env
Aug 17, 2026
Merged

Point Claude Code's telemetry at the local collector#69
esnible merged 1 commit into
mainfrom
claude-otel-env

Conversation

@esnible

@esnible esnible commented Aug 17, 2026

Copy link
Copy Markdown
Member

Adds authbridge exec --with-claude-otel, which gives the hosted command the variables that make Claude Code export traces to a local collector:

rossoctl otel collect
rossoctl authbridge exec --with-claude-otel --config ./authbridge.yaml -- claude

OTEL_EXPORTER_OTLP_ENDPOINT is built from httpEndpoint in ~/.config/rossoctl/otel-config.yaml; the rest are static. Reading that record rather than assuming a port means the flag fails, naming otel collect, when no collector has been started here.

--otel-endpoint <url> overrides the endpoint for a collector this host did not start, and then the record is not read at all. It requires --with-claude-otel, since it sets one of the variables that flag turns on.

Also changes the recorded httpEndpoint to 127.0.0.1:4318 from 0.0.0.0:4318. The receiver still binds the wildcard inside the container — loopback there is unreachable through a published port — but the recorded value is consumed as a destination, and http://0.0.0.0:4318 is not one. The rewrite runs on read too, so existing records still work.

Plus a .gitignore entry for mlflow.db.

Verified end to end: a child launched with the flag POSTed a span to its own $OTEL_EXPORTER_OTLP_ENDPOINT/v1/traces and the running collector logged it.

Assisted by Claude.

`authbridge exec --with-claude-otel` gives the hosted command the variables that
make Claude Code export traces: CLAUDE_CODE_ENABLE_TELEMETRY,
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA, the OTEL_* transport settings, and
OTEL_EXPORTER_OTLP_ENDPOINT built from httpEndpoint in
~/.config/rossoctl/otel-config.yaml. Reading that record rather than assuming a
port means the flag fails, naming `otel collect`, when no collector has been
started here — a child pointed at an absent collector drops spans silently.

--otel-endpoint overrides the endpoint with a full URL, for a collector this host
did not start; the record is then not read at all. It sets one of the variables
--with-claude-otel turns on, so passing it alone is an error rather than an
implied opt-in. The scheme is checked by prefix before url.Parse, because a bare
host:port otherwise fails with "first path segment in URL cannot contain colon",
which describes the parser instead of naming the fix.

The recorded httpEndpoint is now 127.0.0.1:4318 rather than 0.0.0.0:4318. The
receiver still binds the wildcard inside the container, where loopback would be
unreachable through a published port, but the recorded value is consumed as a
destination: it becomes an OTEL_EXPORTER_OTLP_ENDPOINT, and an exporter sending
to http://0.0.0.0:4318 relies on the platform reinterpreting it. The rewrite also
runs on read, so a record written before this change still yields a usable URL.

The environment is layered onto host.env, which is nil when no forward proxy runs
and means "inherit" to exec.Cmd. It is expanded first: appending to the nil would
have given the child only these variables, with no PATH. An already-exported
variable is kept and reported, as the proxy and CA settings are.

Also ignores mlflow.db, the backing store `mlflow server` writes into the working
directory.

Assisted by Claude.

Signed-off-by: Ed Snible <snible@us.ibm.com>
@esnible
esnible merged commit 09fd535 into main Aug 17, 2026
2 checks passed
@esnible
esnible deleted the claude-otel-env branch August 17, 2026 20:01
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.

1 participant