G
GuideDevOps
Lesson 12 of 17

Log Files & Journalctl

Part of the Linux Fundamentals tutorial series.

Where Logs Reside

Almost everything that happens on a Linux system is logged. Traditionally, logs are flat text files in /var/log. Modern systems also use the systemd journal (binary format, queried with journalctl).

# Browse the log directory
$ ls -la /var/log/
total 216
drwxr-xr-x  3 root root  4096 Apr 10 08:00 .
drwxr-xr-x  3 root root  4096 Apr 10 08:00 ..
drwxr-xr-x  3 root root  4096 Apr 10 08:00 apt/ Package manager history
drwxr-xr-x  2 root root  4096 Apr 10 09:05 auth.log Authentication attempts
drwxr-xr-x  3 root root  4096 Apr 10 08:00 boot.log Boot messages
drwxr-xr-x  3 root root  4096 Apr 10 08:00 btmp Failed login attempts (binary)
drwxr-xr-x  3 root root  4096 Apr 10 09:05 daemon.log Daemon messages
drwxr-xr-x  3 root root  4096 Apr 10 08:00 dmesg Kernel ring buffer
drwxr-xr-x  3 root root  4096 Apr 10 08:00 dpkg.log Package installation
drwxr-xr-x  3 root root  4096 Apr 10 09:05 kern.log Kernel messages
drwxr-xr-x  3 root root  4096 Apr 10 08:00 syslog System events
drwxr-xr-x  3 root root  4096 Apr 10 08:00 nginx/ Web server logs
drwxr-xr-x  3 root root  4096 Apr 10 08:00 apache2/ Apache logs
drwxr-xr-x  3 root root  4096 Apr 10 08:00 docker/ Container logs
drwxr-xr-x  3 root root  4096 Apr 10 08:00 journal/ Systemd journal (binary)

Important Log Files

FileContentsWhen to Check
/var/log/auth.logSSH logins, sudo, user authenticationSecurity auditing, brute force detection
/var/log/syslogGeneral system events, cron, servicesGeneral troubleshooting
/var/log/kern.logKernel messages, hardware eventsHardware issues, driver problems
/var/log/dmesgBoot-time kernel messagesDriver loading, hardware detection
/var/log/nginx/access.logAll HTTP requests to NGINXTraffic analysis, 404/500 errors
/var/log/nginx/error.logNGINX errors and warningsWeb server problems
/var/log/apache2/access.logApache HTTP requestsSame as NGINX access
/var/log/docker/daemon.logDocker daemon messagesContainer infrastructure issues
/var/log/apt/history.logPackage installations/removalsSystem changes
/var/log/btmpFailed login attemptsSecurity — who's trying to break in?
/var/log/wtmpSuccessful login/logout historyWho logged in and when

Reading Log Files

cat — Entire File

# Display entire log (works for small files)
$ cat /var/log/auth.log | head -50
Apr 10 08:00:01 server sshd[1234]: Server listening on 0.0.0.0 port 22.
Apr 10 08:15:23 server sshd[5678]: Accepted publickey for admin from 192.168.1.50
Apr 10 08:15:23 server systemd-logind[890]: New session 12 of user admin.

head and tail — Beginning and End

# Show first 20 lines
$ head -20 /var/log/syslog
 
# Show last 20 lines (most recent entries)
$ tail -20 /var/log/syslog
Apr 10 11:45:00 server CRON[9876]: (root) CMD (test -x /usr/sbin/anacron)
Apr 10 11:45:00 server CRON[9876]: (root) CMD (test -x /usr/sbin/run-parts /etc/cron.hourly)
Apr 10 11:47:00 server systemd[1]: Started Session 15 of user admin.

tail -f — Live Tail (Real-Time Monitoring)

# Watch logs in real-time — essential for troubleshooting
$ sudo tail -f /var/log/nginx/access.log
192.168.1.50 - - [10/Apr/2026:11:47:00 +0000] "GET /api/health HTTP/1.1" 200 15 "-" "curl/7.81.0"
192.168.1.51 - - [10/Apr/2026:11:47:05 +0000] "GET /api/users HTTP/1.1" 500 342 "-" "python-requests/2.28"
192.168.1.50 - - [10/Apr/2026:11:47:10 +0000] "GET /api/health HTTP/1.1" 200 15 "-" "curl/7.81.0"
^C
 
# Tail multiple files at once
$ sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log
# Tail with line count
$ tail -n 100 /var/log/syslog
# Shows last 100 lines

Filtering Logs with grep

# Find all ERROR entries
$ grep ERROR /var/log/app.log
2026-04-10 09:15:23 ERROR Database connection failed
2026-04-10 09:16:45 ERROR Request timeout: upstream read timeout
 
# Find entries from a specific time
$ grep "2026-04-10 10:" /var/log/app.log
 
# Find errors with context (5 lines before and after)
$ grep -A 5 -B 5 "ERROR" /var/log/app.log
 
# Count errors by type
$ grep ERROR /var/log/app.log | awk '{print $4}' | sort | uniq -c
    12 ConnectionError
     5 TimeoutError
     3 ValidationError
 
# Exclude DEBUG lines
$ grep -v DEBUG /var/log/app.log
 
# Use case-insensitive search
$ grep -i "warning\|error\|critical" /var/log/syslog

journalctl — Systemd Journal

Systemd stores logs in binary format in /var/log/journal/. Query them with journalctl.

Basic Usage

# Show all logs (opens in pager, like less)
$ journalctl
 
# View logs for a specific service
$ journalctl -u nginx.service
 
# Follow logs in real-time
$ journalctl -u nginx.service -f
 
# View since last boot
$ journalctl -b
 
# View logs from previous boot (if available)
$ journalctl -b -1
 
# Show last N lines
$ journalctl -u nginx.service -n 50
 
# Follow the system journal (all services)
$ journalctl -f

Filtering by Priority

Systemd uses log levels (similar to syslog):

LevelNameSeverityWhen to Use
0emergSystem unusableEmergency only
1alertMust act immediatelyImmediate action needed
2critCriticalCritical failures
3errErrorErrors
4warningWarningWarnings
5noticeNoticeSignificant but normal
6infoInformationalNormal info
7debugDebugDebug messages
# Show only errors and worse
$ journalctl -p err
 
# Show warnings and above (errors, alerts, emergencies)
$ journalctl -p warning
 
# Combine with service
$ journalctl -u nginx.service -p err

Time-Based Queries

# Logs since specific time
$ journalctl --since "2026-04-10 09:00:00"
$ journalctl --since "1 hour ago"
$ journalctl --since "today"
$ journalctl --since "yesterday"
 
# Logs between two times
$ journalctl --since "2026-04-10 09:00:00" --until "2026-04-10 10:00:00"
 
# All logs since midnight
$ journalctl --since today

Disk Usage

# Check journal disk usage
$ journalctl --disk-usage
Archived and active journals take up 1.2G on disk.
 
# Limit journal size (in /etc/systemd/journald.conf)
# Runtime journal max size
journald.conf: SystemMaxUse=500M

NGINX Log Format

Understanding log formats is essential for parsing them.

Default NGINX Access Log

$ tail -5 /var/log/nginx/access.log
192.168.1.50 - admin [10/Apr/2026:11:47:00 +0000] "GET /api/health HTTP/1.1" 200 15 "-" "curl/7.81.0"
192.168.1.51 - - [10/Apr/2026:11:47:05 +0000] "POST /api/users HTTP/1.1" 201 45 "-" "python-requests/2.28"
192.168.1.50 - admin [10/Apr/2026:11:47:10 +0000] "GET /api/health HTTP/1.1" 200 15 "-" "curl/7.81.0"

Breakdown:

IP          User  Time                              Request                           Status  Size  Referrer  User-Agent
192.168.1.50  admin  10/Apr/2026:11:47:00 +0000  "GET /api/health HTTP/1.1"        200     15    "-"       "curl/7.81.0"

Parsing NGINX Logs

# Top 10 slowest requests (by response time, if logged)
$ awk '{print $NF}' /var/log/nginx/access.log | sort -rn | head
 
# Error rate (non-200 responses)
$ grep -v '" 200 ' /var/log/nginx/access.log | wc -l
 
# Requests per minute
$ awk '{print substr($4, 14, 5)}' /var/log/nginx/access.log | sort | uniq -c
 
# Unique IP addresses
$ awk '{print $1}' /var/log/nginx/access.log | sort -u | wc -l

Log Rotation

Logs grow indefinitely — log rotation prevents them from filling the disk.

# View logrotate configuration
$ cat /etc/logrotate.conf
 
# View nginx logrotate config
$ cat /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily              # Rotate daily
    missingok           # Don't error if file is missing
    rotate 14          # Keep 14 rotated files
    compress           # Compress old logs
    delaycompress      # Delay compression (keep 1 uncomp)
    notifempty         # Don't rotate if empty
    create 0640 www-data adm    # New log file permissions
    sharedscripts      # Run postrotate script once
    postrotate
        invoke-rc.d nginx rotate >/dev/null 2>&1
    endscript
}

Quick Reference

TaskCommand
Read entire logcat /var/log/syslog
First 50 lineshead -50 /var/log/syslog
Last 50 linestail -50 /var/log/syslog
Live tailtail -f /var/log/syslog
Search for errorsgrep ERROR /var/log/app.log
Service logsjournalctl -u <service>
Follow service logsjournalctl -u <service> -f
Logs since bootjournalctl -b
Error logs onlyjournalctl -p err
Logs since timejournalctl --since "1 hour ago"

Practice Challenge

  1. Run tail -f /var/log/syslog and watch system events in real-time (press Ctrl+C to exit)
  2. Find all entries in /var/log/auth.log related to sudo usage: grep sudo /var/log/auth.log
  3. Check the size of /var/log/ with du -sh /var/log/
  4. View the last 20 entries in the nginx (or apache) access log if it exists
  5. Run journalctl -u ssh — what SSH events are logged?
  6. Find failed login attempts: journalctl -p err or check /var/log/btmp with lastb