The exported dashboard-1783595688930.json wraps the model in the apiVersion/kind/metadata/spec envelope. Grafana's "Import via JSON" validates the pasted top level against the dashboard-spec schema and reports every required field (annotations, elements, layout, timeSettings, etc.) as missing because they live under spec. dashboard-import.json is the same dashboard with the envelope stripped, so the required fields sit at the top level and the UI importer accepts it. The original envelope file is kept for API/provisioning use. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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_tokensopenclaw_daily_input_tokensopenclaw_daily_output_tokensopenclaw_daily_cache_read_tokensopenclaw_daily_cache_write_tokensopenclaw_daily_reasoning_tokensopenclaw_daily_usage_entriesopenclaw_daily_cost_inputopenclaw_daily_cost_outputopenclaw_daily_cost_cache_readopenclaw_daily_cost_cache_writeopenclaw_daily_cost_totalopenclaw_daily_message_recordsopenclaw_daily_non_message_recordsopenclaw_daily_unique_sessionsopenclaw_daily_unique_modelsopenclaw_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_countopenclaw_sessions_total_countopenclaw_sessions_has_moreopenclaw_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_totalopenclaw_input_tokens_totalopenclaw_output_tokens_totalopenclaw_cache_read_tokens_totalopenclaw_cache_write_tokens_totalopenclaw_reasoning_tokens_totalopenclaw_usage_entries_totalopenclaw_cost_input_usd_totalopenclaw_cost_output_usd_totalopenclaw_cost_cache_read_usd_totalopenclaw_cost_cache_write_usd_totalopenclaw_cost_total_usd_totalopenclaw_message_records_totalopenclaw_non_message_records_totalopenclaw_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_scannedopenclaw_exporter_lines_scannedopenclaw_exporter_parse_errorsopenclaw_exporter_negative_cost_entries_skippedopenclaw_exporter_negative_cost_fields_skipped{cost_field=...}openclaw_exporter_negative_cost_amount_skipped{cost_field=...}openclaw_exporter_history_days_retainedopenclaw_exporter_history_hours_retainedopenclaw_usage_cost_cache_files_trackedopenclaw_usage_cost_cache_versionopenclaw_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.pykeeps the uvicorn entrypoint tinyopenclaw_usage_exporter/config.pyholds env-driven paths and retention settingsopenclaw_usage_exporter/models.pyholds report dataclasses and cost handlingopenclaw_usage_exporter/collectors.pyreads session files and cache/index dataopenclaw_usage_exporter/metrics.pyrenders Prometheus outputopenclaw_usage_exporter/utils.pykeeps shared helpers small
Run locally
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_DIRdefault:/root/.openclaw/agents/main/sessionsOPENCLAW_EXPORTER_TZdefault:Europe/BerlinOPENCLAW_SESSIONS_INDEXdefault:/root/.openclaw/agents/main/sessions/sessions.jsonOPENCLAW_USAGE_COST_CACHEdefault:/root/.openclaw/agents/main/sessions/.usage-cost-cache.jsonOPENCLAW_HISTORY_DAYSdefault:30OPENCLAW_HISTORY_HOURSdefault:168PORTignored by app directly; set it in the service or uvicorn command