FS reader
The filesystem drain writes wide events as NDJSON to .jsonl files under .evlog/logs/ (one file per day, e.g. 2026-05-08.jsonl, plus rotation suffixes like .1.jsonl when size-based rotation is enabled). The evlog/fs module also ships readers that let any Node tool replay or follow that history without hooking into the running app.
Read or tail evlog NDJSON logs from disk
Replay history
import { readFsLogs } from 'evlog/fs'
for await (const event of readFsLogs({ since: '2026-03-01', level: 'error' })) {
console.log(event.timestamp, event.action ?? event.message)
}
readFsLogs(options) walks the NDJSON files in chronological order, parses them line by line, and yields events that pass all filters. Files outside the date window are skipped entirely.
Options
| Option | Type | Description |
|---|---|---|
dir | string | Directory to read from. Default: .evlog/logs. |
since | Date | string | Yield events with timestamp >= since. |
until | Date | string | Yield events with timestamp <= until. |
level | LogLevel | LogLevel[] | Filter by event level. |
filter | (event) => boolean | Custom predicate. |
Malformed lines (partial writes, manual edits) are silently skipped — your script never crashes on a bad line.
Live tail
import { tailFsLogs } from 'evlog/fs'
const ac = new AbortController()
process.on('SIGINT', () => ac.abort())
for await (const event of tailFsLogs({ signal: ac.signal })) {
console.log('live:', event.action ?? event.message)
}
tailFsLogs(options) first yields existing events (unless fromEnd: true), then keeps yielding new ones as they're appended — including events written into newly created daily files. Partial writes split across polls are recombined transparently.
Tail-specific options
| Option | Type | Description |
|---|---|---|
pollIntervalMs | number | Polling interval. Default: 500ms (minimum 50ms). |
fromEnd | boolean | Skip existing events; only yield future ones. Default: false. |
signal | AbortSignal | Stop tailing when aborted. |
All readFsLogs options also apply.
Use cases
- A local Electron / Tauri dashboard reading
.evlog/logs/from a target project directory - A CI report aggregator that scans logs after a test run
- A
grep-style CLI that pipes filtered events intojq - Replaying historic events into a dashboard before switching to a live in-process subscription. See the replay-then-live recipe
Custom framework
Build evlog support for an HTTP framework (or non-HTTP runtime) without a built-in integration. Use defineFrameworkIntegration for the (ctx, next) middleware shape, or createMiddlewareLogger / createRequestLogger for everything else.
Recipes
Concrete copy-paste recipes — build your own minimal devtool, pipe to curl + jq, replay history then go live, and aggregate on the consumer side.