"""Configuration du log fichier de la GUI V6 (E1). Sans ceci, la GUI frozen fenêtrée (sans console) perd ses logs de diagnostic. Le log est posé dans le même répertoire applicatif que la licence (``%LOCALAPPDATA%/Aivanov/Anonymisation``) pour faciliter sa récupération (E2/E3). """ from __future__ import annotations import logging import os from logging.handlers import RotatingFileHandler from pathlib import Path _CONFIGURED = False def _app_data_dir() -> Path: base = os.environ.get("LOCALAPPDATA") if base: root = Path(base) else: # Linux/dev root = Path.home() / ".local" / "share" return root / "Aivanov" / "Anonymisation" def log_file_path() -> Path: return _app_data_dir() / "logs" / "anonymisation.log" def setup_file_logging() -> Path: """Configure un handler fichier rotatif sur le logger racine. Idempotent.""" global _CONFIGURED path = log_file_path() if _CONFIGURED: return path path.parent.mkdir(parents=True, exist_ok=True) handler = RotatingFileHandler( str(path), maxBytes=2_000_000, backupCount=3, encoding="utf-8" ) handler.setFormatter( logging.Formatter("%(asctime)s %(levelname)s %(name)s: %(message)s") ) root = logging.getLogger() if root.level == logging.NOTSET: root.setLevel(logging.INFO) root.addHandler(handler) # Best-effort : si le cœur utilise loguru, on ajoute aussi un sink fichier. try: from loguru import logger as _loguru _loguru.add(str(path), rotation="2 MB", retention=3, encoding="utf-8") except Exception: pass _CONFIGURED = True return path def _reset_for_tests() -> None: """Réinitialise l'état pour l'isolation des tests (NE PAS appeler en prod).""" global _CONFIGURED root = logging.getLogger() for h in list(root.handlers): if isinstance(h, RotatingFileHandler): root.removeHandler(h) h.close() _CONFIGURED = False