Log Rotation and Compression
Rotate and compress application logs with Bash to prevent disk exhaustion and simplify log retention.
Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.
Overview
Application logs grow continuously. Without rotation, a single verbose service can fill a disk, crash the host, and make log analysis impractical. A Bash log rotation script renames active logs, compresses old ones, and deletes archives past a retention age. This keeps logs accessible, searchable, and bounded in size without relying on a heavyweight log management agent.
When to Use
Use this resource when:
- You need to rotate logs on a server without logrotate installed.
- You want custom naming, compression, or retention rules.
- You rotate logs for a container or embedded environment.
- You need to ship compressed logs to cold storage.
Solution
Bash log rotation script
#!/usr/bin/env bash
set -euo pipefail
LOG_DIR="${1:-/var/log/app}"
RETENTION_DAYS="${2:-30}"
MAX_SIZE_MB="${3:-100}"
mkdir -p "$LOG_DIR/archive"
for log in "$LOG_DIR"/*.log; do
[[ -f "$log" ]] || continue
size_mb=$(du -m "$log" | cut -f1)
if (( size_mb > MAX_SIZE_MB )); then
base=$(basename "$log" .log)
timestamp=$(date +%Y%m%d-%H%M%S)
rotated="$LOG_DIR/archive/${base}-${timestamp}.log"
mv "$log" "$rotated"
gzip "$rotated"
touch "$log"
fi
done
# Delete old compressed logs
find "$LOG_DIR/archive" -name '*.gz' -type f -mtime +$RETENTION_DAYS -delete
# Optional: signal the app to reopen logs
# kill -HUP "$APP_PID"
echo "Log rotation completed"
Explanation
The script iterates over *.log files in the target directory. If a log exceeds MAX_SIZE_MB, it renames the file with a timestamp, compresses it with gzip, and creates a new empty log file. Old compressed archives are deleted after RETENTION_DAYS. The optional kill -HUP tells daemons that expect signal-based reopening to close the old file descriptor and start writing to the new file. This is common for long-running services like nginx or custom apps.
Variants
| Variant | Compression | Use case |
|---|---|---|
| gzip | Default | Good balance, widely supported |
| bzip2 | Slower, smaller | Long-term archives |
| zstd | Fast, modern | Large log volumes |
| xz | Smallest, slowest | Compliance archives |
Best Practices
- Rotate before the disk is full. Monitor free space and rotate at 70-80% usage, not 99%.
- Use copytruncate or signals when possible. Moving an open log file can cause the app to keep writing to the old inode.
- Keep archive permissions restrictive. Logs may contain sensitive data; set
chmod 640on archives. - Test rotation on a copy first. A bad script can delete active logs; validate against a non-production directory.
- Centralize logs after rotation. Ship compressed logs to S3, Loki, or Elasticsearch for retention and search.
Common Mistakes
- Deleting logs before compression. The archive step can fail; keep the original until gzip succeeds.
- Rotating the same file twice. Timestamped filenames prevent overwriting the same archive.
- Not handling log files in subdirectories. Use
findwith-maxdepthif logs are nested. - Running as root unnecessarily. Use the service account that owns the log files.
- Forgetting to reopen file descriptors. The app may keep writing to the moved file; send HUP or use copytruncate.
Frequently Asked Questions
Q: When should I use logrotate instead of a custom script? A: Use logrotate for standard Linux servers. Use a custom script when you need behavior that logrotate cannot express, or when logrotate is not available.
Q: How do I avoid losing log lines during rotation? A: Use copytruncate or send HUP to the application. This ensures the app closes the old file and starts writing to the new one.
Q: Can I rotate logs by date instead of size? A: Yes. Run the script from cron daily and remove the size check. The date-based timestamp still archives the previous day.
Related Resources
Compress and Decompress Files
How to handle ZIP, GZIP, and TAR archives programmatically.
RecipeBash Scripting for DevOps Automation and System Tasks
How to write robust Bash scripts for automating deployments, system monitoring, log rotation, and routine maintenance tasks
RecipeBackup Rotation Script
Automate file backups with retention policies using a Bash script that rotates daily, weekly, and monthly snapshots.
RecipeBash Loop Over Files
How to safely loop over files and directories in Bash, handling spaces, globs, and large file lists with correct patterns.
RecipeBash Parallel Execution
How to run shell commands in parallel with xargs, GNU parallel, and Bash background jobs while controlling concurrency and collecting results.