Skip to content

fix(otel): parameterize file exporter path; honor CLAUDE_CODE_TMPDIR#315

Open
lcatlett wants to merge 1 commit into
Kastalien-Research:mainfrom
lcatlett:fix/otel-collector-file-export-path
Open

fix(otel): parameterize file exporter path; honor CLAUDE_CODE_TMPDIR#315
lcatlett wants to merge 1 commit into
Kastalien-Research:mainfrom
lcatlett:fix/otel-collector-file-export-path

Conversation

@lcatlett

Copy link
Copy Markdown

Summary

The OTEL Collector file exporter hardcoded /tmp/claude-code-{events,metrics}.jsonl inside the distroless container. The default uid (10001) cannot write to the container's /tmp on macOS bind-mount setups, producing:

can't open new logfile: open /tmp/claude-code-metrics.jsonl: permission denied

Host-side chmod or symlinking does not reach the container filesystem, so this needs a config + compose fix rather than a host workaround.

Changes

  • otel-collector/config.yaml, otel-collector/config-with-prometheus.yaml — Replace hardcoded /tmp/... with ${env:OTEL_FILE_EXPORT_DIR}/... so the in-container target is configurable instead of baked into a checked-in file.
  • docker-compose.yml (otel-collector service):
    • OTEL_FILE_EXPORT_DIR=/var/log/otel (in-container mount point — fixed).
    • Bind-mount ${CLAUDE_CODE_TMPDIR:-./otel-collector/data}/otel:/var/log/otel. The /otel sub-namespace prevents collector output from sharing a directory with Claude Code's per-uid runtime tmpdir (claude-<uid>/).
    • user: "0:0" so writes succeed regardless of bind-mount ownership on macOS.
  • otel-collector/enable-telemetry.sh — Default CLAUDE_CODE_TMPDIR to project-local ./otel-collector/data when not already exported.
  • .gitignore — Ignore otel-collector/data/.

Behavior

CLAUDE_CODE_TMPDIR exported in shell? Files land at
Yes (e.g. ~/.claude/tmp) $CLAUDE_CODE_TMPDIR/otel/claude-code-*.jsonl
No ./otel-collector/data/otel/claude-code-*.jsonl

Test plan

  • docker compose up -d otel-collector starts cleanly with no logfile error
  • OTLP HTTP POSTs to localhost:4318/v1/metrics return 200 partialSuccess: {}
  • File exporter writes to the configured host path; size grows under load
  • Sub-namespace (/otel/) keeps output isolated from claude-<uid>/
  • Verified via lsof that there is one writer and one active file (no duplicate writes)

Notes

  • docker-compose interpolates ${CLAUDE_CODE_TMPDIR} from the shell that invokes it, not from Claude Code's settings.json. Users who want the override to apply automatically should export it from their shell rc, an .env file, or enable-telemetry.sh.
  • For Cloud Run / stateless deployments, the file exporter remains a footgun — an OTLP exporter to a managed sink is the right move there. Out of scope for this PR.

The OTEL Collector file exporter hardcoded /tmp/claude-code-{events,metrics}.jsonl
inside the distroless container. The default uid (10001) cannot write to the
container's /tmp on macOS bind-mount setups, producing:

  can't open new logfile: open /tmp/claude-code-metrics.jsonl: permission denied

Host-side chmod or symlinking does not reach the container filesystem.

Changes:
- Replace hardcoded paths in both otel-collector configs with
  ${env:OTEL_FILE_EXPORT_DIR} so the container target is configurable.
- docker-compose: set OTEL_FILE_EXPORT_DIR=/var/log/otel (in-container mount
  point) and bind-mount ${CLAUDE_CODE_TMPDIR:-./otel-collector/data}/otel
  into it. The /otel sub-namespace prevents collector output from sharing a
  directory with Claude Code's per-uid runtime tmpdir (claude-<uid>/).
- Run the collector as root (user: "0:0") so writes succeed regardless of
  bind-mount ownership on macOS.
- enable-telemetry.sh: set CLAUDE_CODE_TMPDIR fallback to project-local
  ./otel-collector/data when not already exported.
- .gitignore: ignore otel-collector/data/.

Verified: collector starts cleanly; OTLP POSTs land at
$CLAUDE_CODE_TMPDIR/otel/claude-code-metrics.jsonl with rotation working.
@vercel

vercel Bot commented May 10, 2026

Copy link
Copy Markdown
Contributor

@lcatlett is attempting to deploy a commit to the Thoughtbox Team on Vercel.

A member of the Team first needs to authorize it.

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