OpenTelemetry tracing and metrics for pi coding agent. Exports spans and counters for sessions, agent prompts, LLM turns, and tool executions.
session (root span, entire session lifecycle)
├── agent.prompt (one per user message)
│ └── agent.turn (one per LLM call + tool execution cycle)
│ ├── llm.request (span event: before provider API call)
│ ├── tool.bash (tool execution span)
│ ├── tool.read (tool execution span)
│ └── tool.edit (tool execution span)
├── model.changed (span event on model switch)
└── session.compacted (span event on compaction)
| Metric | Type | Labels | Description |
|---|---|---|---|
pi.tokens.input |
Counter | — | Total input tokens consumed |
pi.tokens.output |
Counter | — | Total output tokens produced |
pi.tool.calls |
Counter | tool.name |
Total tool invocations |
pi.tool.errors |
Counter | tool.name |
Total failed tool invocations |
pi.tool.duration |
Histogram (ms) | tool.name |
Tool execution time |
pi.turns |
Counter | — | Total LLM turns |
pi.prompts |
Counter | — | Total user prompts |
pi.session.duration |
Histogram (s) | — | Session duration |
The extension automatically resolves user identity at startup and attaches it to all traces and metrics as OTEL resource attributes:
| Resource Attribute | Source | Description |
|---|---|---|
user.email |
PI_OTEL_USER_EMAIL or git config user.email |
User email |
user.full_name |
PI_OTEL_USER_NAME or git config user.name |
User display name |
user.name |
OS userInfo().username |
OS username |
host.name |
OS hostname() |
Machine hostname |
These propagate to every metric data point and trace span, enabling per-user filtering in Grafana/Tempo without high-cardinality metric labels.
| Attribute | Description |
|---|---|
session.id |
Session file path or "ephemeral" |
session.cwd |
Working directory |
session.turns |
Total turn count |
session.tool_calls |
Total tool calls |
session.tokens.input |
Total input tokens |
session.tokens.output |
Total output tokens |
llm.model |
Current model (provider/id) |
user.email |
User email (from git config or env) |
user.name |
OS username |
user.full_name |
User display name (from git config or env) |
host.name |
Machine hostname |
| Attribute | Description |
|---|---|
turn.index |
Turn index within agent prompt |
turn.number |
Global turn number in session |
turn.tool_results |
Number of tool results |
llm.usage.input_tokens |
Tokens consumed (input) |
llm.usage.output_tokens |
Tokens produced (output) |
| Attribute | Description |
|---|---|
tool.name |
Tool name (bash, read, edit, write, etc.) |
tool.call_id |
Unique tool call ID |
tool.args_summary |
Brief summary of arguments (truncated) |
tool.is_error |
Whether execution failed |
tool.duration_ms |
Execution time in milliseconds |
| Environment Variable | Default | Description |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:4318 |
Base OTLP HTTP endpoint. /v1/traces and /v1/metrics are appended automatically unless per-signal endpoints are set. |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT |
— | Explicit OTLP HTTP traces endpoint override |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT |
— | Explicit OTLP HTTP metrics endpoint override |
OTEL_SERVICE_NAME |
pi-coding-agent |
Service name in traces |
PI_OTEL_ENABLED |
true |
Set to false to disable |
PI_OTEL_DEBUG |
false |
Set to true to also log spans/metrics to console |
OTEL_METRIC_EXPORT_INTERVAL |
10000 |
Metric export interval in ms |
PI_OTEL_USER_EMAIL |
git config user.email |
Override user email |
PI_OTEL_USER_NAME |
git config user.name |
Override user display name |
A pre-built Grafana dashboard is included in pi-otel-telemetry.json. Import it into your Grafana instance to visualize pi session traces, token usage, tool call metrics, and more.
To import: Grafana → Dashboards → Import → Upload JSON file → select pi-otel-telemetry.json.
# Start Jaeger with OTLP support
docker run -d --name jaeger \
-p 16686:16686 \
-p 4318:4318 \
jaegertracing/jaeger:2 \
--set receivers.otlp.protocols.http.endpoint=0.0.0.0:4318
# Start pi (extension auto-discovered from ~/.pi/agent/extensions/)
pi
# Open Jaeger UI
open http://localhost:16686OTEL_EXPORTER_OTLP_ENDPOINT=http://tempo:4318 piIf your collector exposes OTLP HTTP on a non-default port, point the base endpoint at that port:
OTEL_EXPORTER_OTLP_ENDPOINT=http://alloy.it-expert.com.ua:14318 piIf traces and metrics need different destinations, use per-signal overrides:
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://alloy.it-expert.com.ua:14318/v1/traces \
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=http://alloy.it-expert.com.ua:14318/v1/metrics \
piPI_OTEL_DEBUG=true piPI_OTEL_ENABLED=false piInstall with:
pi install git:github.com/mprokopov/pi-otel-telemetryThe package is loaded by pi from ~/.pi/agent/git/github.com/mprokopov/pi-otel-telemetry.
To reinstall dependencies manually:
cd ~/.pi/agent/git/github.com/mprokopov/pi-otel-telemetry
npm install