# Info-Board Neu - Logging- und Monitoring-Konzept ## Ziel Logging und Monitoring geben dem Betriebsteam vollstaendige Transparenz ueber: - Verhalten und Fehler auf dem Player - Verhalten und Fehler auf dem Server - Health-Status aller Screens - Netzwerk- und Synchronisierungsprobleme - Kapazitaetsauslastung und Trends Das Konzept muss robust gegen Speicherplatz-Engpaesse auf dem Raspberry Pi arbeiten und zentralisiert auf dem Server auswertbar sein. ## Logging-Architektur ### Allgemeine Prinzipien - **strukturiertes JSON-Logging** — nicht Freitextloggen, sondern strukturierte Felder - **Log-Levels**: `debug`, `info`, `warn`, `error`, `fatal` - **Zentrale Auswertung** — Player loggen lokal und senden auch an Server - **Rotation und Bereinigung** — lokale Logs werden rotiert und komprimiert - **Datenschutz** — keine sensiblen Inhalte (Passwoerter, API-Keys) ins Log ### Komponenten und ihre Logs ## 1. Player-Logs ### Player-Agent Der Agent protokolliert: - **Startup/Shutdown** ```json { "ts": "2025-03-23T14:22:00Z", "level": "info", "component": "agent", "event": "startup", "config_file": "/etc/signage/config.yml", "screen_id": "info01" } ``` - **Server-Sync** ```json { "ts": "2025-03-23T14:22:05Z", "level": "info", "component": "agent.sync", "event": "sync_complete", "duration_ms": 342, "items_synced": 15, "bytes_downloaded": 4521000 } ``` - **MQTT-Ereignisse** ```json { "ts": "2025-03-23T14:22:10Z", "level": "info", "component": "agent.mqtt", "event": "playlist_changed", "source": "mqtt", "cause": "playlist-changed-event" } ``` - **Fehler** ```json { "ts": "2025-03-23T14:22:15Z", "level": "error", "component": "agent.cache", "event": "download_failed", "media_id": "abc123", "url": "https://cdn.example.com/video.mp4", "error": "connection_timeout", "retry_count": 2 } ``` - **Watchdog-Ereignisse** (siehe WATCHDOG-KONZEPT.md) ### Player-UI Die lokale Web-App protokolliert: - **Item-Wechsel** ```json { "ts": "2025-03-23T14:23:00Z", "level": "info", "component": "ui", "event": "item_change", "previous_item": "img-001", "current_item": "video-002", "source": "campaign" } ``` - **Rendering-Fehler** ```json { "ts": "2025-03-23T14:23:05Z", "level": "warn", "component": "ui.renderer", "event": "render_failed", "item_id": "url-003", "media_type": "webpage", "error": "load_timeout", "timeout_ms": 10000 } ``` - **Overlay-Status-Aenderungen** ```json { "ts": "2025-03-23T14:23:10Z", "level": "info", "component": "ui.overlay", "event": "status_change", "old_status": "online", "new_status": "offline", "reason": "broker_connection_lost" } ``` ### Chromium Der Browser ist schwer zu loggable, aber systemd journal erfasst: - Startup und Argumente - Crash-Meldungen - Fehlerrückmeldungen bei Seitenladefehler ## 2. Server-Logs ### Backend-API Der Server protokolliert: - **HTTP-Requests** (strukturiert, nicht kompletter Request-Body) ```json { "ts": "2025-03-23T14:22:20Z", "level": "info", "component": "server.http", "method": "POST", "path": "/api/v1/screens/info01/playlist", "status": 200, "duration_ms": 34, "user_id": "admin123", "tenant_id": "tenant01" } ``` - **Datenbank-Operationen** (nur bei Debug-Level) ```json { "ts": "2025-03-23T14:22:25Z", "level": "debug", "component": "server.db", "query": "UPDATE playlists SET updated_at = NOW() WHERE screen_id = $1", "duration_ms": 5, "rows_affected": 1 } ``` - **Fehler und Exceptions** ```json { "ts": "2025-03-23T14:22:30Z", "level": "error", "component": "server.api", "event": "media_download_failed", "media_id": "abc123", "reason": "storage_quota_exceeded", "available_bytes": 1024000, "required_bytes": 50000000 } ``` - **Admin-Kommandos** ```json { "ts": "2025-03-23T14:22:35Z", "level": "info", "component": "server.command", "event": "command_sent", "command_type": "restart_player", "target_screen": "info01", "triggered_by_user": "admin123" } ``` ### Provisionierungs-Worker ```json { "ts": "2025-03-23T14:22:40Z", "level": "info", "component": "server.provision", "event": "provision_started", "screen_id": "new_display_01", "target_ip": "192.168.1.50", "ansible_playbook": "site.yml" } ``` ## Log-Format und Ausgabe ### Struktur Alle Logs folgen diesem Schema: ```json { "ts": "2025-03-23T14:22:00Z", // ISO 8601, UTC "level": "info|warn|error|debug", "component": "agent|ui|server.api|server.db|server.mqtt", "event": "descriptive_name", "screen_id": "info01", // nur auf Player relevant "tenant_id": "tenant01", // nur auf Server relevant "user_id": "user123", // nur auf Server bei Auth-Events "duration_ms": 342, // bei Performance-Events // Fehler-spezifische Felder "error": "error_code", "error_message": "readable error", // Domain-spezifische Felder "item_id": "...", "media_type": "image|video|pdf|webpage", "source": "campaign|tenant_playlist|fallback", // Sonstige beliebige Felder "details": { ... } } ``` ### Ausgabeziele #### Auf dem Player 1. **stdout/stderr** mit `log/slog` JSON-Formatter - erfasst von systemd journal - abrufbar via `journalctl` 2. **Lokale Datei** `/var/log/signage/player.log` - JSON, eine Zeile pro Event - Rotation auf 100 MB, 10 Archive 3. **Schnelle Fehler** an Server via HTTP-POST - `POST /api/v1/screens/{screenSlug}/log-event` - asynchron, Fehler bei Offline ignoriert - nur `error` und `fatal` Events #### Auf dem Server 1. **stdout/stderr** mit strukturiertem Logging - erfasst von Docker/systemd - abrufbar via `docker logs` oder `journalctl` 2. **PostgreSQL** (Phase 2+) - wichtige Fehler und Status-Events in Tabelle `logs` - Abfrage-UI im Admin-Dashboard 3. **Dateispeicher** (Docker Volume) - `/var/log/signage/server.log` - Rotation und Verdichtung durch Container-Orchester ## Log-Level-Strategie ### Debug (development) - SQL-Queries - HTTP-Request-Details - interner State-Uebergaenge Bei Production: `--log-level warn` oder `--log-level info` ### Info (standard) - Startup/Shutdown - erfolgreiche Operationen - Status-Wechsel - Synchronisierungsereignisse ### Warn (aufmerksamkeit) - Timeouts - Retry-Versuche - deprecierte APIs - suboptimale Performance ### Error (problematisch) - gescheiterte HTTP-Requests - Datenbankfehler - fehlende Ressourcen - Auth-Fehler ### Fatal (kritisch) - nicht-wiederherstellbare Fehler - Prozess beendet sich danach ## Monitoring-Metriken ### Player-seitig Metriken, die der Agent periodisch dem Server meldet: ```json { "screen_id": "info01", "ts": "2025-03-23T14:25:00Z", "heartbeat": { "uptime_seconds": 86400, "last_sync_at": "2025-03-23T14:24:55Z", "seconds_since_last_sync": 5, "sync_status": "ok|failed|pending", "sync_fail_count_24h": 0 }, "resources": { "cpu_percent": 25, "memory_percent": 45, "disk_free_mb": 2048, "disk_used_percent": 35 }, "network": { "broker_connected": true, "server_reachable": true, "ip_addresses": ["192.168.1.10"], "signal_strength_dbm": -55 }, "playback": { "current_item_id": "img-001", "source": "campaign", "rendering_status": "ok", "seconds_on_current_item": 23 }, "errors_last_hour": [ { "event": "download_failed", "media_id": "video-999", "count": 2 } ] } ``` **Uebertragung:** HTTP `POST /api/v1/screens/{screenSlug}/heartbeat` alle 60 Sekunden ### Server-seitig Der Server sammelt und ueberwacht: ```json { "screen_id": "info01", "status": "online|offline|degraded|error", "last_heartbeat_at": "2025-03-23T14:25:00Z", "seconds_since_last_heartbeat": 0, "heartbeat_interval_sec": 60, "offline_since_sec": null, "screenshot": { "latest_at": "2025-03-23T14:25:00Z", "seconds_since_latest": 0 }, "sync": { "latest_at": "2025-03-23T14:24:55Z", "latest_duration_ms": 342, "fail_count_24h": 1, "last_error": null }, "content": { "current_item": "img-001", "source": "campaign", "campaign_id": "xmas-2025" }, "performance": { "cpu_avg_percent_1h": 22, "memory_avg_percent_1h": 44, "disk_free_mb": 2048 } } ``` Diese Metriken werden in PostgreSQL gespeichert und bilden Basis fuer: - Status-Dashboard - Alerts - Trend-Analysen - Kapazitaetsplanung ## Log-Rotation auf dem Player Der Raspberry Pi hat begrenzte Speicherkapazitaet. Log-Rotation muss aggressiv sein: ```yaml # /etc/logrotate.d/signage /var/log/signage/player.log { size 50M rotate 5 compress delaycompress missingok notifempty create 0644 root root postrotate systemctl reload signage-agent.service || true endscript } /var/log/signage/watchdog.log { size 20M rotate 3 compress delaycompress missingok notifempty create 0644 root root } ``` Resultat: - `player.log`: max 50 MB * 5 = 250 MB - `watchdog.log`: max 20 MB * 3 = 60 MB - Komprimierung von alten Logs auf ~10% der urspruenglichen Groesse ## Alerting-Strategie ### Kriterien fuer Alerts | Bedingung | Severity | Aktion | |---|---|---| | Screen offline > 15 min | High | Email + Dashboard-Alert | | Screen offline > 2h | Critical | Email + SMS | | Sync-Fehlerquote > 50% in 1h | Medium | Email | | Disk Full auf Player | Critical | Email + Stop-Recording | | CPU > 90% fuer 5 min | Medium | Warnung + Analysis | | Provisioning fehlgeschlagen | High | Email an Provisioner | ### Alert-Kanal (Phase 2) 1. **Dashboard-Benachrichtigungen** (im Admin-UI sichtbar) 2. **Email** an konfigurierte Admin-Adressen 3. **Webhook** fuer externe Monitoring-Systeme (Zabbix, Grafana) 4. **Server-API** `/api/v1/admin/alerts` fuer Polling ## Zusammenfassung Das Logging- und Monitoring-Konzept: - **ist strukturiert** — JSON, nicht Freitexte - **ist verteilt** — lokal auf Player + zentral auf Server - **ist speicherbewusst** — Rotation und Kompression - **gibt Ueberblick** — Heartbeat + Metriken fuer jeden Screen - **ermoeglicht Diagnose** — detaillierte Logs im Fehlerfall - **skaliert** — Verfahren gilt fuer beliebig viele Player