Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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 installdo 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
- Zkopíruj adresář
CentralLogging/na Unraid (např. do/mnt/user/appdata/central-logging/src). - Uprav cesty volumes v
docker-compose.yml(výchozí/mnt/user/appdata/central-logging/{loki,grafana}). - Nastav tajemství (soubor
.envvedle compose, NE do gitu):LOG_TOKEN=nejaky-dlouhy-nahodny-retezec GRAFANA_PASSWORD=silne-heslo - Spusť:
cd docker docker compose up -d docker compose ps - 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="..."}
- Gateway health:
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:
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:
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ů)
- 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ě. - Fáze B — ověření: porovnáš soubor vs. Loki na vybraných skriptech, že nic nechybí (spool funguje i při výpadcích).
- Fáze C — vypnutí souborů: nastav globálně
CENTRAL_LOG_KEEP_FILE=0(nebosetup_logging(..., keep_file=False)). Skripty pak píší jen do centrálu. Staré.logsoubory přesuň doTRASH/(nemazat — konvence).
6. Dotazy v Grafaně (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í.