File size: 1,122 Bytes
188f0cf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | """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)
|