OpenClaw Prometheus metrics
An official plugin publishes Gateway diagnostics as Prometheus text, which gives you run, model, tool and queue numbers without a collector, provided you scrape it through Gateway authentication.
Running an assistant in production eventually turns into an operations question rather than a model question. You want to know how many runs completed, how long provider calls took, what they cost, whether the queue is backing up and whether the event loop is stalling. OpenClaw answers that with an official diagnostics plugin that renders the standard Prometheus text exposition format on a Gateway route, so an existing Prometheus or Grafana stack can scrape it directly. There is no collector to deploy, but there is also no public metrics port, because the route is an operator surface and it stays behind authentication.
What gets exported
- The plugin listens to trusted diagnostics plus internally tagged dispatcher owned events covering queue, memory and session recovery signals, and renders them as the standard Prometheus text exposition format on a Gateway diagnostics route.
- Counters and histograms cover Gateway RPC requests with separate first response, handler, admission and queue wait timings, completed runs and their durations, model calls split by provider and transport, failovers, token totals, cost in US dollars, skill activations, tool executions including blocked ones, harness runs, webhooks and the whole message pipeline.
- Runtime health is exported as well, with queue lane size and wait, session state, stuck and recovery counters, event loop delay maxima and observed seconds, liveness measures including a CPU core ratio that can exceed one, memory and memory pressure, oversized payloads, garbage collection duration and two drop counters.
- For model call metrics one observation unit measures a single observable provider request while the other measures a synthetic Claude Code or Codex command line agent turn that can contain several hidden provider requests, so the two series should not be compared as if they described the same latency.
Prometheus labels stay bounded and low-cardinality.
Cardinality is the budget
The exporter keeps at most 2,048 time series in memory across counters, gauges and histograms combined, and anything beyond that is dropped while a dedicated counter increments by one each time. That counter is the signal to watch, because the cap is never lifted automatically and a climbing value means an upstream attribute is leaking high cardinality values rather than that the exporter needs more room. The accounting is worth knowing in detail, since each Gateway RPC method with all four timings occupies five aggregate samples, and one duration histogram takes a single sample but expands into 19 series at scrape time, so covering every core method can fill the budget on its own. Labels are redacted and must match a low cardinality character policy, with failing values replaced by unknown, other or none depending on the metric, and anything that looks like a scoped agent session key is replaced too. Raw diagnostic identifiers are never emitted, which rules out run identifiers, session keys and session identifiers, call and tool call identifiers, message identifiers, chat identifiers and provider request identifiers. Prompt and response text, tool inputs and outputs, system prompts, talk transcripts and audio payloads, hostnames, file paths and secret values never appear at all. The async diagnostic queue can also drop observations under saturation, and it reports that through its own counter. Between those two counters you can tell whether a quiet dashboard means a quiet system or a lossy pipeline.
Getting a first scrape
- Install and enable the plugin, leave diagnostics enabled, then restart the Gateway, because the HTTP route is registered at plugin startup and a process that is already running will not pick it up.
- Scrape with the same credentials your operator clients already use, since the route requires the Gateway operator scope and a caller whose effective scopes include operator read, which operator write and operator admin both imply.
- Expect an empty body before any traffic exists, because counters and histograms only emit lines after at least one event, and expect counters to reset to zero after a Gateway restart since the plugin keeps its state in memory only.
If the first scrape comes back empty or refused, the two things to sit with are Gateway authentication and the exporter troubleshooting notes, because an empty body, a 401 and a 403 about a missing read scope are three different problems with three different fixes.
Why metrics only
The plugin does one thing, and the reference is clear that this is a choice rather than a gap. It is a pull surface with no external collector, no traces and no logs, which suits a stack already standardised on Prometheus and Grafana, while the OpenTelemetry exporter exists for everything else and the two can run together, separately or not at all. The same restraint shapes collection itself. Event loop windows and garbage collection entries are only gathered when something is interested, so counters for runs, model calls and queued work can already exist while a newly added consumer still waits for the diagnostics heartbeat to notice it on the next tick. Observations before that point are not backfilled, and an intentional monitor reset discards the unfinished window. That makes the numbers honest about their own coverage, which is more useful than a dashboard that silently invents continuity. It also means the represented duration counter and the drop counters are part of reading the data rather than optional extras.
On Diali
On Diali each customer runs their own assistant, and the runtime configuration is generated from the dashboard and replaced at each release, so operational wiring is not something you maintain by hand. State lives on a persistent volume, with daily snapshots and one-click restore available through the Backups add-on (included on Max). Hosted OpenClaw on Diali describes the hosted shape and Diali security covers the rest.
- The route needs operator read, not a public metrics port.
- Watch the dropped series counter before trusting a chart.
- Counters reset on restart, so read them with rate and increase.
Stop reading about it, build one
Set up an agent, pick a channel, and have it working inside the app you already keep open.
