Skip to content

supaernova.logging

[docs] module supaernova.logging

 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
# Copyright 2025 Patrick Armstrong

import sys
from typing import TYPE_CHECKING
import logging

import coloredlogs

if TYPE_CHECKING:
    from pathlib import Path


def setup_logging(
    module: str,
    *,  # Force keyword-only arguments
    log_path: "Path | None" = None,
    verbose: bool = False,
) -> logging.Logger:
    logger = logging.getLogger(module)
    logger.setLevel(logging.DEBUG)
    logger.propagate = False

    # Clear existing handlers
    while logger.handlers:
        logger.handlers.pop()

    # --- Formatting ---
    debug_fmt = "[%(levelname)8s] %(filename)10s | %(message)s"
    info_fmt = "%(message)s"
    level_styles = coloredlogs.parse_encoded_styles(
        "debug=8;info=green;warning=yellow;error=red,bold;critical=red,inverse"
    )

    # --- Stream Handler ---
    # Set level and formatting
    stream_level = logging.DEBUG if verbose else logging.INFO
    stream_fmt = coloredlogs.ColoredFormatter(
        debug_fmt if verbose else info_fmt, level_styles=level_styles
    )

    # Initialise file handler
    stream_handler = logging.StreamHandler(stream=sys.stdout)
    stream_handler.setLevel(stream_level)
    stream_handler.setFormatter(stream_fmt)
    logger.addHandler(stream_handler)

    # --- File Handler ---
    if log_path is not None:
        # Determine output log file
        if log_path.is_dir():
            log_path /= f"{module}.log"

        # Ensure directory exists
        log_path.parent.mkdir(parents=True, exist_ok=True)

        # Set level and formatting
        file_level = logging.DEBUG
        file_fmt = logging.Formatter(debug_fmt)

        # Initialise file handler
        file_handler = logging.FileHandler(log_path, mode="w")
        file_handler.setLevel(file_level)
        file_handler.setFormatter(file_fmt)
        logger.addHandler(file_handler)

    return logger