Files
drobboxordinacebackup/indexer/logger.py
T
2026-06-09 15:44:42 +02:00

133 lines
4.9 KiB
Python

import logging
import os
import sys
from logging.handlers import TimedRotatingFileHandler
from indexer.config import LOG_LEVEL, LOG_DIR
# Loki label aplikace (stabilní, BEZ verze) — podle něj se filtruje v Grafaně:
# {app="dropbox_backup"}
CENTRAL_APP_NAME = "dropbox_backup"
# Sdílené knihovny (central_logging klient) — na produkci leží v
# C:\Reporting\knihovny, v dev prostředí ve zdroji CentralLogging.
_LIB_DIRS = [
r"C:\Reporting\knihovny",
r"U:\janssen\CentralLogging\client",
]
# Token/gateway pro central logging držíme centrálně v /scripts na unraidu
# (\\tower\Scripts). Skript si je odsud načte do os.environ, takže není nutné
# nastavovat env proměnné na každém stroji ani mít token v repu/.env.
_CENTRAL_ENV_FILES = [
r"\\tower\Scripts\central_log.env",
r"\\192.168.1.76\Scripts\central_log.env",
]
def _load_central_env() -> None:
"""Načte CENTRAL_LOG_* z token souboru na unraidu (KEY=VALUE řádky) do
os.environ. Nepřepisuje už nastavené hodnoty (setdefault). Tiše ignoruje,
když share není dostupný — fallback řeší volající."""
path = os.environ.get("CENTRAL_LOG_ENV_FILE")
candidates = [path] if path else _CENTRAL_ENV_FILES
for p in candidates:
if not p or not os.path.isfile(p):
continue
try:
with open(p, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, _, val = line.partition("=")
os.environ.setdefault(key.strip(), val.strip())
return
except OSError:
continue
def _attach_central_handler(root: logging.Logger, fmt: logging.Formatter, level: int) -> bool:
"""Připojí na root logger handler centrálního logování (Grafana Loki).
Posílá KAŽDÝ log řádek (tedy i celou konzoli) do centrální gateway na
pozadí, neblokujícím způsobem se spool fallbackem. Vrací True při úspěchu.
Když klient/gateway nejsou dostupné (např. dev stroj), tiše degraduje na
file+console — záloha běží dál.
"""
_load_central_env()
for d in _LIB_DIRS:
if os.path.isdir(d) and d not in sys.path:
sys.path.insert(0, d)
try:
# importlib shim re-exportuje CentralLogHandler i _GatewaySender přes
# implementační modul; sender vytvoříme přímo, ať nepřepíšeme naše
# vlastní file+console handlery (central setup_logging si je čistí sám).
import central_logging # noqa: F401 (shim načte impl modul)
impl = sys.modules.get("central_logging_impl") or central_logging.setup_logging.__globals__
if isinstance(impl, dict):
GatewaySender = impl["_GatewaySender"]
CentralLogHandler = impl["CentralLogHandler"]
else:
GatewaySender = impl._GatewaySender
CentralLogHandler = impl.CentralLogHandler
from pathlib import Path
gw = os.environ.get("CENTRAL_LOG_GATEWAY", "http://192.168.1.76:8770")
tok = os.environ.get("CENTRAL_LOG_TOKEN", "change-this-shared-secret")
ev = os.environ.get("CENTRAL_LOG_ENV", "prod")
sender = GatewaySender(
app_name=CENTRAL_APP_NAME,
gateway=gw,
token=tok,
env=ev,
spool_dir=Path(LOG_DIR) / "_log_spool",
)
ch = CentralLogHandler(sender)
ch.setLevel(level)
ch.setFormatter(fmt)
root.addHandler(ch)
import atexit
atexit.register(sender.flush_and_stop)
return True
except Exception as e: # noqa: BLE001 — logování nikdy nesmí shodit zálohu
print(f"[logger] central logging nedostupné, pokracuji file+console: {e}")
return False
def setup_logging() -> logging.Logger:
os.makedirs(LOG_DIR, exist_ok=True)
level = getattr(logging, LOG_LEVEL.upper(), logging.INFO)
fmt = logging.Formatter(
"%(asctime)s [%(levelname)-8s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
file_handler = TimedRotatingFileHandler(
os.path.join(LOG_DIR, "backup.log"),
when="midnight",
backupCount=90,
encoding="utf-8",
)
file_handler.setFormatter(fmt)
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(fmt)
logging.root.setLevel(level)
logging.root.handlers.clear()
logging.root.addHandler(file_handler)
logging.root.addHandler(console_handler)
# Central logging (Grafana Loki) — vedle file+console, posílá vše do gateway.
if _attach_central_handler(logging.root, fmt, level):
logging.getLogger("backup").info(
"central_logging napojeno (app=%s, gateway=%s)",
CENTRAL_APP_NAME, os.environ.get("CENTRAL_LOG_GATEWAY", "http://192.168.1.76:8770"),
)
return logging.getLogger("backup")