CLI

evlog logs

Read the wide events your app wrote to .evlog/logs from the terminal — the latest requests, the failures, the slowest, or one request in full.

evlog logs reads the events the file system drain wrote and shows them the way you would want to read them: one line per request, the thing that mattered at the end of it, and one request in full when you have its id. It reads files; it never touches the app.

Terminal
evlog logs
Output
6 events · .evlog/logs

08:00:00  GET    /api/health                                 200      2ms
10:00:00  POST   /api/checkout                               402    412ms  ✗ Error: Payment processing failed · Card declined by issuer
10:30:00  GET    /api/reports                                200    1.2s   report.id=r-1
11:00:00  POST   /api/refund                                 200     80ms  audit billing.refund user:usr_42 → invoice:inv_1 success
11:30:00  GET    /api/items                                  500     30ms
11:45:00  GET    /api/items                                  warn   700ms  user.id=usr_7

evlog logs errors — the 2 that failed · evlog logs <requestId> — one request in full · evlog logs slow — worst first

The newest event is at the bottom, like tail. Nothing is written: the fs drain writes on every request and this reads what it wrote, both the compact and the pretty: true layout, across the dated files.

Four views

CommandShows
evlog logsThe last 50 events, oldest first
evlog logs errorsEvents that failed: a 5xx status, an error or fatal level, or an error block
evlog logs slowEvents over 500ms, worst first (--over 1s to move the bar)
evlog logs <requestId>Every event carrying that id, in full: request, error with why and fix, audit record, then the business fields. The first block of a UUID is enough

Filters

Filters compose with any view.

FlagWhat it does
--since <when>Only events after: a duration back from now (15m, 2h, 3d) or a date (2026-10-01, 2026-10-01T09:00)
--until <when>Only events before, same spellings
--level <a,b>Only these levels: trace, debug, info, warn, error, fatal
--path <path>Only requests on this exact path
--status <n>Only this status (404) or class (4xx)
--over <duration>For slow: what a request has to exceed (default 500ms)
--limit <n>Most events to show (default 50)
--dir <path>Read another directory (default: the project's .evlog/logs, or the directory its fs drain is configured for)
-f, --followKeep reading as the app writes, like tail -f; Ctrl-C stops
--jsonThe events as JSON on stdout
--cwd <dir>Another project in the workspace

A time, level, status or limit that cannot be read stops the command (exit 2) rather than silently widening the query.

Terminal
evlog logs errors --since 1h
evlog logs slow --over 2s --path /api/reports
evlog logs --status 5xx --level error,fatal --limit 20
evlog logs -f --path /api/checkout

For agents

--json returns one envelope: the directory, the view, how many events matched, and the events shown.

Terminal
evlog logs errors --since 30m --json
{
  "schemaVersion": 2,
  "dir": "/app/.evlog/logs",
  "view": "errors",
  "count": 2,
  "matched": 2,
  "events": [ { "timestamp": "…", "path": "/api/checkout", "status": 402, "error": { "data": { "why": "…", "fix": "…" } } } ]
}

With --follow --json, each new event is one JSON line on stdout, since a stream has no end. The analyze-logs skill calls evlog logs first and falls back to reading the files only when the CLI is not available.

What it will not do

  • It reads local files. A remote drain (Axiom, Datadog, …) has its own query language and UI; this command does not wrap them.
  • One directory per run. In a monorepo, run it from the app (--cwd apps/web) or pass --dir.
  • No aggregation yet. Counts by route or status are a jq away from --json; a stats view may come later.

Next