# CentralLogging — centrální logování (Loki + Grafana + FastAPI gateway) **Verze:** 1.0 · **Datum:** 2026-06-08 · **Autor:** Vladimír Buzalka Řešení pro sjednocení logů z rozházených skriptů projektu Janssen do jednoho centrálního místa na Unraidu, **bez zrušení stávajícího souborového logování**. Soubory a centrál běží paralelně; po ~měsíci ověřování se souborové logování vypne jedním přepínačem. --- ## 1. Architektura ``` ┌────────────────┐ HTTP POST /log/batch ┌──────────────┐ push ┌────────┐ │ Python skript │ ── Bearer token, JSON ──────▶ │ Log Gateway │ ───────▶ │ Loki │ │ (central_ │ (na pozadí, v dávkách) │ (FastAPI) │ /push │ (90 d) │ │ logging.py) │ └──────────────┘ └────┬───┘ │ │ │ │ + soubor .log │ (stávající RotatingFileHandler — zatím zůstává) │ └────────────────┘ ┌─────▼────┐ │ Grafana │ Při výpadku gateway → lokální spool .ndjson, přehraje se po obnovení. │ (dashbrd)│ └──────────┘ ``` **Proč takhle:** - **Loki** — průmyslový standard pro centrální logy, levné úložiště (chunky na Unraid share), retence vynucená automaticky, vizualizace v Grafaně. - **FastAPI gateway** (jako tvůj `msgreceiver`) — skripty neznají interní detaily Loki ani DB hesla, jen jednoduchý JSON + sdílený token. Backend lze kdykoli vyměnit beze změny skriptů. - **Klient jen stdlib** (`urllib`) — žádné `pip install` do desítek skriptů. - **Neblokující + odolné** — emit jen vloží do fronty, odesílá vlákno na pozadí v dávkách; při výpadku spool soubor → žádný log se neztratí. --- ## 2. Adresářová struktura ``` CentralLogging/ ├── README.md ← tento soubor ├── docker/ │ ├── docker-compose.yml Loki + Grafana + Gateway │ ├── loki-config.yml Loki, retence 90 dní │ └── grafana-datasource.yml auto-přidání Loki do Grafany ├── gateway/ │ ├── log_gateway_v1.0.py FastAPI brána │ ├── log_gateway_v1.0.md dokumentace brány │ ├── requirements.txt │ └── Dockerfile └── client/ ├── central_logging.py stabilní import shim ├── central_logging_v1.0.py implementace (verze ve jméně) ├── central_logging_v1.0.md dokumentace knihovny └── example_usage_v1.0.py ukázka integrace ``` --- ## 3. Nasazení na Unraid 1. Zkopíruj adresář `CentralLogging/` na Unraid (např. do `/mnt/user/appdata/central-logging/src`). 2. Uprav cesty volumes v `docker-compose.yml` (výchozí `/mnt/user/appdata/central-logging/{loki,grafana}`). 3. Nastav tajemství (soubor `.env` vedle compose, NE do gitu): ```env LOG_TOKEN=nejaky-dlouhy-nahodny-retezec GRAFANA_PASSWORD=silne-heslo ``` 4. Spusť: ```bash cd docker docker compose up -d docker compose ps ``` 5. Kontrola: - Gateway health: `curl http://192.168.1.76:8770/health` → očekávané `{"status":"ok","loki":"ready",...}` - Grafana: `http://192.168.1.76:3001` (admin / GRAFANA_PASSWORD) → Explore → datasource Loki → dotaz `{app="..."}` > Porty: Loki 3100 (interní), Grafana 3001 (3000 drží Gitea), Gateway 8770. Uprav, pokud kolidují > (msgreceiver běží na 8765). --- ## 4. Integrace do stávajících skriptů Typický skript dnes obsahuje: ```python import logging logging.basicConfig(filename=str(LOG_FILE), level=logging.ERROR, format="%(asctime)s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S", encoding="utf-8") ``` Nahradíš celý blok `basicConfig(...)` jedním voláním — **zbytek skriptu (`logging.error(...)`, `log.info(...)`) zůstává beze změny:** ```python import sys sys.path.insert(0, r"U:\PythonProject\Janssen\CentralLogging\client") from central_logging import setup_logging log = setup_logging("nazev_skriptu") # label aplikace v Loki ``` Konfigurace přes ENV (nebo argumenty `setup_logging`): | ENV | Default | Význam | |-------------------------|-----------------------------|---------------------------------------| | `CENTRAL_LOG_GATEWAY` | `http://192.168.1.76:8770` | URL brány | | `CENTRAL_LOG_TOKEN` | `change-this-shared-secret` | sdílené tajemství (musí sedět s bránou)| | `CENTRAL_LOG_ENV` | `prod` | label prostředí | | `CENTRAL_LOG_KEEP_FILE` | `1` | psát i do souboru (po měsíci → `0`) | | `CENTRAL_LOG_LEVEL` | `INFO` | min. úroveň | --- ## 5. Plán migrace (souběh → vypnutí souborů) 1. **Fáze A — souběh (cca 1 měsíc):** `keep_file=True` (default). Logy jdou do souboru i do Loki. Ověřuješ úplnost, ladíš dashboardy, labely, úrovně. 2. **Fáze B — ověření:** porovnáš soubor vs. Loki na vybraných skriptech, že nic nechybí (spool funguje i při výpadcích). 3. **Fáze C — vypnutí souborů:** nastav globálně `CENTRAL_LOG_KEEP_FILE=0` (nebo `setup_logging(..., keep_file=False)`). Skripty pak píší jen do centrálu. Staré `.log` soubory přesuň do `TRASH/` (nemazat — konvence). --- ## 6. Dotazy v Grafaně (LogQL) ```logql {app="parse_emails_graph"} # vše z jednoho skriptu {app="parse_emails_graph", level="ERROR"} # jen chyby {env="prod"} |= "bulk_write" # fulltext napříč skripty {app="edc_import"} | json | line > 100 # parsování JSON pole z těla sum by (app) (count_over_time({level="ERROR"}[1h])) # počet chyb / skript / h ``` Labely (nízká kardinalita): `app`, `host`, `level`, `env`. Vše ostatní (`logger`, `func`, `line`, `exc`, `extra`) je v těle řádku jako JSON → v Grafaně dostupné přes `| json`. --- ## 7. Bezpečnost a poznámky - Token je sdílené tajemství; drž ho v `.env` / ENV, ne v gitu. - Gateway běží v interní docker síti; ven publikuje jen port 8770. Pokud má být dostupná i mimo LAN, dej před ni reverzní proxy s TLS. - Loki má `auth_enabled: false` (single-tenant, interní). Pro veřejné vystavení přidej autentizaci na proxy. - Spool soubory (`_log_spool/*.ndjson`) vznikají jen při výpadku brány a samy se po obnovení spojení vyprázdní.