Resolving Logrotate Dateext Filename Mismatch: Aligning Rotation Dates with Log Content Periods


2 views

When working with monthly log rotations, many sysadmins encounter this frustrating behavior:


# Current rotation (September 1st)
error_log -> error_log.2023.09  # Actually contains August logs

The fundamental issue stems from logrotate's design: it uses the rotation date rather than the log period date when generating filenames with dateext.

This discrepancy causes several operational headaches:

  • Log analysts must mentally subtract one month when searching historical data
  • Automated log processing scripts require additional date adjustment logic
  • Archival systems may misfile logs due to inconsistent dating

Here are three approaches I've successfully implemented:

1. The dateyesterday Hack


/var/log/http/*log {
    monthly
    dateext
    dateformat .%Y.%m
    prerotate
        YESTERDAY=$(date -d "yesterday" +"%Y.%m")
        mv "${1}.${YESTERDAY}" "${1}.$(date -d "yesterday -1 month" +"%Y.%m")" 2>/dev/null || true
    endscript
    [...]
}

2. Custom Rotation Script with Offset

For more control, create a wrapper script:


#!/bin/bash
# /usr/local/bin/logrotate-with-offset

LOG_PATH=$1
OFFSET_MONTHS=${2:-1}  # Default 1 month offset

ACTUAL_DATE=$(date -d "-${OFFSET_MONTHS} month" +"%Y.%m")
TARGET_FILE="${LOG_PATH}.${ACTUAL_DATE}"

/usr/sbin/logrotate -f /etc/logrotate.d/custom_apache
mv "${LOG_PATH}.$(date +"%Y.%m")" "${TARGET_FILE}"

3. Apache's rotatelogs Alternative

While you mentioned preferring logrotate, sometimes using Apache's built-in solution works better:


CustomLog "|/usr/bin/rotatelogs -l /var/log/http/access_log.%Y.%m 86400" combined
  • Test any solution in a non-production environment first
  • Document the date offset convention for your team
  • Consider log retention policies when changing naming schemes
  • Monitor disk space during transition periods

For most implementations, I recommend the first approach (prerotate script) as it:

  • Maintains existing logrotate infrastructure
  • Requires minimal changes to current configurations
  • Provides clear audit trails of rotation actions

When using logrotate with Apache or other services, the default dateext behavior creates rotated filenames based on the rotation date rather than the log period. This creates a mismatch where:

error_log.2023.09  # Filename suggests September
                   # Actual content: August logs

The discrepancy becomes problematic when:

  • Searching logs by date range
  • Automating log analysis scripts
  • Complying with audit requirements
  • Maintaining consistent naming across services

The dateext feature uses the system time at rotation moment to generate filenames. For monthly rotations at midnight on the 1st:

# Rotation occurs at 2023-09-01 00:00:01
# Generates: error_log.2023.09
# Contains: 2023-08-01 through 2023-08-31 logs

While logrotate doesn't natively support date offsets, we can create a pre-rotation script:

/var/log/http/*log {
    monthly
    dateext
    dateformat .%Y.%m
    prerotate
        # Calculate previous month for filename
        ROTDATE=$(date -d "1 month ago" +%Y.%m)
        mv "$1" "${1%.*}.$ROTDATE"
    endscript
    [...]
}

For systems where modifying rotation is difficult, consider this post-rotation script:

postrotate
    # Get last modified date of original log
    LOGDATE=$(date -r "$1" +%Y.%m)
    # Rename the rotated file
    mv "$1.1" "$1.$LOGDATE"
endscript
  • Test scripts with logrotate -d first
  • Consider timezone differences in date calculations
  • Ensure proper file permissions during rename operations
  • Document the naming convention for other admins

Here's a complete Apache configuration that worked in production:

/var/log/apache2/*.log {
    monthly
    missingok
    rotate 12
    compress
    delaycompress
    dateext
    dateformat .%Y.%m
    prerotate
        if [ -f "$1" ]; then
            LOGMONTH=$(date -d "$(stat -c %y "$1") -15 days" +%Y.%m)
            mv "$1" "${1%.*}.$LOGMONTH"
        fi
    endscript
    sharedscripts
    postrotate
        /usr/sbin/apachectl graceful >/dev/null
    endscript
}