Skip to main content

Logging and Monitoring

Running rsync without logging is like running backups with your eyes closed — you won't know if something failed until you need to restore. Proper logging provides audit trails, performance insight, and failure detection for every rsync operation.

Real-Time Progress

Per-File Progress

# Show progress bar for each file being transferred
rsync -avP /var/www/html/ user@backup:/backups/www/

The -P flag combines --progress (show transfer speed per file) and --partial (keep partially transferred files for resume).

Output example:

index.php
4,096 100% 3.91MB/s 0:00:00 (xfr#1, to-chk=1234/1500)
styles.css
12,345 67% 11.73MB/s 0:00:01

Human-Readable Sizes

rsync -avhP /var/www/html/ user@backup:/backups/www/

The -h flag converts bytes to KB/MB/GB for easier reading.

Transfer Statistics

--stats Flag

Get a summary report after the transfer:

rsync -avz --stats /var/www/html/ user@backup:/backups/www/

Output:

Number of files: 45,832 (reg: 38,291, dir: 7,541)
Number of created files: 23
Number of deleted files: 0
Number of regular files transferred: 156
Total file size: 12.47G bytes
Total transferred file size: 34.21M bytes
Literal data: 33.89M bytes
Matched data: 0 bytes
File list size: 1.23M
Total bytes sent: 35.21M
Total bytes received: 12.3K

sent 35.21M bytes received 12.3K bytes 4.70M bytes/sec
total size is 12.47G speedup is 354.12

Key metrics to monitor:

MetricWhat It Tells You
Number of regular files transferredHow many files actually changed
Total file size vs Transferred sizeDelta transfer efficiency
SpeedupHow much data rsync avoided sending (higher = better)
Number of deleted filesWhen using --delete — verify expected deletions
Total bytes sentActual network usage

Log to File

Basic File Logging

rsync -av --log-file=/var/log/rsync/backup.log \
/var/www/html/ user@backup:/backups/www/

Dated Log Files

Give each run its own log file:

rsync -av --log-file="/var/log/rsync/backup_$(date +%F_%H%M).log" \
--stats \
/var/www/html/ user@backup:/backups/www/

Combine Stats + Log

rsync -avz --stats --log-file=/var/log/rsync/backup.log \
/var/www/html/ user@backup:/backups/www/

Itemized Changes (--itemize-changes)

Get detailed information about what changed for each file:

rsync -av --itemize-changes /var/www/html/ /backup/www/

Output format:

>f.st...... index.php # File transferred, size and time changed
>f..t...... config.yaml # File transferred, time changed only
cd+++++++++ new-directory/ # New directory created
*deleting old-file.txt # File deleted from destination

Decoding the Flags

>f.st......
│││││
│││││
│││└┴── Other attributes (permissions, owner, group, etc.)
││└──── Size changed
│└───── Timestamp changed
└────── f=file, d=directory, L=symlink
SymbolMeaning
>fFile being sent to destination
cdDirectory being created
.Attribute unchanged
sSize differs
tTimestamp differs
pPermissions differ
oOwner differs
gGroup differs

Logging in Automated Scripts

Production Backup Script with Logging

#!/bin/bash
# backup-with-logging.sh
set -e

TIMESTAMP=$(date +%F_%H%M)
LOG_DIR="/var/log/rsync"
LOG_FILE="$LOG_DIR/backup_$TIMESTAMP.log"
ALERT_EMAIL="admin@example.com"

mkdir -p "$LOG_DIR"

echo "[$TIMESTAMP] Starting backup..." >> "$LOG_FILE"

# Run rsync with stats and logging
if rsync -avz --stats \
--exclude='cache/' \
--exclude='*.log' \
--log-file="$LOG_FILE" \
/var/www/html/ user@backup:/backups/www/ \
>> "$LOG_FILE" 2>&1; then

echo "[$TIMESTAMP] Backup completed successfully" >> "$LOG_FILE"
else
EXIT_CODE=$?
echo "[$TIMESTAMP] Backup FAILED (exit code: $EXIT_CODE)" >> "$LOG_FILE"

# Send alert on failure
echo "Rsync backup failed. Check $LOG_FILE" | \
mail -s " Backup Failed on $(hostname)" "$ALERT_EMAIL"
fi

Cron with Logging

# Daily backup at 2 AM with logging
0 2 * * * /usr/local/bin/backup-with-logging.sh

# Weekly full backup with separate log
0 3 * * 0 rsync -avz --stats --log-file="/var/log/rsync/weekly_$(date +\%F).log" \
/var/www/ user@backup:/backups/weekly/

Log Rotation

Prevent logs from filling up disk space:

/etc/logrotate.d/rsync
/var/log/rsync/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 root root
}

Or use a simple cleanup in your backup script:

# Delete rsync logs older than 30 days
find /var/log/rsync/ -name "*.log" -mtime +30 -delete

Analyzing Logs

Check for Errors

# Find errors in logs
grep -i "error\|failed\|denied" /var/log/rsync/backup.log

# Check what was deleted
grep "deleting" /var/log/rsync/backup.log

# Count files transferred
grep "^>f" /var/log/rsync/backup.log | wc -l

Monitor in Real Time

# Watch log as backup runs
tail -f /var/log/rsync/backup.log

# Watch for errors only
tail -f /var/log/rsync/backup.log | grep -i "error\|failed"

Common Pitfalls

PitfallConsequencePrevention
No logging on cron jobsFailures go unnoticed for days/weeksAlways use --log-file in automated runs
Logs in /var/www/Publicly accessible, potential data leakStore logs in /var/log/rsync/
No log rotationLogs fill the diskUse logrotate or find -mtime cleanup
Not checking exit codesScript reports success even on failureCheck $? and alert on non-zero exit
Only using --progress (no persistent log)No record after terminal closesUse --log-file for persistent records
Not monitoring --stats outputInefficient transfers go unnoticedReview speedup ratio periodically

Quick Reference

# Real-time progress
rsync -avhP /src/ user@dest:/dest/

# Transfer statistics
rsync -avz --stats /src/ user@dest:/dest/

# Log to file
rsync -av --log-file=/var/log/rsync/backup.log /src/ user@dest:/dest/

# Itemized changes (detailed diff)
rsync -av --itemize-changes /src/ /dest/

# Combination: stats + log + progress
rsync -avzhP --stats --log-file=/var/log/rsync/backup.log /src/ user@dest:/dest/

# Analyze logs
grep -i "error\|failed" /var/log/rsync/backup.log
grep "deleting" /var/log/rsync/backup.log

What's Next