opencode icon indicating copy to clipboard operation
opencode copied to clipboard

Add OpenTelemetry instrumentation for the AI SDK

Open BrianVandenberg-vivint opened this issue 3 months ago • 0 comments

Problem statement

opencode does not currently provide much visibility into the underlying behavior of the system as it relates to the AI SDK & API server.

The AI SDK integrates with OpenTelemetry to emit metrics & logs. This change-set enables support for those features, making it easy for developers and users of opencode to observe metrics & logs emitted by the AI SDK.

Summary of changes

  • What: Adds opt-in OpenTelemetry (OTEL) observability for traces/logs to the opencode CLI for the AI SDK
  • Why: Provide optional local observability for debugging and diagnostics while keeping telemetry disabled by default and avoiding Node-only imports in alternative runtimes.

Files Changed

  • Docs:
    • /README.md — adds an "OpenTelemetry logs & metrics" section with usage examples and recommendations.
  • Dependencies:
    • packages/opencode/package.json — adds @opentelemetry/sdk-node, @opentelemetry/exporter-trace-otlp-grpc, and @opentelemetry/exporter-trace-otlp-http.
  • Code:
    • packages/opencode/src/util/telemetry.ts — new module exporting aiSdkTelemetrySettings and initOpenTelemetry(); dynamically imports Node OTEL SDK and starts a NodeSDK when enabled.
    • packages/opencode/src/index.ts — calls initOpenTelemetry() during CLI startup so OTEL can initialize early (only when enabled).
    • AI SDK wiring: pass aiSdkTelemetrySettings into relevant requests so the AI SDK can emit telemetry when enabled
      • packages/opencode/src/agent/agent.ts
      • packages/opencode/src/session/compaction.ts
      • packages/opencode/src/session/prompt.ts
  • Developer tooling: convenience scripts for running otel-cli and pretty-print incoming telemetry
    • script/otel-listener.sh
    • script/otel-pretty-printer.jq

Implementation Details

  • Opt-in: Telemetry is enabled only when the USE_OTEL environment variable is set; otherwise aiSdkTelemetrySettings is undefined and behavior is unchanged.
  • Dynamic import: initOpenTelemetry() uses dynamic import() so Node-only OpenTelemetry packages are not loaded unless telemetry is requested.
  • Default exporter: If OTEL_EXPORTER_OTLP_PROTOCOL is not set, a default OTLP gRPC exporter is created; setting various OTEL env vars allows full exporter customization.
  • Safe failure: OTEL initialization errors are caught and emitted as warnings to stderr (no CLI crash).

Testing

  1. Start a local listener: script/otel-listener.sh (requires otel-cli and jq to be installed)
  2. Run the CLI with telemetry: USE_OTEL=1 opencode (or USE_OTEL=1 bun dev in development)
  3. Verify output: The listener should receive/print traces emitted by the AI SDK (note: currently only the AI SDK is configured to emit telemetry).

Notes for reviewers

  • Dependencies: New OTEL packages were added to packages/opencode; ensure CI/installers pick those up when running Node-based workflows.
  • Runtime safety: Confirm dynamic import behavior is correct for both Node and Bun
  • Telemetry scope: The implementation configures the AI SDK to emit telemetry via OpenTelemetry
  • Scripts: script/otel-listener.sh assumes otel-cli and jq are installed and that script/otel-pretty-printer.jq is executable.

Risk & Backwards compatibility

  • Experimental functionality: The AI SDK provides this functionality as an experimental feature (doc link), so this could stop working down the road without warning. Best case: it silently stops working, worst case it fails to run on a newer version of the SDK, though this would be observed by devs updating dependencies, not by users.
  • Default behavior preserved: No runtime change unless USE_OTEL is set
  • Installer size: OTEL was already a transitive dependency, so it's unlikely the size changed noticeably
  • Robustness: Initialization failures are non-fatal and surface as warnings only

Screenshots

image image image image image image

BrianVandenberg-vivint avatar Sep 22 '25 19:09 BrianVandenberg-vivint