Skip to content

schemaitat/opencode-otel-observability

Repository files navigation

OpenCode Observability Stack

License Docker Docs

A self-contained observability stack for OpenCode. OpenCode does not emit telemetry on its own — opencode-plugin-otel is the plugin that instruments it and exports traces, metrics, and logs over OTLP. This repo is the receiving end for that data: an OTLP collector, Tempo, Prometheus, and Loki feeding a Grafana dashboard with cost/token analytics, TraceQL-based explainability, and a standalone session timeline (waterfall) explorer. Without the plugin installed in OpenCode, there is nothing for any of this to show.

This repo, especially the grafana dashboard and docker compose config, is mostly taken from ColeMurray/claude-code-otel. The trace explorer serves as a local debugging tool only (asof now) and could be in a next step generalized to work for more coding agents by adapting to different OTEL exporters.

Screenshots

Grafana dashboard Trace Explorer — Overview
Grafana OpenCode Observability dashboard Trace Explorer Overview view
Trace Explorer — Sessions
Trace Explorer Sessions view

Prerequisites

  • Docker with Compose v2 (docker compose)
  • just (optional — wraps common commands)
  • Bun (only for Option B — building the plugin from source)
  • uv (only for just setupscripts/setup.sh uses uv run python to edit opencode.json)

Quick Start

1. Start the observability stack

docker compose up -d
# or: just up

2. Install and configure the plugin

The plugin exists in two places:

  • DEVtheOPS/opencode-plugin-otel — upstream, published to npm as @devtheops/opencode-plugin-otel. Options A and B below install from here.

  • schemaitat/opencode-plugin-otel — André Schemaitat's fork. Synced with upstream and adds an opt-in long-running session span mode: with OPENCODE_LONG_RUNNING_SESSION_SPANS=1 (or the longRunningSessionSpans plugin option) a single root opencode.session span stays open for a primary session's entire lifetime — from session.created through session.deleted — so every turn's LLM and tool spans nest under one cohesive trace instead of a separate root span per turn. This change is currently in PR #98 (not yet merged upstream). Trace Explorer works either way — without the flag its session timeline still renders, the spans just aren't necessarily nested under a single root session span.

    Upstream behaviour (default): the root session span is closed on each session.idle, and every subsequent user turn gets its own independent root run span keyed by message ID — producing separate trace trees per turn rather than one session-wide tree. The fork's flag is off by default, so it matches this behaviour unless you enable it. Subagent sessions nest under their parent session's trace regardless of the flag.

Option A — npm (recommended, no build step):

Add the plugin to ~/.config/opencode/opencode.json (merge into your existing config):

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["@devtheops/opencode-plugin-otel"]
}

OpenCode installs it automatically at startup from the npm registry. The published package includes pre-built output — no Bun required.

Option B — local file: path (for development/customization):

Clone and build the plugin manually first — OpenCode does not build it for you:

git clone https://github.com/DEVtheOPS/opencode-plugin-otel ~/projects/opencode-plugin-otel
cd ~/projects/opencode-plugin-otel
bun install
bun run build

Then reference it by absolute path:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["file:///home/you/projects/opencode-plugin-otel"]
}

Note: ~ is not valid here — use the full absolute path. OpenCode symlinks the directory into its cache; if dist/ is missing or stale the plugin loads silently but does nothing. Re-run bun run build after any source change.

Git URLs (e.g. github:DEVtheOPS/opencode-plugin-otel) do not work — the prepare script is absent so the build never runs and dist/ is never produced.

Option C — automated (just setup):

just setup

Runs scripts/setup.sh: adds the upstream npm plugin (@devtheops/opencode-plugin-otel) to ~/.config/opencode/opencode.json and starts the stack — all in one step. This is the scripted equivalent of Option A (no clone, no build); OpenCode installs the plugin from npm at startup. For the long-running single-session trace behaviour, install the fork manually via Option B and set OPENCODE_LONG_RUNNING_SESSION_SPANS=1 (see step 3) until PR #98 lands upstream.

3. Enable telemetry

Export environment variables before running opencode:

export OPENCODE_ENABLE_TELEMETRY=1
export OPENCODE_OTLP_ENDPOINT=http://localhost:4317
export OPENCODE_OTLP_PROTOCOL=grpc

# Optional (fork / Option C only): keep one root span open for the whole primary
# session so all turns nest into a single trace, matching the Trace Explorer timeline.
export OPENCODE_LONG_RUNNING_SESSION_SPANS=1

Or add these to your shell profile (.bashrc, .zshrc, etc.).

Verify the plugin is configured and built before running OpenCode:

just check-otel-plugin

4. Access the dashboards

Dashboards will be empty until you run OpenCode (step 5).

URL Service
http://localhost:3000 Grafana — "OpenCode Observability" (admin/admin)
http://localhost:8060 Trace Explorer
http://localhost:9090 Prometheus
http://localhost:3200 Tempo
http://localhost:4317 OTLP collector — gRPC ingest (used by the plugin)
http://localhost:3100 Loki

5. Run OpenCode

Now when you run opencode, traces and metrics will be emitted to the local OTLP collector and visible in the dashboards above.

See the Quick Start guide for the full walkthrough.

Uninstall

Stop the stack:

docker compose down
# or: just down

Remove the plugin config:

Remove the plugin entry from ~/.config/opencode/opencode.json:

{
  "plugin": ["@devtheops/opencode-plugin-otel"]
}

Delete that line (or the entire "plugin" key if it's the only entry).

If you installed from source (Option B), also delete the clone:

rm -rf ~/projects/opencode-plugin-otel

Also remove the telemetry env vars from your shell profile if you added them.

Features

  • Cost & token analytics — usage by model, agent, and session; breakdown by token type
  • Tool usage — call counts, average duration, and success rate per tool
  • Productivity — lines added/removed, message counts per session
  • TraceQL tables — LLM calls (prompt → model → outcome) and tool calls (tool → params → result)
  • Trace → Logs linking — click a span in Grafana to jump to matching Loki logs
  • Trace Explorer — React/FastAPI waterfall SPA with session timelines, subagent linking, and a cross-session usage dashboard
  • Dashboard filterssession_id, model, and agent template variables apply to every panel

Available Metrics

The @devtheops/opencode-plugin-otel plugin instruments OpenCode and exports the following (default OTel prefix opencode.). Counters surface in Prometheus with ._ and a _total suffix — e.g. opencode.session.count becomes opencode_session_count_total. See docs/telemetry.md for the full label sets.

Core Metrics

  • opencode.session.count — sessions started (is_subagent)
  • opencode.lines_of_code.count — lines of code modified (type=added/removed)
  • opencode.commit.count — Git commits created
  • opencode.cost.usage — session cost by model and agent (USD)
  • opencode.token.usage — token usage by type (input/output/reasoning/cacheRead/cacheCreation)
  • opencode.cache.count — cache read/creation events
  • opencode.message.count — assistant messages by model and agent
  • opencode.model.usage — requests per model and provider
  • opencode.tool.duration — tool execution duration histogram (tool_name, success)
  • opencode.session.duration — session duration histogram
  • opencode.subtask.count — subagent (task tool) invocations
  • opencode.retry.count — API request retries

Event Data (Loki logs, {service_name="opencode"})

  • user_prompt — user prompt submissions (prompt_length, model)
  • api_request — API requests with duration, token counts, and cost
  • api_error — API errors with status codes
  • tool_result — tool execution results and timings (tool_name, success, duration_ms)
  • tool_decision — tool permission decisions
  • subtask_invoked — subagent task invocations
  • session.created / session.idle / session.deleted / session.error — session lifecycle with running total_* counters
  • commit — Git commit activity

Documentation

Full documentation is published at schemaitat.github.io/opencode-otel-observability, or browse it directly in docs/:

References

This repo, especially the grafana dashboard and docker compose config, is mostly taken from ColeMurray/claude-code-otel.

License

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors