fmatituy/selectospromanager
0
1import logging
2import os
3import sys
4from datetime import datetime
5
6class SafeStreamHandler(logging.StreamHandler):
7 """Handler que evita fallos si el stream (stdout/stderr) es destruido por el IDE."""
8 def emit(self, record):
9 try:
10 if not self.stream or self.stream.closed:
11 return
12 super().emit(record)
13 except (RuntimeError, ValueError, AttributeError):
14 # Ignorar si el stream ya no es válido durante el apagado
15 pass
16
17def setup_logger(name: str = "SelectosERP"):
18 # Directorio de logs (Relativo a /src/static)
19 base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
20 log_dir = os.path.join(base_dir, "static", "logs")
21 os.makedirs(log_dir, exist_ok=True)
22
23 # Archivo diario de logs
24 log_file = os.path.join(log_dir, f"{datetime.now().strftime('%Y-%m-%d')}.log")
25
26 # Formateador profesional
27 formatter = logging.Formatter(
28 '[%(asctime)s] %(levelname)s | %(name)s | %(message)s',
29 datefmt='%Y-%m-%d %H:%M:%S'
30 )
31
32 # Logger base
33 logger = logging.getLogger(name)
34 logger.setLevel(logging.INFO)
35 logger.propagate = False # Evitar duplicación con el logger raíz
36
37 if not logger.handlers:
38 # Handler: Archivo (con delay=True para no abrirlo hasta que sea necesario)
39 try:
40 fh = logging.FileHandler(log_file, encoding='utf-8', delay=True)
41 fh.setFormatter(formatter)
42 logger.addHandler(fh)
43 except Exception:
44 pass
45
46 # Handler: Consola Seguro
47 ch = SafeStreamHandler(sys.stderr)
48 ch.setFormatter(formatter)
49 logger.addHandler(ch)
50
51 return logger
52
53# Instancia global
54logger = setup_logger()
55
56# Silenciar basura de librerías
57logging.getLogger("uvicorn.error").setLevel(logging.DEBUG)
58logging.getLogger("nicegui").setLevel(logging.DEBUG)
59
60def shutdown_logging():
61 """Cierra todos los handlers de forma segura."""
62 for handler in logger.handlers[:]:
63 handler.close()
64 logger.removeHandler(handler)
65
66import atexit
67atexit.register(shutdown_logging)
68 