# PVE Backup Log Viewer Ein schlankes Web-UI, das vzdump-Task-Logs direkt aus `/var/log/pve/tasks/` einliest und auswertet. Eine einzige Python-Datei (`app.py`), eine Abhängigkeit (Flask), Bedienung im Browser. Läuft direkt auf dem PVE-Host und bietet drei Sichten: - **Übersicht** aller vzdump- und PBS-Backup-Läufe mit Quelle (PVE/PBS), Status, Knoten/Datastore, Art und Gästezahl - **Detail eines Backup-Laufs** mit Tabelle aller Gäste (ID, Name, Typ, Status, Dauer, Übertragen, Gespeichert, Reused, Gesamt) plus KPI-Kacheln und Fehlerbanner - **Entwicklung pro VM/CT-ID** mit gruppiertem Balkendiagramm (Übertragen vs. Gespeichert), Dauer-Trend und vollständiger Historie – mischt PVE- und PBS-Datenpunkte je nachdem was verfügbar ist ![Screenshot-Schema: Dark-Theme, IBM Plex Mono, orange Akzentfarbe](#) ## Features - **Zwei Quellen, ein UI** – liest sowohl PVE-vzdump-Logs (`/var/log/pve/tasks/`) als auch PBS-Backup-Task-Logs (`/var/log/proxmox-backup/tasks/`) und stellt beide einheitlich dar. Quellen werden automatisch erkannt; jede einzeln deaktivierbar. - **Robuste UPID-Erkennung** – funktioniert mit dem aktuellen 7-Feld-Format (`UPID:node:pid:pstart:starttime:type:id:user`) und der älteren 8-Feld-Variante mit zusätzlichem `task-id`. Erkennung über `@` im User-Feld als Anker. - **Inkrementeller Cache** nach Datei-mtime: beim Start einmal alles parsen, danach nur Geänderte. Skaliert auf hunderte/tausende Task-Logs. - **Mehrere Backup-Modi** im Parser: - PVE-Seite: CT (pxar), VM laufend (Dirty-Bitmap), VM gestoppt (Vollscan) - PBS-Seite: pro Task das aggregierte `Upload statistics`-Bilanz über alle Archive/Disks - **Gespeichert vs. Übertragen** unterscheidet, was vom Quellgast hochgeladen wurde und was davon tatsächlich neu im Datastore landete (für PBS-Sicht sind beide Werte identisch, weil PBS nur sieht/schreibt, was wirklich neu war) - **Fehler-Anzeige** für fehlgeschlagene Backups (z.B. „No space left on device"): Job-Banner, Status-Pills, KPI „Fehlgeschlagen" und Fehlertext direkt in der Zeile - **Scan-Diagnose** im Footer: Anzahl Subdirs (mit Permission-Fehlern), gefundene UPID-Files, davon Backup-Tasks – hilft beim Debugging ## Voraussetzungen - Proxmox VE 7+/8+ und/oder Proxmox Backup Server 2+/3+ - Python 3.10+ - Flask 3.x - Leseberechtigung auf den jeweiligen Task-Verzeichnissen: - `/var/log/pve/tasks/` (Standard: `www-data:www-data`, Mode 750) - `/var/log/proxmox-backup/tasks/` (Standard: `backup:backup`, Mode 750) ## Installation Zwei Wege: dedizierter LXC per Helper-Script (empfohlen), oder direkt auf einem PVE-Host neben pveproxy. ### Variante A: Eigener LXC-Container (empfohlen) `install-lxc.sh` zeigt ein whiptail-Menü mit zwei Modi (Standard / Erweitert), erstellt einen privilegierten LXC (wegen Bind-Mount ohne UID-Mapping), bind-mountet `/var/log/pve/tasks` und – falls auf dem Host vorhanden – auch `/var/log/proxmox-backup/tasks` jeweils read-only, kopiert die App rein und startet den Service. **Einzeiler aus dem Netz** (lädt alle nötigen Dateien automatisch): ```bash bash -c "$(curl -fsSL https://dc8wan.de/backup-dashboard/install-lxc.sh)" ``` **Oder lokal aus dem entpackten ZIP**: ```bash unzip pve-log-viewer.zip cd pve-log-viewer bash install-lxc.sh ``` Im Menü: - **Standard-Einstellungen** – schnelles Setup mit Defaults (nächste freie CTID, Debian 12, 1 vCPU, 256 MB RAM, 8 GB rootfs, DHCP) - **Erweiterte Einstellungen** – jeder Parameter einzeln abfragbar (CTID, Hostname, Disk, CPU, RAM, Storage, Bridge, IP/Gateway, Task-Dir, Port, Read-only-Mount) - **Abbrechen** – tut nichts **Skriptgesteuerter Modus** (kein Menü, alles per Umgebungsvariable): ```bash CTID=115 HOSTNAME=backup-dashboard \ IP=192.168.11.240/24 GW=192.168.11.254 \ NONINTERACTIVE=1 \ bash -c "$(curl -fsSL https://dc8wan.de/backup-dashboard/install-lxc.sh)" ``` Konfigurierbare Variablen: `CTID`, `HOSTNAME`, `DISK_SIZE`, `CORES`, `MEMORY`, `STORAGE`, `TEMPLATE_STORAGE`, `BRIDGE`, `IP`, `GW`, `TASK_DIR`, `APP_PORT`, `READONLY_MOUNT`, `BASE_URL` (Quelle für Downloads), `NONINTERACTIVE`. Details im Script-Kopf. Der erzeugte Container entspricht im Wesentlichen dieser pct-Config: ``` arch: amd64 cores: 1 features: nesting=1 hostname: backup-dashboard memory: 256 mp0: /var/log/pve/tasks,mp=/var/log/pve/tasks,acl=1,ro=1 net0: name=eth0,bridge=vmbr0,firewall=1,ip=dhcp,type=veth onboot: 1 ostype: debian rootfs: local-lvm:vm--disk-0,size=8G swap: 0 unprivileged: 0 ``` ### Variante B: Direkt auf dem PVE-Host ```bash mkdir -p /opt/pve-log-viewer cd /opt/pve-log-viewer unzip ~/pve-log-viewer.zip -d . apt install -y python3-venv python3 -m venv venv ./venv/bin/pip install -r requirements.txt cp pve-log-viewer.service /etc/systemd/system/ systemctl daemon-reload systemctl enable --now pve-log-viewer # → http://:5000 ``` ## Konfiguration Alles über Umgebungsvariablen, am bequemsten in der systemd-Unit gesetzt: | Variable | Default | Beschreibung | | --------------- | ---------------------------------- | ----------------------------------------------- | | `PVE_TASK_DIR` | `/var/log/pve/tasks` | PVE-vzdump-Task-Logs. Fallback auf `/var/log/pve/task` für sehr alte Versionen. | | `PBS_TASK_DIR` | `/var/log/proxmox-backup/tasks` | PBS-Backup-Task-Logs. Wird automatisch ignoriert, wenn der Pfad nicht existiert. | | `LISTEN_HOST` | `0.0.0.0` | Bind-Adresse. Auf `127.0.0.1` setzen, wenn ein Reverse-Proxy davor steht. | | `LISTEN_PORT` | `5000` | TCP-Port. | ## Architektur Eine einzelne `app.py` mit: 1. **Parser** für vzdump-Logs (`parse_log`) – erkennt CT/VM, Status, Dauer, Übertragen, Reused (Bytes + Prozent), Gespeichert (berechnet als `Gesamt − Reused`), Fehler. 2. **UPID-Parser** (`parse_upid`) – split-basiert, findet User über `@`, ermittelt Worker-Type/-ID und Startzeit. 3. **Scanner** (`scan_tasks`) – läuft bei jedem Request, cacht parsed Daten nach mtime, filtert auf `UPID:…:vzdump:…`. 4. **Flask-Routen**: `/` Übersicht, `/log/` Detail, `/vm/` Entwicklung. 5. **Templates** inline via `render_template_string` – kein extra Templates-Ordner, IBM Plex Sans/Mono über Google Fonts, Chart.js über CDN. Wenn die App ohne Internet auskommen soll, Fonts und Chart.js lokal einbinden – sind die einzigen externen Ressourcen. ## Reverse-Proxy (optional) Für sauberen Produktivbetrieb gunicorn dahinter setzen und in nginx/Caddy als Vhost binden: ```nginx location /pbslogs/ { proxy_pass http://127.0.0.1:5000/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } ``` Dabei `LISTEN_HOST=127.0.0.1` setzen, damit Port 5000 nicht von außen erreichbar ist. ## Multi-Node-Cluster Die App liest nur den lokalen `/var/log/pve/tasks/`. In einem PVE-Cluster also pro Node eine Instanz – jede zeigt nur die Tasks ihres Knotens. Eine Cluster-weite Aggregation über die PVE-API (`pvesh get /cluster/tasks`) ist denkbar, aber nicht implementiert. ## Datenfelder Die wichtigsten extrahierten Werte pro Gast: - **Übertragen** – PVE: aus `had to backup X of Y` (pxar) bzw. `transferred X` (QEMU). PBS: aus `Upload size: N` der einzelnen Archive-Statistik-Blöcke, aufsummiert. - **Gespeichert** – PVE: `Gesamt − Reused`. PBS: identisch mit Übertragen, weil PBS nur das sieht, was nach Dedup über die Leitung kam. - **Reused** – PVE: aus `backup was done incrementally, reused X (Y%)`. PBS: `Gesamt − Übertragen`. Im UI als `Bytes · Prozent`. - **Gesamt** – PVE: Quellgröße. PBS: Summe aller `Size: N` über alle Archive (Disk-Images + pxar-Archive). - **Dauer** – aus `Finished Backup of VM N (HH:MM:SS)` bzw. bei Fehlern aus `Backup started at` ↔ `Failed at` (PVE) bzw. aus erster ISO-Zeile bis `TASK OK/ERROR` (PBS). - **Fehler** – PVE: `INFO: Error: …` bevorzugt, sonst aus `ERROR: Backup of VM N failed - …` extrahiert. PBS: aus `TASK ERROR: …`. ## Troubleshooting **Footer zeigt `0 vzdump`:** Wenn dort auch `(X unlesbar)` steht, läuft die App nicht als `www-data`. Per systemd ist das schon richtig konfiguriert; bei manuellem Start eventuell `sudo -u www-data ./venv/bin/python app.py` verwenden. **Banner „Keine Leseberechtigung auf …":** Gleiche Ursache. **Keine Diagramme:** Browser-Konsole prüfen. Chart.js kommt von `cdn.jsdelivr.net` – bei strikten CSP-Setups eventuell blockiert. **Einträge fehlen:** PVE rotiert die Task-Logs irgendwann (Retention via `pveproxy`). Sehr alte Backups sind dann nicht mehr in der Historie. ## Lizenz Privat/Homelab. Keine Lizenz vergeben – nutze nach Bedarf.