File size: 2,137 Bytes
e391a84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""
shared/logger.py
────────────────
Logging factory with a consistent format for all modules.

Usage:
    from src.shared.logger import get_logger
    logger = get_logger(__name__)
    logger.info("Signal ingested", extra={"device_id": "sensor-001"})
"""
from __future__ import annotations

import logging
import sys
from typing import Optional

# Module-level cache so duplicate calls reuse the same logger object
_loggers: dict[str, logging.Logger] = {}


def get_logger(
    name: str,
    level: Optional[str] = None,
) -> logging.Logger:
    """
    Return a configured logger for *name*.

    The first call for a given name creates and caches the logger;
    subsequent calls return the cached instance.

    Args:
        name:  Logger name, typically ``__name__`` of the calling module.
        level: Override log level (e.g. ``"DEBUG"``). If *None*, the level
               is read from the ``LOG_LEVEL`` environment variable via
               :func:`~src.shared.config.get_settings`, defaulting to INFO.

    Returns:
        Configured :class:`logging.Logger` instance.
    """
    if name in _loggers:
        return _loggers[name]

    # Resolve level
    if level is None:
        try:
            from src.shared.config import get_settings  # lazy import to avoid cycles

            level = get_settings().log_level
        except Exception:
            level = "INFO"

    numeric_level = getattr(logging, level.upper(), logging.INFO)

    logger = logging.getLogger(name)
    logger.setLevel(numeric_level)

    # Avoid adding duplicate handlers if the logger already has them
    if not logger.handlers:
        handler = logging.StreamHandler(sys.stdout)
        handler.setLevel(numeric_level)

        formatter = logging.Formatter(
            fmt="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
        )
        handler.setFormatter(formatter)
        logger.addHandler(handler)

    # Don't propagate to the root logger to avoid duplicate output
    logger.propagate = False

    _loggers[name] = logger
    return logger