Skip to content

Log Rotation

logrotate manages automatic rotation, compression, and deletion of log files, preventing disk space exhaustion while maintaining log history.

logrotate Fundamentals

How logrotate Works

┌─────────────────────────────────────────────────────────────┐
│                    Daily Cron Job                            │
│            /etc/cron.daily/logrotate                         │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│                    logrotate                                 │
│           Reads /etc/logrotate.conf                          │
│           Includes /etc/logrotate.d/*                        │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│                    For each log file:                        │
│         1. Check rotation criteria (size, time)              │
│         2. Execute prerotate scripts                         │
│         3. Rotate: app.log → app.log.1                       │
│         4. Compress old files                                │
│         5. Execute postrotate scripts                        │
│         6. Remove files beyond rotate limit                  │
└─────────────────────────────────────────────────────────────┘

Configuration Files

File Purpose
/etc/logrotate.conf Main configuration
/etc/logrotate.d/*.conf Per-application configs
/var/lib/logrotate/status Rotation state

Main Configuration

/etc/logrotate.conf

# Default settings
weekly
rotate 4
create
dateext
compress

# Uncomment to use extended pattern matching
#compresscmd /usr/bin/xz
#compressext .xz

# Include application-specific configs
include /etc/logrotate.d

Key Directives

Directive Description
daily/weekly/monthly Rotation frequency
rotate N Keep N rotated files
compress Compress rotated files
delaycompress Compress on second rotation
create mode owner group Create new log with permissions
notifempty Don't rotate empty logs
missingok Don't error if log missing
copytruncate Copy then truncate (no reload)
dateext Add date to rotated filename

Creating Rotation Rules

Basic Example

# /etc/logrotate.d/myapp

/var/log/myapp/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data www-data
    sharedscripts
    postrotate
        systemctl reload myapp > /dev/null 2>&1 || true
    endscript
}

Detailed Configuration

# /etc/logrotate.d/myapp

/var/log/myapp/*.log {
    # Rotation frequency
    daily               # Rotate daily (weekly, monthly)

    # Retention
    rotate 30           # Keep 30 rotated files
    maxage 90          # Delete files older than 90 days

    # Size-based rotation (instead of/with time)
    size 100M          # Rotate when file reaches 100M
    minsize 10M        # Don't rotate if smaller than 10M
    maxsize 500M       # Force rotate if larger than 500M

    # Compression
    compress           # Compress rotated files
    delaycompress      # Wait one rotation before compressing
    compresscmd /usr/bin/gzip
    compressoptions -9
    compressext .gz

    # File handling
    missingok          # Don't error if file is missing
    notifempty         # Don't rotate empty files
    create 0640 www-data www-data  # New file permissions
    olddir /var/log/myapp/archive  # Move old logs here

    # Naming
    dateext            # Use date in rotated filename
    dateformat -%Y%m%d # Date format (default: -%Y%m%d)

    # Scripts
    sharedscripts      # Run scripts once for all matched files
    prerotate
        echo "Starting rotation" >> /var/log/myapp/rotate.log
    endscript
    postrotate
        systemctl reload myapp > /dev/null 2>&1 || true
    endscript
    lastaction
        echo "Rotation complete" >> /var/log/myapp/rotate.log
    endscript
}

Common Configurations

Nginx

# /etc/logrotate.d/nginx

/var/log/nginx/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data adm
    sharedscripts
    prerotate
        if [ -d /etc/logrotate.d/httpd-prerotate ]; then
            run-parts /etc/logrotate.d/httpd-prerotate
        fi
    endscript
    postrotate
        invoke-rc.d nginx rotate >/dev/null 2>&1 || true
    endscript
}

Apache

# /etc/logrotate.d/apache2

/var/log/apache2/*.log {
    daily
    rotate 14
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
    sharedscripts
    postrotate
        if invoke-rc.d apache2 status > /dev/null 2>&1; then
            invoke-rc.d apache2 reload > /dev/null 2>&1
        fi
    endscript
}

Application Without Reload Support

For applications that don't support log reopening:

# /etc/logrotate.d/simpleapp

/var/log/simpleapp/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    copytruncate        # Copy then truncate original
    # No postrotate needed - app keeps writing to same file
}

Large Log Files

# /etc/logrotate.d/bigapp

/var/log/bigapp/*.log {
    size 500M           # Rotate when file reaches 500M
    rotate 10
    compress
    compresscmd /usr/bin/xz    # Use xz for better compression
    compressext .xz
    delaycompress
    missingok
    notifempty
    create 0644 root root
}

Remote Archive

# /etc/logrotate.d/archive-remote

/var/log/important/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
    sharedscripts
    lastaction
        # Sync to remote storage after rotation
        rsync -avz /var/log/important/*.gz backup@storage:/logs/$(hostname)/ || true
    endscript
}

Scripts in Rotation

Script Types

Script When it Runs
prerotate Before rotation
postrotate After rotation
firstaction Once before all rotations
lastaction Once after all rotations

Script Options

Option Effect
sharedscripts Run scripts once for all matched files
nosharedscripts Run scripts for each file (default)

Example: Service Reload

/var/log/myservice/*.log {
    daily
    rotate 7
    compress
    sharedscripts
    postrotate
        # Method 1: systemd
        systemctl reload myservice > /dev/null 2>&1 || true

        # Method 2: Send signal
        [ -f /var/run/myservice.pid ] && kill -USR1 $(cat /var/run/myservice.pid) || true

        # Method 3: Service command
        service myservice reload > /dev/null 2>&1 || true
    endscript
}

Testing and Debugging

Test Configuration

# Dry run (show what would happen)
sudo logrotate -d /etc/logrotate.d/myapp

# Force rotation (actually rotate)
sudo logrotate -f /etc/logrotate.d/myapp

# Verbose output
sudo logrotate -v /etc/logrotate.d/myapp

Debug Output

# Verbose dry run
sudo logrotate -d -v /etc/logrotate.conf

# Output:
# reading config file /etc/logrotate.conf
# including /etc/logrotate.d
# reading config file myapp
# ...
# considering log /var/log/myapp/app.log
#   log needs rotating
# rotating log /var/log/myapp/app.log, log->rotateCount is 7
# ...

Force Immediate Rotation

# Rotate specific config
sudo logrotate -f /etc/logrotate.d/myapp

# Rotate all
sudo logrotate -f /etc/logrotate.conf

Check Status

# View rotation state
cat /var/lib/logrotate/status

# Output:
# logrotate state -- version 2
# "/var/log/apt/term.log" 2024-1-15-6:25:1
# "/var/log/syslog" 2024-1-15-6:25:1

Reset Rotation State

# Reset specific log state
sudo sed -i '/myapp/d' /var/lib/logrotate/status

# Or reset all
sudo rm /var/lib/logrotate/status

Troubleshooting

Logs Not Rotating

# Check logrotate runs
sudo logrotate -d /etc/logrotate.d/myapp

# Common issues:
# - Missing file: Check path is correct
# - Permissions: Check user can read/write
# - Already rotated: Check status file
# - Configuration error: Test with -d

Disk Space Issues

# Check rotation is working
ls -la /var/log/myapp/

# Check how much space logs use
du -sh /var/log/*

# Force cleanup of old logs
sudo logrotate -f /etc/logrotate.conf

Service Not Reloading

# Test postrotate manually
sudo systemctl reload myservice

# Check if signal works
sudo kill -USR1 $(cat /var/run/myservice.pid)

# Add error logging to script
postrotate
    systemctl reload myservice 2>> /var/log/logrotate-errors.log
endscript

Configuration Errors

# Syntax check
sudo logrotate -d /etc/logrotate.d/myapp 2>&1 | grep -i error

# Common syntax errors:
# - Missing closing brace
# - Invalid directive
# - Permission issue in postrotate

Best Practices

Rotation Strategy

Log Type Recommendation
Application logs Daily, 14-30 rotations
Access logs Daily, 30-90 rotations
Security logs Daily, 90+ rotations
Debug logs Daily, 7 rotations
Error logs Size-based (100M), 30 rotations

Space Management

# Calculate space needed
# Example: 100MB daily log, 30 rotations, 80% compression
# = 100MB active + (100MB × 30 × 0.2) = 700MB total

# Set conservative limits
size 100M      # Rotate at 100M
rotate 30      # Keep 30 files
maxage 90      # Delete after 90 days regardless

Security Considerations

# Secure permissions
create 0640 root adm

# Secure old directory
olddir /var/log/myapp/archive
createolddir 0750 root adm

# Don't world-readable
create 0640 syslog adm

Quick Reference

Commands

# Test configuration
sudo logrotate -d /etc/logrotate.d/config

# Force rotation
sudo logrotate -f /etc/logrotate.d/config

# Verbose
sudo logrotate -v /etc/logrotate.d/config

# View state
cat /var/lib/logrotate/status

Common Directives

Directive Example Purpose
daily daily Rotate daily
weekly weekly Rotate weekly
size size 100M Rotate at size
rotate rotate 7 Keep N files
compress compress gzip old files
delaycompress delaycompress Compress after 1 rotation
create create 0640 root adm New file permissions
copytruncate copytruncate Copy and truncate
postrotate postrotate...endscript Run after rotation

Key Files

File Purpose
/etc/logrotate.conf Main config
/etc/logrotate.d/*.conf App configs
/var/lib/logrotate/status State file

Next Steps

With logging configured, proceed to Services Management to harden and optimize running services.