Schiff HeimlichThe problem with copytruncate If you've ever configured logrotate for a high-throughput...
If you've ever configured logrotate for a high-throughput service like nginx or syslog, you might have used copytruncate. It copies the log file then truncates it in place, avoiding the need to signal the process to reopen its file descriptors.
The issue: there's a window between the copy and the truncate. Any log lines written during that window get either dropped or duplicated when rotation runs on a busy system.
# /etc/logrotate.d/nginx
/var/log/nginx/access.log {
daily
rotate 7
copytruncate
compress
}
On a server doing high request volume, that copy-then-truncate gap can silently eat log lines per rotation. If you're doing incident response and wondering why your access logs don't match your application logs, this is one of the places to check.
Use postrotate to signal the service to reopen its logs, then let logrotate do an atomic rename:
/var/log/nginx/access.log {
daily
rotate 7
compress
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
}
nginx (and most well-behaved services) will finish writing the current line, then reopen to the new file on SIGUSR1. No gap, no dupes.
If you're using dateext with dateformat, watch out for rotation runs that trigger twice in the same second (can happen with noisy cron or manual runs). The second rotation will fail to create a unique file. Set dateformat with enough precision:
dateformat -%Y%m%d-%s
The %s gives you Unix timestamp seconds, which keeps it unique even if cron fires twice.
copytruncate is a workaround for services that don't handle SIGUSR1 gracefully. If your service supports log reopening, use postrotate. If you're stuck with copytruncate, be aware it has a silent data loss window on busy systems.