| """Shared logging setup. One formatter, one handler, idempotent configuration.""" | |
| from __future__ import annotations | |
| import logging | |
| import sys | |
| from typing import Final | |
| _LOG_FORMAT: Final[str] = "%(asctime)s | %(levelname)-7s | %(name)s | %(message)s" | |
| _DATE_FORMAT: Final[str] = "%H:%M:%S" | |
| _CONFIGURED: dict[str, bool] = {"done": False} | |
| def _configure_root(level: int) -> None: | |
| """Install a single stdout handler on the root logger exactly once.""" | |
| if _CONFIGURED["done"]: | |
| return | |
| root = logging.getLogger() | |
| root.setLevel(level) | |
| # Remove handlers installed by notebook environments (Colab / Jupyter inject one). | |
| for handler in list(root.handlers): | |
| root.removeHandler(handler) | |
| handler = logging.StreamHandler(sys.stdout) | |
| handler.setFormatter(logging.Formatter(_LOG_FORMAT, datefmt=_DATE_FORMAT)) | |
| root.addHandler(handler) | |
| _CONFIGURED["done"] = True | |
| def get_logger(name: str, level: int = logging.INFO) -> logging.Logger: | |
| """Return a module-scoped logger. Safe to call repeatedly from anywhere.""" | |
| _configure_root(level) | |
| return logging.getLogger(name) | |