#!/bin/bash # ----------------------------------------------------------------------------------------------- # --------------------------------- Bandwidth Monitor ------------------------------------------ # ----------------------------------------------------------------------------------------------- # Logs daily rsync transfer totals and generates weekly summary reports. # Designed for minimal flash drive impact — one bounded write per day. # # Two modes: # --log-transfer "profile" bytes duration — called by rsync.sh after each sync # appends one line, trims old entries # --report — generates weekly summary from log # (no args) — generates summary report # # Log format (one line per transfer): # YYYY-MM-DD|profile|bytes|duration_seconds # # Log file stays bounded to BANDWIDTH_LOG_RETENTION days — old entries trimmed on write. # Minimal writes: one append per rsync run, one trim per append. # # All configuration in Master.conf under Bandwidth Monitor section. # ----------------------------------------------------------------------------------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../Master.conf" source "$SCRIPT_DIR/../common.sh" parse_args "$@" # Check for log-transfer mode LOG_TRANSFER_MODE=false REPORT_MODE=false TRANSFER_PROFILE="" TRANSFER_BYTES=0 TRANSFER_DURATION=0 for arg in "${PARSED_ARGS[@]}"; do case "$arg" in --log-transfer) LOG_TRANSFER_MODE=true ;; --report) REPORT_MODE=true ;; *) if [[ "$LOG_TRANSFER_MODE" == true && -z "$TRANSFER_PROFILE" ]]; then TRANSFER_PROFILE="$arg" elif [[ "$LOG_TRANSFER_MODE" == true && "$TRANSFER_BYTES" -eq 0 ]]; then TRANSFER_BYTES="$arg" elif [[ "$LOG_TRANSFER_MODE" == true ]]; then TRANSFER_DURATION="$arg" fi ;; esac done # Ensure log file exists touch "$BANDWIDTH_LOG" 2>/dev/null || { error "Cannot create bandwidth log: $BANDWIDTH_LOG" exit 1 } # ----------------------------------------------------------------------------------------------- # LOG TRANSFER MODE # Called by rsync.sh after each successful sync — appends one line and trims old entries # Usage: bandwidth_monitor.sh --log-transfer "profile" bytes duration # ----------------------------------------------------------------------------------------------- if [[ "$LOG_TRANSFER_MODE" == true ]]; then TODAY=$(date '+%Y-%m-%d') echo "${TODAY}|${TRANSFER_PROFILE}|${TRANSFER_BYTES}|${TRANSFER_DURATION}" >> "$BANDWIDTH_LOG" log "Logged transfer: $TRANSFER_PROFILE — $TRANSFER_BYTES bytes in ${TRANSFER_DURATION}s" # Trim entries older than retention period — keeps file bounded CUTOFF=$(date -d "${BANDWIDTH_LOG_RETENTION} days ago" '+%Y-%m-%d') TEMP_FILE="${BANDWIDTH_LOG}.tmp" awk -F'|' -v cutoff="$CUTOFF" '$1 >= cutoff' "$BANDWIDTH_LOG" > "$TEMP_FILE" mv "$TEMP_FILE" "$BANDWIDTH_LOG" log "Log trimmed — keeping entries from $CUTOFF onwards" exit 0 fi # ----------------------------------------------------------------------------------------------- # REPORT MODE — generate summary from log # ----------------------------------------------------------------------------------------------- echo "" echo "━━━ $ICON_BANDWIDTH Bandwidth Report — $(date '+%Y-%m-%d %H:%M:%S') ━━━" echo "" if [[ ! -s "$BANDWIDTH_LOG" ]]; then warn "No bandwidth data yet — log is empty" warn "Data accumulates as rsync jobs run" exit 0 fi START=$(date +%s) # Calculate date range in log OLDEST=$(awk -F'|' 'NR==1{print $1}' "$BANDWIDTH_LOG") NEWEST=$(awk -F'|' 'END{print $1}' "$BANDWIDTH_LOG") ENTRY_COUNT=$(wc -l < "$BANDWIDTH_LOG") info "Log covers: $OLDEST → $NEWEST ($ENTRY_COUNT entries)" echo "" # Total bytes transferred TOTAL_BYTES=$(awk -F'|' '{sum += $3} END {print sum+0}' "$BANDWIDTH_LOG") TOTAL_GB=$(awk "BEGIN {printf \"%.2f\", $TOTAL_BYTES / 1073741824}") # Per-profile breakdown echo "━━━ $ICON_BANDWIDTH Per-Profile Totals ━━━" awk -F'|' '{ bytes[$2] += $3 runs[$2]++ duration[$2] += $4 } END { for (profile in bytes) { gb = bytes[profile] / 1073741824 printf " %-20s %6.2f GB (%d runs)\n", profile, gb, runs[profile] } }' "$BANDWIDTH_LOG" | sort -k3 -rn echo "" # Daily totals for the last 7 days echo "━━━ $ICON_BANDWIDTH Last 7 Days ━━━" for i in 6 5 4 3 2 1 0; do day=$(date -d "$i days ago" '+%Y-%m-%d') day_bytes=$(awk -F'|' -v d="$day" '$1==d{sum+=$3} END{print sum+0}' "$BANDWIDTH_LOG") day_gb=$(awk "BEGIN {printf \"%.2f\", $day_bytes / 1073741824}") # Flag days that exceeded warning threshold over_warn=$(awk "BEGIN {print ($day_bytes > $BANDWIDTH_WARN_GB * 1073741824) ? 1 : 0}") if [[ "$over_warn" == "1" ]]; then echo " $ICON_WARN $day ${day_gb} GB ← exceeded ${BANDWIDTH_WARN_GB}GB threshold" else echo " $ICON_TIME $day ${day_gb} GB" fi done echo "" echo "━━━ $ICON_SUMMARY Totals ━━━" echo " $ICON_BANDWIDTH Total transferred: ${TOTAL_GB} GB" echo " $ICON_TIME Log period: $OLDEST → $NEWEST" echo " $ICON_GEAR Retention: ${BANDWIDTH_LOG_RETENTION} days" END=$(date +%s) echo "" echo "━━━━━ $ICON_SUMMARY BANDWIDTH SUMMARY ━━━━━" echo "$ICON_BANDWIDTH Total: ${TOTAL_GB} GB" echo "$ICON_TIME Duration: $(format_duration $((END - START)))" echo "$ICON_DONE Status: $ICON_SUCCESS DONE" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" notify "Bandwidth report on $(hostname) — ${TOTAL_GB}GB transferred (${OLDEST} to ${NEWEST})" "Bandwidth Monitor" "normal"