1"""
2Logging configuration utilities.
3
4Implements :any:`/specs/spec_settings` §2.7, covering:
5
6* Log level configuration from environment
7* Colored output formatting
8
9"""
10
11import logging
12import os
13from functools import lru_cache
14from typing import Optional
15
16DEFAULT_LEVEL = "INFO"
17
18_COLOR_CODES = {
19 "DEBUG": "\033[36m", # Cyan
20 "INFO": "\033[32m", # Green
21 "WARNING": "\033[33m", # Yellow
22 "ERROR": "\033[31m", # Red
23 "CRITICAL": "\033[41m", # Red background
24}
25_RESET = "\033[0m"
26
27
38
39
[docs]
40@lru_cache(maxsize=None)
41def get_logger(name: Optional[str] = None) -> logging.Logger: # noqa: D401
42 """Return a configured logger.
43
44 The level is taken from – in dieser Priorität:
45 1. Environment variable ``LOG_LEVEL``
46 2. Otherwise falls back to :data:`DEFAULT_LEVEL`.
47 """
48
49 logger = logging.getLogger(name if name else "gitlab_overviewer")
50
51 if logger.handlers:
52 # Already configured – return early
53 return logger
54
55 level_str = os.getenv("LOG_LEVEL", DEFAULT_LEVEL).upper()
56 level = getattr(logging, level_str, logging.INFO)
57 logger.setLevel(level)
58
59 handler = logging.StreamHandler()
60 fmt = "%(asctime)s | %(levelname)-8s | %(name)s: %(message)s"
61 formatter = _ColorFormatter(fmt, datefmt="%H:%M:%S")
62 handler.setFormatter(formatter)
63 logger.addHandler(handler)
64
65 # Avoid duplicate logs if root logger is configured later
66 logger.propagate = False
67
68 return logger