Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 0 additions & 103 deletions .github/workflows/codex.yml

This file was deleted.

9 changes: 8 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,16 @@ src/
- **Model context capture** — opt-in only, text parts only, bounded; never serialize full media or structured tool payloads into span attributes.
- **Multi-location configuration** — process-wide exporters require identical telemetry configuration; reject a conflicting setup and derive project attributes from the observed session, not the loading location.
- **Shutdown** — providers are flushed (never shut down) on plugin cleanup and once per process on `beforeExit`. Shutting down the global OTel providers poisons them for the rest of the process.
- **All env vars are `OPENCODE_` prefixed** — `OPENCODE_ENABLE_TELEMETRY`, `OPENCODE_OTLP_ENDPOINT`, `OPENCODE_OTLP_METRICS_INTERVAL`, `OPENCODE_OTLP_LOGS_INTERVAL`, `OPENCODE_METRIC_PREFIX`, `OPENCODE_CAPTURE_PROMPT_IN_LOGS`, `OPENCODE_OTLP_HEADERS`, `OPENCODE_RESOURCE_ATTRIBUTES`, `OPENCODE_SPAN_ATTRIBUTES`. Never use bare `OTEL_*` names for plugin config. Headers are passed directly to exporters; `loadConfig` copies `OPENCODE_RESOURCE_ATTRIBUTES` → `OTEL_RESOURCE_ATTRIBUTES` before the SDK initializes.
- **All env vars are `OPENCODE_` prefixed** — `OPENCODE_ENABLE_TELEMETRY`, `OPENCODE_OTLP_ENDPOINT`, `OPENCODE_OTLP_METRICS_INTERVAL`, `OPENCODE_OTLP_LOGS_INTERVAL`, `OPENCODE_METRIC_PREFIX`, `OPENCODE_CAPTURE_PROMPT_IN_LOGS`, `OPENCODE_OTLP_HEADERS`, `OPENCODE_RESOURCE_ATTRIBUTES`, `OPENCODE_SPAN_ATTRIBUTES`, `OPENCODE_METRIC_ATTRIBUTES`, `OPENCODE_EXCLUDE_METRICS_ATTRIBUTES`, `OPENCODE_COST_USAGE_SCALE`. Never use bare `OTEL_*` names for plugin config. Headers are passed directly to exporters; `loadConfig` copies `OPENCODE_RESOURCE_ATTRIBUTES` → `OTEL_RESOURCE_ATTRIBUTES` before the SDK initializes.
- **Attribute channels are per-signal and independent** — all parsed with `parseAttributePairs` (`src/config.ts`):
- `OPENCODE_RESOURCE_ATTRIBUTES` → OTel `Resource` (producer metadata), applied in `buildResource` (`src/otel.ts`).
- `OPENCODE_SPAN_ATTRIBUTES` → **spans only**, threaded as `ctx.spanAttributes` and spread into each `tracer.startSpan` attribute block (run/llm/tool). Not in `commonAttrs`, so it never reaches logs or metrics.
- `OPENCODE_METRIC_ATTRIBUTES` → **metrics only**, merged via instrument wrapping in `createInstruments` (`src/otel.ts`, called from `acquireSharedOtel`); never touches spans or logs.
- `OPENCODE_EXCLUDE_METRICS_ATTRIBUTES` → **metrics only**, attribute keys stripped from each metric data point in `createInstruments` (e.g. `session.id`); applied last so it always wins over `OPENCODE_METRIC_ATTRIBUTES`.
- `commonAttrs` (just the per-session `project.id`) is the only set applied to all three signals.
- **`OPENCODE_ENABLE_TELEMETRY`** — all OTel instrumentation is gated on this env var (or the `enabled` plugin option). The plugin always loads regardless.
- **`OPENCODE_METRIC_PREFIX`** — defaults to `opencode.`; set to `claude_code.` for Claude Code dashboard compatibility.
- **`OPENCODE_COST_USAGE_SCALE`** — positive number (default `1`); multiplier applied **only** to the `cost.usage` counter (`recordUsageMetrics` in `src/handlers/step.ts`). Workaround for backends that round metric values to one decimal place (e.g. AppSignal). `session.cost.total`, spans, and log events keep raw USD. When ≠ 1, the `cost.usage` unit is `USD/<scale>`.
- **Plugin options** — read from `ctx.options` during `setup`. Precedence is option → `OPENCODE_*` env → default. Keep option keys 1:1 with `PluginConfig` field names.

## Commit message format
Expand Down
42 changes: 32 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ An [opencode](https://opencode.ai) plugin that exports telemetry via OpenTelemet
- [Datadog example](#datadog-example)
- [Honeycomb example](#honeycomb-example)
- [Claude Code dashboard compatibility](#claude-code-dashboard-compatibility)
- [Scaling cost.usage for backends that round metric values (`OPENCODE_COST_USAGE_SCALE`)](#scaling-costusage-for-backends-that-round-metric-values)
- [Local development](#local-development)
- [GitHub Discord notifications](#github-discord-notifications)

Expand Down Expand Up @@ -148,9 +149,12 @@ The environment variables (set them in your shell profile — `~/.zshrc`, `~/.ba
| `OPENCODE_DISABLE_TRACES` | *(unset)* | Comma-separated list of trace types to disable (`session`, `llm`, `tool`). Use `all`, `*`, `true`, or `1` to disable every trace type |
| `OPENCODE_OTLP_HEADERS` | *(unset)* | Comma-separated `key=value` headers added to all OTLP exports. **Keep out of version control — may contain sensitive auth tokens.** |
| `OPENCODE_OTLP_HEADERS_HELPER` | *(unset)* | Executable script/binary that returns dynamic OTLP headers as JSON after an auth failure. Helper headers override `OPENCODE_OTLP_HEADERS`. |
| `OPENCODE_RESOURCE_ATTRIBUTES` | *(unset)* | Comma-separated `key=value` pairs merged into the OTel resource. Example: `service.version=1.2.3,deployment.environment=production` |
| `OPENCODE_SPAN_ATTRIBUTES` | *(unset)* | Comma-separated `key=value` pairs attached to every emitted span, log event, and metric data point. Example: `team=platform,deployment.environment=production` |
| `OPENCODE_RESOURCE_ATTRIBUTES` | *(unset)* | Comma-separated `key=value` pairs merged into the OTel **resource** (describes the producer). Example: `service.version=1.2.3,deployment.environment=production` |
| `OPENCODE_SPAN_ATTRIBUTES` | *(unset)* | Comma-separated `key=value` pairs added to **spans only** (not logs, metrics, or the resource). Example: `team=platform,deployment.environment=production` |
| `OPENCODE_METRIC_ATTRIBUTES` | *(unset)* | Comma-separated `key=value` pairs added to **metric data points only** (not spans, logs, or the resource). Example: `deployment.environment=production` |
| `OPENCODE_EXCLUDE_METRICS_ATTRIBUTES` | *(unset)* | Comma-separated attribute keys stripped from **metric data points only** (not spans or logs). Applied last, so it always wins over `OPENCODE_METRIC_ATTRIBUTES`. Example: `session.id` to avoid high-cardinality session labels on counters and histograms |
| `OPENCODE_OTLP_METRICS_TEMPORALITY` | *(unset)* | Metrics aggregation temporality: `delta`, `cumulative`, or `lowmemory`. Required for Datadog (`delta`). Passed to the exporter and copied to `OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE`. |
| `OPENCODE_COST_USAGE_SCALE` | `1` | Multiplier applied to USD cost values before they are recorded as the `cost.usage` counter. Set to `1000000` for backends that round metric values to one decimal place (e.g. AppSignal) so per-message cents land as whole numbers. Only affects `cost.usage` — `session.cost.total`, spans, and log events keep raw USD. Divide by this value in dashboards to display dollars. |
| `OPENCODE_TRACEPARENT` | *(unset)* | W3C [`traceparent`](https://www.w3.org/TR/trace-context/#traceparent-header) string. When set, all spans are parented under this remote context so opencode traces nest inside a caller's trace (e.g. a CI job). Invalid values are logged and ignored. Note: with the default `ParentBased` sampler, a value with the sampled flag off (`...-00`) suppresses all trace export. |
| `OPENCODE_TRACESTATE` | *(unset)* | W3C [`tracestate`](https://www.w3.org/TR/trace-context/#tracestate-header) string, parsed alongside `OPENCODE_TRACEPARENT` and attached to the remote parent context. Ignored unless a valid `OPENCODE_TRACEPARENT` is also set. |
| `OPENCODE_TRACE_PROPAGATION_PROVIDERS` | *(unset)* | Comma-separated opencode provider IDs that receive W3C `traceparent` and `tracestate` headers on LLM requests. Use `*` to explicitly enable every provider. |
Expand Down Expand Up @@ -198,6 +202,9 @@ Option keys mirror the resolved config and map to the environment variables:
| `otlpHeadersHelper` | `OPENCODE_OTLP_HEADERS_HELPER` |
| `resourceAttributes` | `OPENCODE_RESOURCE_ATTRIBUTES` |
| `spanAttributes` | `OPENCODE_SPAN_ATTRIBUTES` |
| `metricAttributes` | `OPENCODE_METRIC_ATTRIBUTES` |
| `excludeMetricAttributes` | `OPENCODE_EXCLUDE_METRICS_ATTRIBUTES` (array, not a comma string) |
| `costUsageScale` | `OPENCODE_COST_USAGE_SCALE` |
| `traceparent` | `OPENCODE_TRACEPARENT` |
| `tracestate` | `OPENCODE_TRACESTATE` |
| `metricsTemporality` | `OPENCODE_OTLP_METRICS_TEMPORALITY` |
Expand Down Expand Up @@ -226,19 +233,19 @@ For `OPENCODE_OTLP_PROTOCOL=http/protobuf` or `OPENCODE_OTLP_PROTOCOL=http/json`
# Auth token for a managed collector (e.g. Honeycomb, Grafana Cloud)
export OPENCODE_OTLP_HEADERS="x-honeycomb-team=your-api-key,x-honeycomb-dataset=opencode"

# Tag every metric and log with deployment context
# Tag the OTel resource (producer metadata) with deployment context
export OPENCODE_RESOURCE_ATTRIBUTES="service.version=1.2.3,deployment.environment=production"

# Tag every span, log event, and metric point with filterable attributes
export OPENCODE_SPAN_ATTRIBUTES="team=platform,deployment.environment=production"
```
# Tag spans only (e.g. high-cardinality dimensions for trace drill-down)
export OPENCODE_SPAN_ATTRIBUTES="team=platform"

> **Security note:** `OPENCODE_OTLP_HEADERS` typically contains auth tokens. Set it in your shell profile (`~/.zshrc`, `~/.bashrc`) or a secrets manager — never commit it to version control or print it in CI logs.
# Tag metric data points only (e.g. low-cardinality dashboard dimensions)
export OPENCODE_METRIC_ATTRIBUTES="deployment.environment=production"
```

`OPENCODE_RESOURCE_ATTRIBUTES` and `OPENCODE_SPAN_ATTRIBUTES` are independent:
Each attribute channel targets a different signal: `OPENCODE_RESOURCE_ATTRIBUTES` → the OTel `Resource` (producer metadata); `OPENCODE_SPAN_ATTRIBUTES` → spans only; `OPENCODE_METRIC_ATTRIBUTES` → metric data points only. They are independent — a key set in one does not appear in the others.

- Use `OPENCODE_RESOURCE_ATTRIBUTES` for producer metadata on the OTel Resource.
- Use `OPENCODE_SPAN_ATTRIBUTES` for attributes that need to appear on each span, log event, and metric data point for filtering or grouping in backends.
> **Security note:** `OPENCODE_OTLP_HEADERS` typically contains auth tokens. Set it in your shell profile (`~/.zshrc`, `~/.bashrc`) or a secrets manager — never commit it to version control or print it in CI logs.

### Dynamic headers

Expand Down Expand Up @@ -407,6 +414,21 @@ export OPENCODE_OTLP_HEADERS="Authorization=Basic <base64-instance-id:api-key>"
export OPENCODE_METRIC_PREFIX=claude_code.
```

### Scaling cost.usage for backends that round metric values

Some observability backends round metric values to one decimal place server-side (AppSignal is one example). Per-message cost values like `$0.023` then collapse to `0.0` and dashboards look empty.

Use `OPENCODE_COST_USAGE_SCALE` to multiply the value sent to `cost.usage` so the integer part is meaningful. Only `cost.usage` is affected — `session.cost.total`, spans, and log events still carry the raw USD value.

```bash
# Scale to millionths of a dollar — $0.023 → 23000
export OPENCODE_COST_USAGE_SCALE=1000000
```

When querying the metric, divide by the same factor to get dollars back. With `OPENCODE_COST_USAGE_SCALE=1000000`, a `cost.usage` value of `23000` is `$0.023`.

The `cost.usage` `unit` is updated to `USD/1000000` (or whatever scale you set) and the description is annotated so the unit is visible in the backend's metric catalog.

## Local development

See [CONTRIBUTING.md](./CONTRIBUTING.md).
Expand Down
Loading
Loading