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
}