Andrew Mercer
on this page

Classic tools

tail -F /var/log/syslog                 # follow, survives rotation (-F not -f)
less +F /var/log/messages               # follow inside less; Ctrl-C to scroll, F to resume
grep -i 'error' /var/log/syslog
zgrep -i 'error' /var/log/syslog.*.gz   # search compressed rotations
zcat /var/log/syslog.2.gz | less
grep -h 'sshd' /var/log/auth.log{,.1} <(zcat /var/log/auth.log.*.gz)   # current + rotated

# Count messages per program
awk '{print $5}' /var/log/syslog | sed 's/\[.*//; s/:$//' | sort | uniq -c | sort -rn | head

# Messages per minute (spot bursts)
awk '{print $1, $2, substr($3,1,5)}' /var/log/syslog | uniq -c | sort -rn | head

Use tail -F rather than tail -f so you keep following after logrotate swaps the file.

lnav is a terminal log viewer that auto-detects common formats (syslog, journald JSON, Apache/nginx access logs, dpkg, and more), merges multiple files into a single timeline, highlights errors, and lets you query logs with SQL. It's the most useful single tool for ad-hoc log investigation on a server.

Install:

sudo apt install lnav                      # Debian/Ubuntu
sudo dnf install lnav                      # Fedora; EPEL on RHEL
# Or grab the static binary from the GitHub releases page

Opening logs:

lnav                                       # opens the default system logs
lnav /var/log/syslog /var/log/auth.log     # merged by timestamp
lnav /var/log/nginx/                       # a whole directory, including .gz rotations
journalctl -o json --since today | lnav    # the journal, with fields parsed
lnav user@web01:/var/log/syslog            # remote file over SSH

Navigation essentials:

Key Action
e / E Next / previous error
w / W Next / previous warning
/ then n / N Search forward, next / previous match
i Toggle histogram view (messages over time by severity)
p Toggle display of parsed fields for the current line
m Bookmark line; u / U jump between bookmarks
t Text view (for non-log files)
: Command prompt (:filter-in, :filter-out, :goto)
; SQL prompt
? Help
q Back / quit

Filtering:

:filter-in sshd
:filter-out CRON
:goto 2026-10-09 14:00

SQL queries against parsed logs (each format is a table, e.g. syslog_log):

;SELECT log_procname, count(*) AS n FROM syslog_log GROUP BY log_procname ORDER BY n DESC LIMIT 10
;SELECT log_time, log_text FROM syslog_log WHERE log_level = 'error' ORDER BY log_time DESC LIMIT 50

Non-interactive (scriptable) use:

lnav -n -c ';SELECT log_procname, count(*) FROM syslog_log GROUP BY 1 ORDER BY 2 DESC LIMIT 10' /var/log/syslog

lnav also supports custom formats (JSON definitions under ~/.lnav/formats/installed/) for application logs it doesn't recognize.

Other handy tools

Tool Use
jq Slice JSON logs and journalctl -o json output
multitail Several logs side by side in one terminal
goaccess Real-time web server access log analytics
logwatch / logcheck Daily summary reports by email
fail2ban Watches auth/web logs and bans abusive IPs
ccze / grc Colourize log output