Files
openclaw-usage-exporter/README.md
T
2026-07-09 10:21:37 +00:00

163 lines
6.5 KiB
Markdown

# OpenClaw Usage Exporter
FastAPI Prometheus exporter for OpenClaw usage, session, and runtime-adjacent metrics.
## What it exports
Reads OpenClaw session data from disk and exposes `/metrics` with as much non-sensitive data as possible.
### Why timeframe switching looked wrong before
Prometheus scrapes snapshots. The old exporter leaned heavily on "today so far" gauges, so a Grafana timeframe change could look almost unchanged unless the panel query explicitly used range math.
The exporter now also exposes:
- monotonic all-time counters for tokens, cost, and usage entries
- retained daily buckets
- retained hourly buckets
That gives dashboards something real to aggregate over a selected time range.
### Daily usage metrics
- `openclaw_daily_total_tokens`
- `openclaw_daily_input_tokens`
- `openclaw_daily_output_tokens`
- `openclaw_daily_cache_read_tokens`
- `openclaw_daily_cache_write_tokens`
- `openclaw_daily_reasoning_tokens`
- `openclaw_daily_usage_entries`
- `openclaw_daily_cost_input`
- `openclaw_daily_cost_output`
- `openclaw_daily_cost_cache_read`
- `openclaw_daily_cost_cache_write`
- `openclaw_daily_cost_total`
- `openclaw_daily_message_records`
- `openclaw_daily_non_message_records`
- `openclaw_daily_unique_sessions`
- `openclaw_daily_unique_models`
- `openclaw_daily_unique_providers`
### Daily breakdowns
- `openclaw_daily_messages_total{role=...}`
- `openclaw_daily_stop_reasons_total{stop_reason=...,model=...,provider=...}`
- `openclaw_daily_tool_calls_total{tool_name=...}`
- `openclaw_daily_errors_total{error_type=...}`
- `openclaw_daily_model_total_tokens{model=...,provider=...}`
- `openclaw_daily_model_input_tokens{model=...,provider=...}`
- `openclaw_daily_model_output_tokens{model=...,provider=...}`
- `openclaw_daily_model_reasoning_tokens{model=...,provider=...}`
- `openclaw_daily_session_total_tokens{session_id=...}`
- `openclaw_daily_session_input_tokens{session_id=...}`
- `openclaw_daily_session_output_tokens{session_id=...}`
- `openclaw_daily_session_messages_total{session_id=...,role=...}`
- `openclaw_daily_session_errors_total{session_id=...}`
- `openclaw_daily_session_tool_calls_total{session_id=...,tool_name=...}`
### Session inventory metrics
Derived from `sessions.json`:
- `openclaw_sessions_visible_count`
- `openclaw_sessions_total_count`
- `openclaw_sessions_has_more`
- `openclaw_session_info{session_id=...,status=...,chat_type=...,last_channel=...,model=...,provider=...,auth_profile_override=...,system_sent=...,aborted_last_run=...,total_tokens_fresh=...}`
- `openclaw_session_age_seconds{session_id=...}`
- `openclaw_session_updated_timestamp_seconds{session_id=...}`
- `openclaw_session_started_timestamp_seconds{session_id=...}`
- `openclaw_session_last_interaction_timestamp_seconds{session_id=...}`
- `openclaw_session_total_tokens{session_id=...}`
- `openclaw_session_input_tokens{session_id=...}`
- `openclaw_session_output_tokens{session_id=...}`
- `openclaw_session_context_tokens{session_id=...}`
- `openclaw_session_runtime_seconds{session_id=...}`
- `openclaw_session_estimated_cost_usd{session_id=...}`
- `openclaw_session_compaction_count{session_id=...}`
- `openclaw_session_usage_family_session_count{session_id=...}`
### Time-range-friendly counters and buckets
- `openclaw_total_tokens_total`
- `openclaw_input_tokens_total`
- `openclaw_output_tokens_total`
- `openclaw_cache_read_tokens_total`
- `openclaw_cache_write_tokens_total`
- `openclaw_reasoning_tokens_total`
- `openclaw_usage_entries_total`
- `openclaw_cost_input_usd_total`
- `openclaw_cost_output_usd_total`
- `openclaw_cost_cache_read_usd_total`
- `openclaw_cost_cache_write_usd_total`
- `openclaw_cost_total_usd_total`
- `openclaw_message_records_total`
- `openclaw_non_message_records_total`
- `openclaw_model_total_tokens_total{model=...,provider=...}`
- `openclaw_model_input_tokens_total{model=...,provider=...}`
- `openclaw_model_output_tokens_total{model=...,provider=...}`
- `openclaw_session_total_tokens_total{session_id=...}`
- `openclaw_day_total_tokens{date=...,tz=...}`
- `openclaw_day_cost_total{date=...,tz=...}`
- `openclaw_day_usage_entries{date=...,tz=...}`
- `openclaw_hour_total_tokens{hour=...,tz=...}`
- `openclaw_hour_cost_total{hour=...,tz=...}`
- `openclaw_hour_usage_entries{hour=...,tz=...}`
### Exporter/runtime metrics
- `openclaw_exporter_files_scanned`
- `openclaw_exporter_lines_scanned`
- `openclaw_exporter_parse_errors`
- `openclaw_exporter_negative_cost_entries_skipped`
- `openclaw_exporter_negative_cost_fields_skipped{cost_field=...}`
- `openclaw_exporter_negative_cost_amount_skipped{cost_field=...}`
- `openclaw_exporter_history_days_retained`
- `openclaw_exporter_history_hours_retained`
- `openclaw_usage_cost_cache_files_tracked`
- `openclaw_usage_cost_cache_version`
- `openclaw_usage_cost_cache_updated_timestamp_seconds`
## Privacy boundary
This exporter intentionally skips obvious revealing fields like message content, sender labels, sender ids, phone numbers, response ids, idempotency keys, and session keys.
Session ids are exported.
It also ignores invalid negative cost values found in some legacy/raw usage records and exposes exporter metrics for how many were skipped.
## Code layout
- `app.py` keeps the uvicorn entrypoint tiny
- `openclaw_usage_exporter/config.py` holds env-driven paths and retention settings
- `openclaw_usage_exporter/models.py` holds report dataclasses and cost handling
- `openclaw_usage_exporter/collectors.py` reads session files and cache/index data
- `openclaw_usage_exporter/metrics.py` renders Prometheus output
- `openclaw_usage_exporter/utils.py` keeps shared helpers small
## Run locally
```bash
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
uvicorn app:app --host 0.0.0.0 --port 9487
```
## Runtime
- Canonical repo path: `/root/projects/openclaw-usage-exporter`
- Compatibility workspace path: `/root/.openclaw/workspace/openclaw-daily-tokens-exporter`
- systemd user unit: `~/.config/systemd/user/openclaw-daily-tokens-exporter.service`
- Direct metrics: `http://100.74.255.106:9487/metrics`
- Tailscale Serve path: `https://luna.taile7522.ts.net/openclaw-daily-tokens`
## Env
- `OPENCLAW_SESSIONS_DIR` default: `/root/.openclaw/agents/main/sessions`
- `OPENCLAW_EXPORTER_TZ` default: `Europe/Berlin`
- `OPENCLAW_SESSIONS_INDEX` default: `/root/.openclaw/agents/main/sessions/sessions.json`
- `OPENCLAW_USAGE_COST_CACHE` default: `/root/.openclaw/agents/main/sessions/.usage-cost-cache.json`
- `OPENCLAW_HISTORY_DAYS` default: `30`
- `OPENCLAW_HISTORY_HOURS` default: `168`
- `PORT` ignored by app directly; set it in the service or uvicorn command