from __future__ import annotations import logging import os import sys from logging.handlers import RotatingFileHandler from pathlib import Path from typing import Optional, Union def create_logger( name: str = "factuges-sync", *, level: int = logging.INFO, log_path: Optional[Union[str, Path]] = None, max_bytes: int = 5_000_000, # rotación opcional backup_count: int = 3, ) -> logging.Logger: """ Crea un logger consistente para FactuGES Sync. Reglas: - SIEMPRE envia logs a stdout (Docker-friendly). - SOLO en producción escribe también a fichero si `log_path` está definido. - `log_path` puede ser `str` o `Path`. - Evita duplicar handlers. """ logger = logging.getLogger(name) logger.setLevel(level) # Si ya está configurado, no duplicamos handlers if logger.handlers: return logger formatter = logging.Formatter( "%(asctime)s - %(levelname)s - %(message)s" ) # ------------------------------ # 1) Handler de consola (siempre) # ------------------------------ h_console = logging.StreamHandler(sys.stdout) h_console.setFormatter(formatter) logger.addHandler(h_console) # ------------------------------ # 2) Handler de fichero (solo prod) # ------------------------------ is_production = os.getenv("ENV") == "production" if log_path and is_production: p = Path(log_path) # Aseguramos directorios p.parent.mkdir(parents=True, exist_ok=True) # Puedes usar FileHandler simple, pero Rotating es más seguro. h_file = RotatingFileHandler( filename=str(p), maxBytes=max_bytes, backupCount=backup_count, encoding="utf-8", ) h_file.setFormatter(formatter) logger.addHandler(h_file) # Verificación explícita try: test_msg = f"Log file active at: {p}" h_file.acquire() h_file.stream.write(f"{test_msg}\n") h_file.flush() h_file.release() logger.info(test_msg) except Exception as e: logger.error(f"ERROR: cannot write to log file {p}: {e}") raise return logger # logger "global" ya creado logger = create_logger()