Why lnav?
Reading raw JSONL files with grep and jq works, but you lose context. lnav gives you a real-time, interactive view of your logs — color-coded levels, instant filtering, SQL queries, and a timeline view — all in your terminal.
docker-agent-tail includes a built-in lnav format definition that’s auto-installed on first run. No configuration, no schema files to manage.
| Without lnav | With lnav |
|---|
grep error combined.jsonl | :filter-in error with color-coded context |
jq 'select(.container=="api")' combined.jsonl | :filter-in api with live updates |
| Manual timestamp correlation | Timeline histogram view (press t) |
| No aggregation | ;SELECT container, count(*) FROM log GROUP BY container |
Setup
Install lnav
# Debian/Ubuntu
sudo apt install lnav
# Or download from https://lnav.org/downloads
The lnav format is auto-installed the first time you run docker-agent-tail. No manual setup needed.
To manually install or reinstall:
docker-agent-tail lnav-install
This installs a format definition that teaches lnav how to parse the JSONL fields (ts, container, stream, level, message).
Usage
The easiest way to view logs is with the lnav subcommand:
# Open latest session in lnav
docker-agent-tail lnav
# Open a specific session
docker-agent-tail lnav --session 2026-03-04-143700
You can also call lnav directly:
# View the latest combined log
lnav logs/latest/combined.jsonl
# View all per-container logs from the latest session
lnav logs/latest/*.jsonl
# View logs from a specific session
lnav logs/2026-03-04-103001/combined.jsonl
Key Features
Filter by log level
Use lnav’s built-in level filtering to focus on errors or warnings:
:set-min-log-level warning
Or filter to show only specific levels:
Filter by container
Show logs from a specific container:
SQL queries
lnav supports SQL queries against your log data:
;SELECT container, count(*) as cnt FROM log GROUP BY container ORDER BY cnt DESC
;SELECT container, level, count(*) FROM log GROUP BY container, level
;SELECT * FROM log WHERE level = 'error' ORDER BY log_time DESC LIMIT 20
Regex search
Search across all logs with regex:
/timeout|connection refused
Timeline view
Press t to switch to the timeline/histogram view, which shows log density over time — useful for spotting bursts of errors.
Non-interactive mode (for scripts and AI agents)
lnav’s interactive TUI doesn’t work in non-interactive shells (CI, scripts, AI agents). Use -n (non-interactive) with -c to run commands and get output to stdout:
# Count log lines per container
lnav -n -c ';SELECT container, count(*) AS cnt FROM log GROUP BY container ORDER BY cnt DESC' logs/latest/combined.jsonl
# Find all errors
lnav -n -c ';SELECT log_time, container, log_body FROM log WHERE level = "error"' logs/latest/combined.jsonl
# Errors in the last 5 minutes
lnav -n -c ';SELECT log_time, container, log_body FROM log WHERE level = "error" AND log_time > datetime("now", "-5 minutes")' logs/latest/combined.jsonl
# Log volume by container and level
lnav -n -c ';SELECT container, level, count(*) FROM log GROUP BY container, level' logs/latest/combined.jsonl
# Filter to a single container and write to stdout
lnav -n -c ':filter-in api' -c ':write-to -' logs/latest/combined.jsonl
AI coding agents (Claude Code, Cursor, etc.) should use lnav -n -c instead of the interactive TUI. This gives them full SQL access to structured log data without needing a terminal.
Multiple commands
Chain multiple -c flags to build pipelines:
# Filter to errors, then write to stdout
lnav -n -c ':filter-in error' -c ':write-to -' logs/latest/combined.jsonl
# Set minimum level, then query
lnav -n -c ':set-min-log-level warning' -c ';SELECT container, count(*) FROM log GROUP BY container' logs/latest/combined.jsonl
Level Normalization
docker-agent-tail normalizes log levels from various formats into canonical values that lnav understands:
| Source format | Normalized level |
|---|
I, info, notice | info |
W, warn, warning | warning |
E, err, error | error |
F, fatal, critical, crit, emerg | fatal |
D, debug | debug |
T, trace | trace |
This means logs from MongoDB (s:"I"), Node.js (level:"info"), Python (levelname:"WARNING"), and other frameworks all get consistent color-coded levels in lnav.
Learn More