📋 Logging Basics

Logging & Log Management Series: Part 1 — Basics  |  Part 2 — journald  |  Part 3 — logrotate  |  Part 4 — Centralized Logging

Why Logging Matters

Logs are the memory of your system. They record what happened, when it happened, and often why. When a service fails at 3 AM, when security is breached, when a user reports a problem that happened last Tuesday — logs are what let you reconstruct the story. A system with no logs, or logs that were not being kept, is a system you cannot understand or defend.

Linux uses two parallel logging systems: the traditional syslog/rsyslog which writes text files to /var/log/, and the modern systemd journal which stores binary logs queryable with journalctl. On most modern systems both run simultaneously.

Syslog Fundamentals — Facility and Severity

Every syslog message has two attributes that determine how it is routed and stored: a facility (what generated it) and a severity (how important it is).

Facilities

FacilityCodeSource
kern0Kernel messages
user1User-level messages
mail2Mail system
daemon3System daemons
auth4Security/authentication messages
syslog5Messages generated by syslogd
lpr6Line printer subsystem
cron9Cron daemon
local0–local716–23Local use — custom applications

Severity Levels

LevelCodeMeaningExamples
emerg0System unusableKernel panic, out of memory
alert1Immediate action requiredDatabase corruption detected
crit2Critical conditionsHardware failure
err3Error conditionsService failed to start
warning4Warning conditionsDisk at 90% capacity
notice5Normal but significantService started/stopped
info6InformationalUser logged in
debug7Debug messagesDetailed trace output
Severity is a threshold — not an exact match. When rsyslog is configured to log warning and above, it captures warning, err, crit, alert, and emerg — everything at that level and more severe. The lower the number, the more critical the message.

Examples

1
Key Log Files in /var/log/
# View the /var/log directory
ls -lh /var/log/

# The most important log files on RHEL/Rocky:
sudo tail -f /var/log/messages      # general system messages
sudo tail -f /var/log/secure        # auth, SSH, sudo
sudo tail -f /var/log/cron          # cron job execution
sudo tail -f /var/log/maillog       # mail system
sudo tail -f /var/log/boot.log      # boot messages
sudo tail -f /var/log/audit/audit.log  # SELinux, auditd

# On Debian/Ubuntu:
sudo tail -f /var/log/syslog        # general system (equiv to messages)
sudo tail -f /var/log/auth.log      # auth (equiv to secure)
sudo tail -f /var/log/kern.log      # kernel messages
sudo tail -f /var/log/dpkg.log      # package install/remove

# Application-specific logs
sudo tail -f /var/log/httpd/access_log    # Apache access
sudo tail -f /var/log/httpd/error_log     # Apache errors
sudo tail -f /var/log/nginx/access.log    # Nginx access
sudo tail -f /var/log/nginx/error.log     # Nginx errors
sudo tail -f /var/log/postgresql/*.log    # PostgreSQL
💡 tail -f is your live window. tail -f /var/log/messages follows the log in real time — new lines appear as they are written. Combine with grep to filter: tail -f /var/log/secure | grep sshd
2
Reading and Searching Log Files
# View last 50 lines
sudo tail -50 /var/log/messages
sudo tail -50 /var/log/secure

# View first lines (useful for log file header/start)
sudo head -20 /var/log/messages

# Search for a pattern
sudo grep "Failed password" /var/log/secure
sudo grep "error" /var/log/messages
sudo grep -i "error\|fail\|warn" /var/log/messages

# Search with context (3 lines before and after match)
sudo grep -B3 -A3 "segfault" /var/log/messages

# Filter by date (logs use month day format)
sudo grep "^Apr 25" /var/log/messages
sudo grep "^Apr 25 10:" /var/log/messages   # specific hour

# Count occurrences
sudo grep -c "Failed password" /var/log/secure

# Find most common SSH failure sources
sudo grep "Failed password" /var/log/secure | \
    awk '{print $11}' | sort | uniq -c | sort -rn | head -10

# Search compressed rotated logs too
sudo zgrep "error" /var/log/messages-20260420.gz
sudo zcat /var/log/messages-20260420.gz | grep "error"
Typical /var/log/secure entry:
Apr 25 10:22:15 server sshd[12345]: Failed password for invalid user admin from 203.0.113.42 port 54321 ssh2 Apr 25 10:22:18 server sshd[12346]: Accepted publickey for craig from 192.168.1.5 port 54400 ssh2
3
rsyslog Configuration

rsyslog is configured in /etc/rsyslog.conf and files in /etc/rsyslog.d/. Rules follow the format facility.severity destination:

# View rsyslog configuration
cat /etc/rsyslog.conf
ls /etc/rsyslog.d/

# Check rsyslog status
sudo systemctl status rsyslog
Key lines from /etc/rsyslog.conf:
# Log anything of level info or higher, except mail, authpriv and cron *.info;mail.none;authpriv.none;cron.none /var/log/messages # Auth messages go to /var/log/secure authpriv.* /var/log/secure # Log all the mail messages in one place mail.* -/var/log/maillog # Log cron stuff cron.* /var/log/cron # Everybody gets emergency messages *.emerg :omusrmsg:*
# Create a custom log rule -- drop in /etc/rsyslog.d/
sudo tee /etc/rsyslog.d/myapp.conf << 'EOF'
# Log myapp messages to its own file
if $programname == 'myapp' then /var/log/myapp.log
& stop
EOF

# Restart rsyslog to apply
sudo systemctl restart rsyslog

# Test: send a test message
logger -t myapp "Test log message"
sudo tail /var/log/myapp.log
The - prefix before a filename (e.g., -/var/log/maillog) tells rsyslog to use async (non-synced) writes — faster but risks losing the last few messages if the system crashes. Fine for non-critical logs, not for security logs.
4
The logger Command — Write to Syslog from Scripts

logger sends messages directly to syslog from the command line or scripts — the right way to log from shell scripts:

# Basic usage
logger "Backup started"
logger "Backup completed successfully"

# Specify tag (program name in log)
logger -t mybackup "Starting nightly backup"
logger -t mybackup "Backup completed: 42 files, 1.2GB"

# Specify facility and severity
logger -p local0.info    "Informational message"
logger -p local0.warning "Warning: disk at 85%"
logger -p local0.err     "Error: backup failed"
logger -p auth.notice    "Admin login from 192.168.1.5"

# Log both to syslog AND stderr
logger -s -t myapp "Error occurred"

# Use in scripts
#!/bin/bash
log() {
    logger -t "$(basename $0)" "$*"
    echo "$(date '+%Y-%m-%d %H:%M:%S') $*"
}

log "Script started"
/usr/local/bin/do-work.sh && log "Work completed" || log "Work FAILED"
💡 Use logger in every cron script. When a cron job calls logger, its activity appears in /var/log/messages alongside all other system events — timestamped, searchable, and integrated with the rest of your logging infrastructure. Far better than writing to a private log file nobody checks.
5
Log File Anatomy — Reading the Format

Traditional syslog format follows a consistent structure:

# Format: TIMESTAMP HOSTNAME PROGRAM[PID]: MESSAGE
sudo head -5 /var/log/messages
Annotated example:
Apr 25 10:22:15 bambustudio sshd[12345]: Accepted publickey for craig │ │ │ │ │ │ │ │ │ └── Message │ │ │ └────────── PID │ │ └─────────────── Program name │ └──────────────────────────── Hostname └─────────────────────────────────────────── Timestamp (no year!)
# The missing year is a known syslog limitation
# Use journalctl for full ISO timestamps with year:
sudo journalctl --since "2026-04-25" | head -5

# Convert syslog timestamps to something more useful
sudo grep "Apr 25" /var/log/messages | \
    awk '{print 2026, $1, $2, $3, $5}' | head -5
Syslog timestamps have no year. This causes problems when reading logs from a previous year or when log files span a year boundary. This is one of the reasons journald with its full ISO timestamps is preferred for new systems. See Part 2 for journalctl in depth.
6
Monitor Logs in Real Time
# Follow multiple log files simultaneously with multitail
sudo dnf install -y multitail 2>/dev/null || sudo apt install -y multitail
multitail /var/log/messages /var/log/secure

# Watch for specific patterns across all logs
sudo tail -f /var/log/messages /var/log/secure /var/log/cron | \
    grep --line-buffered -i "error\|fail\|warn"

# Alert on critical events
sudo tail -f /var/log/messages | while read line; do
    if echo "$line" | grep -qi "critical\|emergency\|kernel panic"; then
        echo "$line" | mail -s "CRITICAL: $(hostname)" admin@example.com
    fi
done

# Check disk space used by logs
sudo du -sh /var/log/*  | sort -rh | head -20

# Find the largest log files
sudo find /var/log -type f -name "*.log" -exec du -sh {} \; | \
    sort -rh | head -10
⚠️ Logs can fill your disk. Without logrotate, log files grow without bound. A busy web server or a misbehaving application can fill /var/log in hours. Monitor disk usage on your log partition and set up logrotate for every application log. See Part 3 for complete logrotate coverage.
7
Check What Is and Is Not Being Logged
# What rsyslog rules are active?
sudo rsyslogd -N1    # validate config
sudo rsyslogd -dn 2>&1 | head -30   # debug mode output

# List all log files being written to
sudo lsof | grep /var/log | awk '{print $9}' | sort -u

# What services are NOT sending to syslog (writing their own logs)?
sudo find /var/log -name "*.log" -newer /var/log/messages | head -20

# Check if auditd is running (security audit log)
sudo systemctl is-active auditd
sudo auditctl -l    # list active audit rules

# Verify messages are actually flowing
logger -t test "Test message $(date)"
sudo grep "Test message" /var/log/messages
sudo journalctl -t test -n 5
Know what is NOT being logged. Many applications write their own log files outside /var/log/ — in their install directory, /opt/, or their home directory. These logs often have no rotation configured and grow indefinitely. Do a periodic survey of all log files on your system.
8
Log Analysis Script — Daily Summary
#!/bin/bash
# log-daily-summary.sh -- morning report on yesterday's log activity

YESTERDAY=$(date -d "yesterday" "+%b %e" | sed 's/  / /')
LOG=/var/log/messages
SECURE=/var/log/secure

echo "========================================"
echo " Daily Log Summary: $(hostname)"
echo " Reporting on: $YESTERDAY"
echo " Generated: $(date)"
echo "========================================"

echo ""
echo "--- AUTHENTICATION FAILURES ---"
count=$(grep "$YESTERDAY" $SECURE 2>/dev/null | grep -c "Failed password")
echo "  SSH failed passwords:     $count"
count=$(grep "$YESTERDAY" $SECURE 2>/dev/null | grep -c "Invalid user")
echo "  Invalid usernames tried:  $count"
count=$(grep "$YESTERDAY" $SECURE 2>/dev/null | grep -c "sudo:")
echo "  sudo commands run:        $count"

echo ""
echo "--- TOP SSH FAILURE SOURCES ---"
grep "$YESTERDAY" $SECURE 2>/dev/null | grep "Failed password" | \
    awk '{print $11}' | sort | uniq -c | sort -rn | head -5 | \
    awk '{printf "  %5d attempts from %s\n", $1, $2}'

echo ""
echo "--- SYSTEM ERRORS ---"
count=$(grep "$YESTERDAY" $LOG 2>/dev/null | grep -c " error\| Error\| ERROR")
echo "  Error messages:    $count"
count=$(grep "$YESTERDAY" $LOG 2>/dev/null | grep -c " warn\| Warn\| WARN")
echo "  Warning messages:  $count"
count=$(grep "$YESTERDAY" $LOG 2>/dev/null | grep -c "kernel:")
echo "  Kernel messages:   $count"

echo ""
echo "--- DISK USAGE ON /var/log ---"
du -sh /var/log/ 2>/dev/null | awk '{print "  Total: " $1}'
df -h /var/log 2>/dev/null | tail -1 | awk '{print "  Available: " $4}'

echo "========================================"

Quick Reference

Key Log Files

FileRHELDebian/UbuntuContents
General messages/var/log/messages/var/log/syslogMost system activity
Auth/security/var/log/secure/var/log/auth.logSSH, sudo, login
Kernel/var/log/messages/var/log/kern.logKernel messages
Cron/var/log/cron/var/log/syslogCron job execution
Mail/var/log/maillog/var/log/mail.logMail system activity
Audit/var/log/audit/audit.log/var/log/audit/audit.logSELinux, auditd
Boot/var/log/boot.log/var/log/boot.logBoot sequence

Essential Commands

CommandWhat it does
tail -f /var/log/messagesFollow log in real time
tail -100 /var/log/secureLast 100 lines of auth log
grep "pattern" /var/log/messagesSearch log for pattern
grep -c "error" /var/log/messagesCount matching lines
zgrep "pattern" /var/log/messages*.gzSearch compressed rotated logs
logger -t mytag "message"Write message to syslog
logger -p local0.err "error"Write with facility and severity
sudo systemctl status rsyslogCheck rsyslog daemon
sudo rsyslogd -N1Validate rsyslog config
du -sh /var/log/*Log file sizes

← Back to Logging Index ↑ Back to EXPANDED