This commit is contained in:
2026-06-09 15:44:42 +02:00
parent 07e6a9c374
commit 9b9310e8fd
3 changed files with 132 additions and 1 deletions
+12 -1
View File
@@ -20,7 +20,18 @@
"Bash(\"C:\\\\Python\\\\python.exe\" -m pip list)", "Bash(\"C:\\\\Python\\\\python.exe\" -m pip list)",
"Bash(findstr:*)", "Bash(findstr:*)",
"Bash(ls:*)", "Bash(ls:*)",
"Bash(C:Pythonpython.exe -m pip install pyzipper)" "Bash(C:Pythonpython.exe -m pip install pyzipper)",
"mcp__knowledgebase__search",
"mcp__mcp-registry__list_connectors",
"mcp__knowledgebase__get_context",
"mcp__knowledgebase__get_recent",
"Bash(U:/janssen/.venv/Scripts/python.exe -c ' *)",
"Bash(U:/janssen/.venv/Scripts/python.exe -X utf8 -c ' *)",
"Bash(U:/janssen/.venv/Scripts/python.exe -X utf8 _store_fix_note.py)",
"Bash(curl -s \"http://192.168.1.76:3100/loki/api/v1/label/level/values\")",
"mcp__knowledgebase__stats",
"mcp__knowledgebase__store_memory",
"PowerShell(Test-NetConnection -ComputerName Reporter -Port 5985 -WarningAction SilentlyContinue)"
] ]
} }
} }
+98
View File
@@ -5,6 +5,97 @@ from logging.handlers import TimedRotatingFileHandler
from indexer.config import LOG_LEVEL, LOG_DIR 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: def setup_logging() -> logging.Logger:
os.makedirs(LOG_DIR, exist_ok=True) os.makedirs(LOG_DIR, exist_ok=True)
@@ -31,4 +122,11 @@ def setup_logging() -> logging.Logger:
logging.root.addHandler(file_handler) logging.root.addHandler(file_handler)
logging.root.addHandler(console_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") return logging.getLogger("backup")
+22
View File
@@ -14,6 +14,23 @@ from indexer.events import batch_log_events
from indexer.backup import ensure_backed_up from indexer.backup import ensure_backed_up
from indexer.hasher import is_cloud_placeholder, hydrate_file from indexer.hasher import is_cloud_placeholder, hydrate_file
# Strop pro výpis seznamu změn do logu (ochrana proti zaplavení při hromadných
# importech). Nad tento počet se v dané kategorii vypíše jen prvních N + zbytek.
MAX_LIST_LOG = 2000
def _log_change_list(log, label: str, paths: list):
"""Vypíše seznam souborů dané kategorie (ADDED/MODIFIED/DELETED) do logu.
Jde přes root logger, takže to skončí i v centrálním loggingu (Loki)."""
n = len(paths)
if n == 0:
return
log.info(f"--- {label} files ({n}) ---")
for p in paths[:MAX_LIST_LOG]:
log.info(f"[{label}] {p}")
if n > MAX_LIST_LOG:
log.info(f"[{label}] ... and {n - MAX_LIST_LOG} more")
def main(): def main():
log = setup_logging() log = setup_logging()
@@ -170,6 +187,11 @@ def main():
if events: if events:
batch_log_events(cur, events) batch_log_events(cur, events)
# 5f) Explicitní seznam změn do logu (soubor + konzole + central logging)
_log_change_list(log, "ADDED", [nf["relative_path"] for nf in new_files])
_log_change_list(log, "MODIFIED", sorted(modified_paths))
_log_change_list(log, "DELETED", sorted(deleted_paths))
# ── 6. Backup ── # ── 6. Backup ──
if files_to_backup and BACKUP_PATH: if files_to_backup and BACKUP_PATH:
log.info(f"[6/7] Backing up {len(files_to_backup)} files...") log.info(f"[6/7] Backing up {len(files_to_backup)} files...")