"""Logging helpers for the reactor simulation package.""" from __future__ import annotations import logging from typing import Optional def configure_logging(level: int | str = "INFO", logfile: Optional[str] = None) -> logging.Logger: """Configure a package-scoped logger emitting to stdout and optional file.""" resolved_level = logging.getLevelName(level) if isinstance(level, str) else level logger = logging.getLogger("reactor_sim") logger.setLevel(resolved_level) if not logger.handlers: stream_handler = logging.StreamHandler() formatter = logging.Formatter( fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s", datefmt="%H:%M:%S" ) stream_handler.setFormatter(formatter) logger.addHandler(stream_handler) if logfile: file_handler = logging.FileHandler(logfile) file_handler.setFormatter(formatter) logger.addHandler(file_handler) else: for handler in logger.handlers: handler.setLevel(resolved_level) if logfile and not any(isinstance(handler, logging.FileHandler) for handler in logger.handlers): file_handler = logging.FileHandler(logfile) formatter = logging.Formatter( fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s", datefmt="%H:%M:%S" ) file_handler.setFormatter(formatter) logger.addHandler(file_handler) # Keep package loggers self-contained so host apps can opt-in to propagation. logger.propagate = False logging.getLogger().setLevel(resolved_level) return logger