Observability (OpenTelemetry, stats, crash reports)

eVi gives you three independent ways to see what your assistant is doing — OpenTelemetry traces/metrics for tool calls, local usage stats computed from your transcripts, and opt-in crash reporting to a Sentry-compatible endpoint. All three are built around eVi's local-first, privacy-first posture: nothing leaves your machine unless you explicitly opt in and point it somewhere.

Overview

PillarWhat it doesDefaultData leaves machine?
OpenTelemetryEmits spans + metrics around every tool call (counts, durations) to an OTLP collector you runOFFOnly if you set an endpoint
Local statsevi stats aggregates sessions, messages, tools, busy days, and rough token volume from your transcriptsAlways available (reads local files)Never
Crash reportsCaptures uncaught exceptions, scrubs them aggressively, and sends them to your Sentry/GlitchTip DSNOFFOnly if you opt in and set a DSN

Use OpenTelemetry when you want live dashboards/traces for tool latency and call volume (e.g. in Grafana/Jaeger/Tempo). Use stats for a quick local "how have I been using eVi?" summary with zero setup. Use crash reports when you want to know about failures in your own self-hosted error tracker without those reports carrying prompt text, file paths, or API keys.

How it works

OpenTelemetry (evi/otel.py)

Local stats (evi/stats.py)

Crash reports (evi/reporting.py)

Setup

All three features are configured under a single [telemetry] section in ~/.evi/config.toml (on Windows, %USERPROFILE%\.evi\config.toml). The home directory can be relocated with the EVI_HOME environment variable. Defaults (everything off) are:

[telemetry]
# Crash reporting (Sentry/GlitchTip)
crash_reports = false
dsn           = ""
backend       = "sentry"   # "sentry" | "none"

# OpenTelemetry traces/metrics
traces        = false
metrics       = false
otlp_endpoint = ""         # base OTLP/HTTP URL, e.g. http://localhost:4318
service_name  = "evi"

Optional pip extras

Both exporting features need optional dependencies (eVi ships without them by default):

# OpenTelemetry traces + metrics
pip install 'evi-assistant[otel]'

# Crash reporting (sentry-sdk)
pip install 'evi-assistant[telemetry]'

If the extras aren't installed, the features stay inert (no-op) even if you enable them in config — they fail open rather than crashing eVi.

Environment-variable overrides

VariableEffect
EVI_OTLP_ENDPOINTOverrides otlp_endpoint (base OTLP/HTTP URL). Trailing slashes are stripped.
EVI_CRASH_REPORTSTruthy (1, true, yes, …) / falsy (`, 0, false, no) override for crash_reports`.
EVI_TELEMETRY_DSNOverrides the crash-report dsn.

Stats

No setup beyond having transcripts. Stats read ~/.evi/transcripts/, which is populated when transcript logging is on ([tools] transcripts = true, the default). If transcripts are disabled, evi stats will report nothing.

Usage

evi stats — local usage analytics

evi stats [--days N] [--json]

The human-readable output shows session/message counts, an approximate token total (in thousands), the date span, the role breakdown, the top 8 tools, and the busiest days. If there are no transcripts it prints a hint that tools.transcripts may be off.

The same numbers are available in the web/desktop app under Settings → Usage (backed by GET /api/stats?days=N), with All / 30d / 7d range buttons and the role/tool/busy-day breakdowns shown as chips.

OpenTelemetry — automatic once enabled

There is no separate command. Once traces/metrics are enabled, an otlp_endpoint is set, and the [otel] extra is installed, eVi instruments tool calls automatically every time you run a chat (CLI or web). Spans and metrics flow to your collector in the background.

Crash reports — automatic once enabled

Also no separate command. Once enabled with a DSN, eVi installs a chained sys.excepthook at startup; any uncaught CLI exception is scrubbed and sent, then the traceback prints as usual.

Web UI

The web server initializes OpenTelemetry the same way as the CLI on startup, so enabling [telemetry] traces/metrics instruments web-driven tool calls too. (The Settings → Model & Backend page surfaces hardware/OS stats, which is separate from evi stats usage analytics.)

Examples

Example 1 — Local OTLP collector, then watch tool metrics

Install the extra, point eVi at a local OTLP/HTTP collector (the default OTLP HTTP port is 4318), and run a chat. Spans/metrics for each tool call are exported automatically.

# ~/.evi/config.toml
[telemetry]
traces        = true
metrics       = true
otlp_endpoint = "http://localhost:4318"
service_name  = "evi"
pip install 'evi-assistant[otel]'

# Optional: override the endpoint for a single run without editing config
export EVI_OTLP_ENDPOINT="http://localhost:4318"

evi chat "summarize my notes from today"

In your backend you'll see the evi.tool spans plus the evi.tool.calls counter (tagged tool + ok) and the evi.tool.duration histogram (in ms, tagged tool), all under service name evi.

Example 2 — Quick local usage report

# Formatted summary for the last 30 days
evi stats --days 30
42 sessions · 318 messages · ~57k tokens  Apr 12 - May 09
  roles: user: 159, assistant: 142, tool: 17
  top tools: fs.read (9), websearch (5), fs.write (3)
  busiest days: 2026-05-07 (6), 2026-05-02 (5), 2026-04-29 (4)

For piping into other tooling, ask for raw JSON:

evi stats --json
{
  "sessions": 42,
  "messages": 318,
  "roles": { "user": 159, "assistant": 142, "tool": 17 },
  "tools": { "fs.read": 9, "websearch": 5, "fs.write": 3 },
  "busiest_days": { "2026-05-07": 6, "2026-05-02": 5 },
  "approx_tokens": 14250,
  "first_ts": 1744483200.0,
  "last_ts": 1746748800.0
}

Example 3 — Opt-in crash reporting to self-hosted GlitchTip

# ~/.evi/config.toml
[telemetry]
crash_reports = true
dsn           = "https://<key>@glitchtip.example.com/1"
backend       = "sentry"   # set to "none" to disable without removing the dsn
pip install 'evi-assistant[telemetry]'
evi chat "..."   # any uncaught error is scrubbed, sent, then printed locally

To toggle reporting per-run via environment without touching config:

EVI_CRASH_REPORTS=0 evi chat "..."          # force-disable for this run
EVI_TELEMETRY_DSN="https://<key>@..." EVI_CRASH_REPORTS=1 evi chat "..."

Notes / limits

Relevant source files: C:\evi\evi\otel.py, C:\evi\evi\stats.py, C:\evi\evi\reporting.py, C:\evi\evi\config.py (TelemetrySettings, lines 188-209), and the CLI wiring in C:\evi\evi\apps\cli\main.py (stats command ~line 4042; startup init ~lines 153-158).

Edit on GitHub ↗