Coverage for src / monte_neo / utils / logger.py: 86%
29 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-28 16:27 +0200
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-28 16:27 +0200
1"""Logging utilities."""
3from __future__ import annotations
5import logging
6import sys
7from pathlib import Path
10def setup_logging(
11 level: str = "INFO",
12 log_file: str | Path | None = None,
13) -> None:
14 """Setup application logging.
16 Args:
17 level: Log level string.
18 log_file: Optional log file path.
19 """
20 log_level = getattr(logging, level.upper(), logging.INFO)
22 # Create formatter
23 formatter = logging.Formatter(
24 "%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
25 datefmt="%Y-%m-%d %H:%M:%S",
26 )
28 # Console handler
29 console_handler: logging.Handler
30 try:
31 from rich.logging import RichHandler
33 from monte_neo.utils.console import console as shared_console
35 console_handler = RichHandler(
36 console=shared_console,
37 rich_tracebacks=True,
38 show_time=True,
39 show_path=False,
40 )
41 except ImportError:
42 console_handler = logging.StreamHandler(sys.stdout)
43 console_handler.setFormatter(formatter)
45 console_handler.setLevel(log_level)
47 # Root logger
48 root_logger = logging.getLogger("monte_neo")
49 root_logger.setLevel(log_level)
51 # Remove existing handlers to avoid duplicates
52 for h in root_logger.handlers[:]:
53 root_logger.removeHandler(h)
55 root_logger.addHandler(console_handler)
57 # File handler if specified
58 if log_file:
59 file_handler = logging.FileHandler(log_file)
60 file_handler.setFormatter(formatter)
61 file_handler.setLevel(log_level)
62 root_logger.addHandler(file_handler)
65def get_logger(name: str) -> logging.Logger:
66 """Get a logger for a module.
68 Args:
69 name: Module name (typically __name__).
71 Returns:
72 Logger instance.
73 """
74 if name.startswith("monte_neo"):
75 return logging.getLogger(name)
76 return logging.getLogger(f"monte_neo.{name}")