Source code for mrv.utils.log

"""
mrv.utils.log -- Logging setup driven by config.yaml.

Call ``setup(cfg)`` once at application start to configure console + optional
file logging.  All mrv modules use ``logging.getLogger(__name__)`` as usual.
"""

from __future__ import annotations

import logging
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Optional

__all__ = ["setup"]


[docs] def setup(cfg: Optional[Dict[str, Any]] = None) -> None: """ Configure Python logging from the ``logging`` section of mrv config. When ``logging.dir`` is set, a timestamped log file is created automatically, e.g. ``logs/mrv_20260319_143012.log``. Parameters ---------- cfg : dict, optional Full mrv config dict (as returned by ``mrv.utils.config.load()``). If *None*, sensible defaults are applied. """ log_cfg = (cfg or {}).get("logging", {}) level_name = str(log_cfg.get("level", "INFO")).upper() level = getattr(logging, level_name, logging.INFO) fmt = log_cfg.get("format", "%(asctime)s %(levelname)s [%(name)s] %(message)s") log_dir = log_cfg.get("log_dir") quiet = log_cfg.get("quiet", []) root = logging.getLogger() # Avoid duplicate handlers on repeated calls if not root.handlers: handler = logging.StreamHandler(sys.stdout) handler.setLevel(level) handler.setFormatter(logging.Formatter(fmt)) root.addHandler(handler) root.setLevel(level) # File handler: auto-generate timestamped filename under log_dir if log_dir: log_path = Path(log_dir) log_path.mkdir(parents=True, exist_ok=True) ts = datetime.now().strftime("%Y%m%d_%H%M%S") _add_file_handler(log_path / f"mrv_{ts}.log", level, fmt) # Silence noisy loggers for name in quiet: logging.getLogger(name).setLevel(logging.WARNING) logging.captureWarnings(True)
def _add_file_handler(path: Path, level: int, fmt: str) -> None: """Add a file handler if one for this path does not already exist.""" path = Path(path) path.parent.mkdir(parents=True, exist_ok=True) root = logging.getLogger() existing = set() for h in root.handlers: if isinstance(h, logging.FileHandler): try: existing.add(Path(h.baseFilename).resolve()) except Exception: continue if path.resolve() not in existing: fh = logging.FileHandler(path, encoding="utf-8") fh.setLevel(level) fh.setFormatter(logging.Formatter(fmt)) root.addHandler(fh) if root.level > level: root.setLevel(level)