What You'll Build
In this exercise you will implement a complete log management system for CricketPulse: a logrotate configuration that rotates, compresses, and retains logs on schedule, a cron job that generates a daily log summary report, and a systemd timer unit that performs weekly log archival to a separate directory. Each component is verified to work correctly before moving to the next, building a production-quality log management pipeline from first principles.
Log management is one of those operational concerns that feels like infrastructure overhead until a disk fills at 3am during a match-day traffic spike and takes the entire CricketPulse platform offline for 45 minutes. Every production team has a version of that story — and every team that implements log management properly beforehand does not. This exercise builds the habits that prevent it.
The exercise combines cron syntax, logrotate configuration, shell scripting with output redirection, systemd timer units, and journalctl verification into a single coherent system. By the end, you will have a complete, tested log management stack that handles the full lifecycle: rotation, compression, retention, reporting, and archival — all running automatically without requiring any manual intervention from the operations team.
Prerequisites
- Completion of Lessons 13–15: package management, networking basics, and cron/scheduling/logs.
- A Linux system with systemd, cron, and logrotate installed (all present by default on Ubuntu 20.04+).
- The CricketPulse directory structure from previous exercises with active log files — the setup commands in this lesson create sample log data if needed.
- Understanding of shell arithmetic and date commands — the summary script uses these to compute log statistics.
- Sudo access for installing logrotate configuration in `/etc/logrotate.d/` and systemd units in `/etc/systemd/system/`.
Setup & Project Structure
The setup creates the CricketPulse directory structure and populates the log directory with realistic sample log files of varying ages and sizes. This provides the actual log data that the log management system will operate on, making it possible to verify that rotation, compression, and retention work correctly rather than testing against an empty directory.
The sample log generation creates files that span the last 35 days, ensuring the 30-day retention policy has files eligible for deletion from the first test run. It also creates files that are large enough to trigger size-based rotation, allowing both time-based and size-based rotation to be tested in a single exercise session.
#!/bin/bash
# setup_logs.sh — generate sample CricketPulse log data
set -euo pipefail
id cricketpulse &>/dev/null || \
useradd --system --no-create-home --shell /usr/sbin/nologin cricketpulse
mkdir -p /var/log/cricketpulse /var/archive/cricketpulse
chown -R cricketpulse:cricketpulse /var/log/cricketpulse
chown root:cricketpulse /var/archive/cricketpulse
chmod 2775 /var/archive/cricketpulse
# Generate current app.log with realistic content
for i in $(seq 1 200); do
echo "[$(date '+%H:%M:%S')] INFO Serving match data — request $i" \
>> /var/log/cricketpulse/app.log
done
chown cricketpulse:cricketpulse /var/log/cricketpulse/app.log
# Generate old log files (35 days ago) — eligible for deletion
for i in 30 31 32 33 34 35; do
OLD_FILE="/var/log/cricketpulse/app.log.$i"
echo "Old log content from $i days ago" > "$OLD_FILE"
touch -d "$i days ago" "$OLD_FILE"
chown cricketpulse:cricketpulse "$OLD_FILE"
done
# Generate a large log file (10MB) to trigger size-based rotation
dd if=/dev/urandom bs=1M count=10 2>/dev/null \
| base64 > /var/log/cricketpulse/error.log
chown cricketpulse:cricketpulse /var/log/cricketpulse/error.log
echo 'Setup complete'
ls -lh /var/log/cricketpulse/
Step 1 — Foundation: logrotate Configuration
Step 1 creates the logrotate configuration file and tests it before deployment. The configuration covers two log patterns: `app.log` with daily rotation and 30-day retention, and `error.log` with size-based rotation (rotate when it exceeds 10MB) and 7-copy retention. The critical practice is testing with `--debug` before deploying and testing the actual rotation with `--force` in a staging environment to confirm the `postrotate` signal reaches the application.
The `postrotate` script in the logrotate configuration sends `SIGUSR1` to the CricketPulse process to trigger log file reopening. Without this signal, the application continues writing to the rotated file (now named `app.log.1`) while the new `app.log` is empty — a variation of the deleted-but-open file descriptor problem from the filesystem lesson. The `|| true` at the end of the `postrotate` command prevents logrotate from failing if the service is temporarily down.
# /etc/logrotate.d/cricketpulse
/var/log/cricketpulse/app.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 640 cricketpulse cricketpulse
postrotate
systemctl kill --signal=USR1 cricketpulse 2>/dev/null || true
endscript
}
/var/log/cricketpulse/error.log {
size 10M
rotate 7
compress
delaycompress
missingok
notifempty
create 640 cricketpulse cricketpulse
}
# ✅ Test configuration before deploying
logrotate --debug /etc/logrotate.d/cricketpulse
# ✅ Force rotation to verify it works correctly
logrotate --force /etc/logrotate.d/cricketpulse
ls -lh /var/log/cricketpulse/
# Expected: app.log (new, empty), app.log.1 (rotated from today)