slug: monitoring
Logs & Monitoring
OAR exposes its traffic through three complementary surfaces: JSONL log files on disk, a real-time SSE stream into the Web UI, and structured usage/activity queries. The Capture feature layers on top to record full request/response pairs for protocol debugging.
Log files
Logs are written as JSONL (one JSON object per line) under ~/.open-agent-router/logs/ with daily-rolling filenames:
~/.open-agent-router/logs/
├── proxy-2026-07-16.log
└── proxy-2026-07-17.log
- Daily rolling — a new file is created at local midnight.
- Asynchronous batch append — log entries are buffered and flushed every 500ms, so logging never blocks a response.
- JSONL — easy to consume with
jq,grepor any structured-log pipeline.
jq . ~/.open-agent-router/logs/proxy-2026-07-17.log pretty-prints each entry. Pipe through jq 'select(.tag=="[route]")' to filter by tag.
Log tags
Every log entry carries a tag that classifies the event. The tags you'll see most often:
| Tag | Meaning |
|---|---|
[route] | A request was routed. Format: [route] <method> <project>/<agent> → [group] account/model @ targetUrl (convert, try N) |
[debug] | Verbose diagnostic output. Useful when reproducing edge cases. |
[retry] | A retry was triggered — either cross-model within the group, or same-model after a transient failure. |
[upstream] | Upstream call lifecycle events (connection, headers, response status, timing). |
[no-model] | The requested model alias did not resolve to any model in the group. |
[no-route] | The request path did not match any project/agent/group route. |
[error] | An unrecoverable error — upstream timeout, adapter failure, etc. |
What's not logged
To keep the log volume sane, Morgan HTTP logging skips:
- Polling paths —
/api/health,/api/activity,/api/activity/status,/api/accounts-health,/api/capture/status,/api/service/status. - SSE endpoints —
/api/logs/stream. - Static resources — files served from
ui-dist/.
Routing, retries, upstream calls and errors are always logged regardless.
Web UI Logs view
The Logs page in the Web UI streams entries live over Server-Sent Events from /api/logs/stream. Open the page and traffic appears in real time — no refresh, no polling.
- Real-time SSE streaming at
/api/logs/stream. - Each entry rendered with its tag, timestamp and full message.
- Capture-related entries surface a
[oar-capture:filename]chip — click it to open the capture record directly.
The same Logs view is available in CLI mode at http://127.0.0.1:26969 — point a browser at the backend and you get the full Web UI.
Dashboard
The Dashboard view is the landing page of the Web UI. It shows overview metrics at a glance:
- Health status — per-account and per-model reachability.
- Recent activity — the last few requests with status and latency.
- Top talkers — accounts/groups/models ranked by request count and token spend.
Pair the Dashboard with the Logs view for a full live picture: the Dashboard summarises, the Logs view drills in.
Usage and activity
Use the oar CLI for structured queries over the activity log. Both commands hit the admin API and return either human-readable tables or, with --json, machine-readable output.
| Command | Description |
|---|---|
oar usage [--start-time <t>] [--end-time <t>] | Aggregate token spend and request counts by model/group over a window. |
oar activity [--limit <n>] | List the most recent requests (default 50). |
Capture
Capture records full request/response pairs for debugging — invaluable when adapting a new protocol, diagnosing a 422 from an upstream, or reproducing a routing edge case. Each capture session runs for a fixed duration and writes one JSON file per recorded request to ~/.open-agent-router/captures/.
CLI
| Command | Description |
|---|---|
oar capture start [--duration <sec>] | Start a capture session (default 300s). |
oar capture stop | Stop the active capture early. |
oar capture status | Report whether a capture is running and how long remains. |
oar capture get <filename> | Read a capture record as JSON. |
Web UI
In the Web UI, capture is driven from a drawer that you open from the Logs page:
- Initial request on drawer open — fetches the current capture state.
- Final request on countdown — fetches the final state when the timer hits zero.
The capture status does not use SSE or polling — just these two HTTP requests.
The capture file list updates live from [oar-capture:filename] log chips pushed via the SSE log stream. Click a chip to open the capture record inline.
Capture file writing happens in a dedicated worker_threads worker. Recording high-traffic periods does not block request handling on the main thread.
Where files are stored
Capture records are plain JSON files under ~/.open-agent-router/captures/:
~/.open-agent-router/captures/
├── 2026-07-17-1421.json
├── 2026-07-17-1422.json
└── ...
Each file contains the inbound request (in), the outbound upstream call (out), the resolved model and the route that was used.
Activity monitoring
The combination of Dashboard, Logs view and oar activity covers day-to-day monitoring:
- Live triage — open the Logs view, watch
[route]and[retry]entries flow, click capture chips to inspect. - Trend analysis — run
oar usageover a window to see which accounts and models are carrying load. - Recent history —
oar activity --limit 50lists the latest requests with status and latency. - Per-account health — the Dashboard surfaces reachability per account and per model, including models in cooldown.
For the underlying CLI commands, see the CLI Reference. For configuration knobs like the model cooldown, see Configuration.