Using cron for Automated Log Rotation
Learn how to use cron to automate log rotation on Linux with simple examples and best practices for DevOps beginners. Step-by-step setup, scheduling tips, and common pitfalls to avoid.
Short introduction: Automated log rotation keeps disk usage under control, reduces manual work, and helps systems stay performant and compliant. This guide shows practical ways to use cron (and simple scripts) to schedule log rotation, whether you rely on system tools like logrotate or build lightweight custom solutions.
Understanding log rotation basics
Before scheduling rotations, know what needs to happen when a log grows: archive or compress the old file, create a fresh file (or truncate), optionally restart or signal the writing process so it recreates the file handle, and remove or prune older archives to save space. Rotation policies typically specify frequency (daily, weekly), retention (keep X files), compression, and whether to run post-rotation hooks.
Terminal example — inspect a common log and size:
$ ls -lh /var/log/nginx/access.log
-rw-r----- 1 nginx adm 45M Sep 26 12:00 /var/log/nginx/access.log
$ tail -n 3 /var/log/nginx/access.log
192.0.2.1 - - [26/Sep/2025:11:59:58 +0000] "GET /index.html HTTP/1.1" 200 1024
192.0.2.2 - - [26/Sep/2025:11:59:59 +0000] "GET /style.css HTTP/1.1" 200 2048
192.0.2.3 - - [26/Sep/2025:11:59:59 +0000] "GET /script.js HTTP/1.1" 200 512
Explanation: The process that writes the log (nginx in this example) keeps a file descriptor open. If you move or compress the file without signaling the process, it may continue writing to the old inode, leading to reclaimed disk space not being freed. Proper rotation either truncates the file in place or signals/restarts the process so it reopens its log file.
Creating a cron job for rotation
Cron provides simple, reliable scheduling for rotation tasks. Use cron when you want to run a custom rotation script or trigger a rotation utility on a schedule. Edit the crontab for root (recommended if logs require root access):
Crontab example — run a rotation script daily at 02:30:
# edit root crontab
$ sudo crontab -e
# add this line to run /usr/local/sbin/logrotate-custom daily at 02:30
30 2 * * * /usr/local/sbin/logrotate-custom >> /var/log/logrotate-custom.log 2>&1
Sample script to rotate a single log by truncating (safe if application supports truncation):
#!/bin/bash
LOG="/var/log/myapp/app.log"
ARCHIVE_DIR="/var/log/myapp/archive"
mkdir -p "$ARCHIVE_DIR"
TS=$(date +%F-%H%M)
cp "$LOG" "$ARCHIVE_DIR/app.log.$TS"
: > "$LOG" # truncate in-place so the process keeps using the same file descriptor
gzip "$ARCHIVE_DIR/app.log.$TS"
find "$ARCHIVE_DIR" -type f -name "app.log.*.gz" -mtime +30 -delete
Explanation: The cron entry runs the script at the scheduled time and logs output. The script copies the current log to an archive, truncates the active log in-place (so no process restart needed), compresses the archive, and removes archives older than 30 days.
Integrating logrotate with cron
Most Linux distributions install logrotate, which handles many rotation tasks declaratively. logrotate itself is usually invoked by cron.daily or systemd timers. You can write a custom config and place it in /etc/logrotate.d or call logrotate manually from cron if you need non-default timing.
Example: a logrotate config file for /var/log/myapp/app.log:
/var/log/myapp/app.log {
daily
rotate 14
compress
missingok
notifempty
create 0640 myapp adm
sharedscripts
postrotate
# If the app supports USR1 for reopen:
/bin/kill -USR1 `cat /var/run/myapp.pid` 2>/dev/null || true
endscript
}
Test logrotate manually:
# simulate rotation and view debug output
$ sudo logrotate -d /etc/logrotate.d/myapp
# force rotation immediately:
$ sudo logrotate -f /etc/logrotate.d/myapp
Explanation: The config sets a daily rotation, keeps 14 compressed rotations, creates the new log with proper permissions, and runs a postrotate block to signal the application to reopen its log file. Use -d to debug and -f to force a rotation when testing.
Writing a custom rotation script
Sometimes you need behavior not covered by logrotate (e.g., custom naming, remote archival, or special post-processing). A robust script should handle errors, permissions, atomic moves, and retention.
Example script using atomic move and gzip:
#!/bin/bash
set -euo pipefail
LOG="/var/log/custom/service.log"
ARCHIVE_DIR="/var/log/custom/archive"
RETENTION=10
mkdir -p "$ARCHIVE_DIR"
TS=$(date +%F-%H%M%S)
TMP="$ARCHIVE_DIR/service.log.$TS.tmp"
ARCHIVE="$ARCHIVE_DIR/service.log.$TS.gz"
# Move the file atomically and create a new empty one with correct permissions
if [ -f "$LOG" ]; then
mv "$LOG" "$TMP"
# ensure a fresh file exists (same owner/mode as before)
touch "$LOG"
chown --reference="$TMP" "$LOG" || true
chmod --reference="$TMP" "$LOG" || true
gzip -c "$TMP" > "$ARCHIVE" && rm -f "$TMP"
fi
# cleanup older archives
find "$ARCHIVE_DIR" -type f -name "service.log.*.gz" -printf '%T@ %p\n' \
| sort -n \
| awk 'NR<=-'"$RETENTION"' {print $2}' \
| xargs -r rm --
Cron entry to run this every 4 hours:
0 */4 * * * /usr/local/sbin/custom-rotate.sh >> /var/log/custom-rotate.log 2>&1
Explanation: Atomic move (mv) prevents writers from corrupting partial files; creating a new file helps some daemons reopen automatically. Preserve ownership/mode to avoid permission errors. Use find or a retention algorithm to limit stored archives. set -euo pipefail makes the script fail loudly on errors — good for visibility.
Verifying and monitoring rotations
After deploying rotation tasks, verify they work and monitor for failures. Check rotated files, timestamps, sizes, and that services are still writing to the active log. A small command set helps quickly inspect status.
Quick verification commands:
# list archives
$ ls -lh /var/log/myapp/archive
# verify the current log is growing
$ tail -f /var/log/myapp/app.log
# check last rotate timestamp in rotation log (if you log)
$ sudo tail -n 20 /var/log/logrotate-custom.log
Commands table
| Command | Purpose |
|---|---|
| sudo crontab -e | Edit root crontab for scheduling tasks |
| ls -lh /var/log/... | Inspect file size and ownership |
| tail -f /var/log/... | Observe live writes to a log |
| sudo logrotate -d /etc/logrotate.d/myapp | Debug logrotate config without performing rotation |
| sudo logrotate -f /etc/logrotate.d/myapp | Force immediate rotation for testing |
| find ... -mtime +N -delete | Remove old archives older than N days |
| kill -USR1 $(cat /var/run/app.pid) | Signal a daemon that supports reopen to close and reopen logs |
Explanation: Use these commands to confirm rotations occurred, ensure services reattached to new files, and check retention. For more long-term monitoring, consider alerting when log disk usage exceeds a threshold or when rotation scripts omit expected logs.
Common Pitfalls
- Not signaling or restarting the writer process after moving the log, causing disk space to remain consumed by an unlinked file.
- Running rotation scripts as an unprivileged user without correct permissions, which causes failures or incomplete rotations.
- Assuming all applications handle truncation or file moves the same way — some require specific signals or full restarts.
Next Steps
- Configure logrotate for other system logs and place app-specific configs in /etc/logrotate.d.
- Add basic alerting (e.g., disk usage or script exit codes) into your monitoring to detect rotation failures.
- Version and test your rotation scripts in a staging environment; use forced rotations to validate behavior before production rollout.
👉 Explore more IT books and guides at dargslan.com.