Offsite backup: write one JSON line per run to ~/Library/Logs

Each run (also failed or aborted ones, via the EXIT trap) appends start,
end, exit code, "complete" and the result per share to
bfds-offsite-backup.jsonl so a dashboard can show the last complete run.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Claude committed 2026-10-30 01:08:07 +01:00
1 parent f035a3dc0c
commit 46e13a4dd5
1 file changed
+41 -1
@@ -37,6 +37,12 @@ DEVICE="${DEVICE:-}"
MOUNTED_BY_US=0 MOUNTED_BY_US=0
# Run-Protokoll: pro Lauf eine JSON-Zeile, aus der das Dashboard den letzten
# durchgehenden Run (alle Freigaben fehlerfrei) abliest.
RUN_LOG_FILE="${RUN_LOG_FILE:-}"
RUN_START="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
SHARE_RESULTS=""
log() { log() {
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
} }
@@ -54,6 +60,35 @@ unmount_volume() {
MOUNTED_BY_US=0 MOUNTED_BY_US=0
} }
# Ergebnis einer Freigabe merken: ok, source_missing, unreadable oder rsync_<code>
record_share() {
SHARE_RESULTS="${SHARE_RESULTS:+$SHARE_RESULTS,}\"$1\":\"$2\""
}
# Haengt am Ende jedes Laufs (auch bei Fehler oder Abbruch) eine JSON-Zeile an
# ~/Library/Logs/bfds-offsite-backup.jsonl an. "complete" ist nur wahr, wenn das
# Script mit 0 endete und jede Freigabe "ok" war.
write_run_record() {
local rc="$1" end ok total="${#SHARES[@]}" complete=false home
end="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
ok="$(printf '%s' "$SHARE_RESULTS" | grep -o ':"ok"' | wc -l | tr -d ' ')"
[ "$rc" -eq 0 ] && [ "$ok" -eq "$total" ] && complete=true
if [ -z "$RUN_LOG_FILE" ]; then
home="$HOME"
if [ -n "${SUDO_USER:-}" ]; then
home="$(dscl . -read "/Users/$SUDO_USER" NFSHomeDirectory 2>/dev/null | awk '{print $2}')"
[ -n "$home" ] || home="$HOME"
fi
RUN_LOG_FILE="$home/Library/Logs/bfds-offsite-backup.jsonl"
fi
mkdir -p "$(dirname "$RUN_LOG_FILE")" 2>/dev/null
printf '{"start":"%s","end":"%s","exit_code":%s,"complete":%s,"shares":{%s}}\n' \
"$RUN_START" "$end" "$rc" "$complete" "$SHARE_RESULTS" >> "$RUN_LOG_FILE" \
|| { log "WARNUNG: Run-Protokoll konnte nicht geschrieben werden: $RUN_LOG_FILE"; return 0; }
# Unter sudo gehoert die Datei sonst root
if [ -n "${SUDO_USER:-}" ]; then chown "$SUDO_USER" "$RUN_LOG_FILE" 2>/dev/null || true; fi
}
# Die Disk-Nummer wechselt (disk4, disk6, ...). Gesucht wird daher die # Die Disk-Nummer wechselt (disk4, disk6, ...). Gesucht wird daher die
# Partition 1 auf externen, physischen Platten, die >= MIN_SIZE_GB gross sind # Partition 1 auf externen, physischen Platten, die >= MIN_SIZE_GB gross sind
# und nicht von macOS eingebunden werden koennen (Typ "Microsoft Basic Data", # und nicht von macOS eingebunden werden koennen (Typ "Microsoft Basic Data",
@@ -81,7 +116,7 @@ find_offsite_partition() {
echo "${found[0]}" echo "${found[0]}"
} }
trap 'unmount_volume' EXIT trap 'rc=$?; unmount_volume; write_run_record "$rc"' EXIT
trap 'log "Abgebrochen"; exit 130' INT TERM trap 'log "Abgebrochen"; exit 130' INT TERM
# ************************************************** # **************************************************
@@ -172,6 +207,7 @@ run_rsync() {
if [ ! -d "$source" ]; then if [ ! -d "$source" ]; then
log "WARNUNG: Quelle nicht gefunden, bitte SMB-Freigabe oeffnen: smb://$SOURCE_HOST/$share" log "WARNUNG: Quelle nicht gefunden, bitte SMB-Freigabe oeffnen: smb://$SOURCE_HOST/$share"
EXIT_CODE=1 EXIT_CODE=1
record_share "$share" source_missing
return return
fi fi
@@ -179,6 +215,7 @@ run_rsync() {
if ! run_with_timeout "$PROBE_TIMEOUT" probe_source "$source"; then if ! run_with_timeout "$PROBE_TIMEOUT" probe_source "$source"; then
log "WARNUNG: $source nicht lesbar (haengt oder Fehler), ueberspringe $share. Freigabe im Finder trennen und neu verbinden." log "WARNUNG: $source nicht lesbar (haengt oder Fehler), ueberspringe $share. Freigabe im Finder trennen und neu verbinden."
EXIT_CODE=1 EXIT_CODE=1
record_share "$share" unreadable
return return
fi fi
@@ -202,6 +239,9 @@ run_rsync() {
if [ "$rc" -ne 0 ]; then if [ "$rc" -ne 0 ]; then
log "WARNUNG: rsync fuer $share endete mit Code $rc" log "WARNUNG: rsync fuer $share endete mit Code $rc"
EXIT_CODE=1 EXIT_CODE=1
record_share "$share" "rsync_$rc"
else
record_share "$share" ok
fi fi
} }