Skip to content

bs_logging module

Utilities for logging:

  • init_logger initializes and returns a customized logger
  • log_execution ia a decorator to log entry into and ext from a function.

init_logger(logger_name, log_level_for_console='info', log_level_for_file='debug', save_dir=None)

Initialize a logger

Parameters:

Name Type Description Default
logger_name str

name for the logger

required
log_level_for_console str

minimum level of messages logged to the console logging

'info'
log_level_for_file str
'debug'
save_dir str | None
None

Returns:

Type Description
Logger

the logger

Examples:

>>> logger_dir = "logs"
>>> logger_name = "check_log"
>>> logger = init_logger(logger_name, save_dir=logger_dir)

This will create two logs:

  • one printed to console where we run the code (the StreamHandler),
  • and one that will be saved to file save_dir/logger_name.txt (the FileHandler).

'logger.propagate = False' makes sure that the logs sent to file will not be printed to console.

We use the Formatter class to define the format of the logs. Here:

  • The time of the log in a human-readable format, asctime
  • levelname is the level of the log, one out of INFO, DEBUG, WARNING, ERROR, CRITICAL.
  • The name of the file, filename, from which the log was generated, and the line number, lineno.
  • Lastly, the message itself — message.

The default has only INFO logs and above (i.e., also WARNING, ERROR and CRITICAL) displayed in the console; the file will also include DEBUG logs.

Source code in bs_python_utils/bs_logging.py
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
75
76
def init_logger(
    logger_name: str,
    log_level_for_console: str = "info",
    log_level_for_file: str = "debug",
    save_dir: str | None = None,
) -> logging.Logger:
    """
    Initialize a logger

    Args:
        logger_name: name for the logger
        log_level_for_console: minimum level of messages logged to the console logging
        log_level_for_file:
        save_dir:

    Returns:
        the logger

    Examples:
        >>> logger_dir = "logs"
        >>> logger_name = "check_log"
        >>> logger = init_logger(logger_name, save_dir=logger_dir)

        This will create two logs:

        * one  printed to console where we run the code (the `StreamHandler`),
        * and one that will be saved to file `save_dir/logger_name.txt` (the `FileHandler`).

        `'logger.propagate = False'`  makes sure that the logs sent to file will not be printed to console.

        We use the `Formatter` class to define the format of the logs.
        Here:

        * The time of the log in a human-readable format, `asctime`
        * `levelname` is the level of the log, one out of `INFO, DEBUG, WARNING, ERROR, CRITICAL`.
        * The name of the file, `filename`, from which the log was generated,
        and the line number, `lineno`.
        * Lastly,  the message itself — `message`.

        The default has only `INFO` logs and above (i.e., also `WARNING, ERROR` and `CRITICAL`)
        displayed in the console; the file will also include `DEBUG` logs.
    """
    logger = logging.getLogger()
    logger.setLevel(level=logging.DEBUG)
    logger.propagate = False

    formatter = logging.Formatter(
        "%(asctime)s [%(levelname)s] %(filename)s %(lineno)d - %(message)s",
        "%Y-%m-%d %H:%M:%S",
    )

    ch = logging.StreamHandler()
    ch.setLevel(log_level_for_console.upper())
    ch.setFormatter(formatter)
    logger.addHandler(ch)

    if save_dir is not None:
        Path(save_dir).mkdir(exist_ok=True, parents=True)
        fh = logging.FileHandler(save_dir + f"/{logger_name}.txt")
        fh.setLevel(log_level_for_file.upper())
        fh.setFormatter(formatter)
        logger.addHandler(fh)

    return logger

log_execution(func)

Decorator to log the execution of a function. Only records entry to and exit from the function, to the console.

Source code in bs_python_utils/bs_logging.py
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def log_execution(func: Callable) -> Callable:
    """Decorator to log the execution of a function.
    Only records entry to and exit from the function, to the console.
    """
    loglevel = logging.info

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        loglevel(f"Executing {func.__name__}")
        result = func(*args, **kwargs)
        loglevel(f"Finished executing {func.__name__}")
        return result

    return wrapper