#!/usr/bin/env bash # fetch-app-logs.sh — App-Crash-Logs von der VM holen # # Nutzt .claude/aria-vm.env als Quelle fuer $ARIA_DIAG_URL und ruft # GET /api/app-log?limit=N. Speichert die Roh-Response unter # .aria-debug/app-log-.json und gibt eine kompakte # Zusammenfassung auf stdout aus (letzte Eintraege mit Stack-Trace). # # Verwendung: # tools/fetch-app-logs.sh # Default limit=200 # tools/fetch-app-logs.sh --limit 50 # nur 50 holen # tools/fetch-app-logs.sh --clear # nach Abholen Log loeschen # tools/fetch-app-logs.sh --watch # alle 5s pollen, neue Eintraege ausgeben set -euo pipefail LIMIT=200 CLEAR=0 WATCH=0 while [[ $# -gt 0 ]]; do case "$1" in --limit) LIMIT="$2"; shift 2 ;; --limit=*) LIMIT="${1#*=}"; shift ;; --clear) CLEAR=1; shift ;; --watch) WATCH=1; shift ;; -h|--help) sed -n '1,/^set/p' "$0" | sed '$d' | sed 's/^# \{0,1\}//' exit 0 ;; *) echo "Unbekannte Option: $1" >&2; exit 1 ;; esac done ROOT="$(cd "$(dirname "$0")/.." && pwd)" ENV_FILE="$ROOT/.claude/aria-vm.env" OUT_DIR="$ROOT/.aria-debug" if [[ ! -f "$ENV_FILE" ]]; then echo "FEHLER: $ENV_FILE nicht vorhanden. Aus .example kopieren und IP anpassen." >&2 exit 1 fi # shellcheck disable=SC1090 source "$ENV_FILE" if [[ -z "${ARIA_DIAG_URL:-}" ]]; then echo "FEHLER: ARIA_DIAG_URL nicht gesetzt in $ENV_FILE" >&2 exit 1 fi mkdir -p "$OUT_DIR" fetch_once() { local ts json file ts="$(date +%Y%m%d_%H%M%S)" json="$(curl -s --max-time 10 "${ARIA_DIAG_URL%/}/api/app-log?limit=$LIMIT")" || { echo "FEHLER: curl gegen $ARIA_DIAG_URL fehlgeschlagen" >&2 return 1 } file="$OUT_DIR/app-log-$ts.json" echo "$json" > "$file" python3 - "$file" <<'PY' import json, sys from pathlib import Path data = json.loads(Path(sys.argv[1]).read_text()) entries = data.get("entries") or [] print(f"=== {len(entries)} Eintrag{'e' if len(entries)!=1 else ''} (gespeichert unter {sys.argv[1]}) ===") for e in entries[-20:]: ts = e.get("ts") or 0 from datetime import datetime when = datetime.fromtimestamp(ts/1000).strftime("%H:%M:%S") if ts else "?" lvl = e.get("level","?") scope = e.get("scope","?") msg = (e.get("message") or "").splitlines()[0][:200] print(f"\n[{when}] {lvl:5} {scope}: {msg}") stack = (e.get("stack") or "").strip() if stack: for line in stack.splitlines()[:8]: print(f" {line}") if len(stack.splitlines()) > 8: print(f" ... ({len(stack.splitlines())-8} weitere Zeilen — siehe JSON)") PY return 0 } if [[ "$WATCH" == "1" ]]; then echo "Watching $ARIA_DIAG_URL/api/app-log — Ctrl+C zum Beenden" SEEN="" while true; do cur=$(curl -s --max-time 10 "${ARIA_DIAG_URL%/}/api/app-log?limit=$LIMIT") || cur="" hash=$(echo "$cur" | md5sum | awk '{print $1}') if [[ "$hash" != "$SEEN" && -n "$cur" ]]; then SEEN="$hash" fetch_once fi sleep 5 done else fetch_once fi if [[ "$CLEAR" == "1" ]]; then echo echo "→ Log auf der VM leeren..." curl -s --max-time 5 -X POST "${ARIA_DIAG_URL%/}/api/app-log/clear" | python3 -m json.tool || true fi