Skip to content

Logging

Logging is a very important part of any application. It allows you to track the code execution and to debug the application. Python has a built-in logging module that allows you to log messages to the console, to a file, or to a remote server. In contrast to the print function, the logging module is more complete, allowing you to configure the log level, the log format, and the log destination.

Logging is based in handlers. A handler is an object that receives the log messages and decides what to do with them. The logging module has several built-in handlers, such as StreamHandler, FileHandler, RotatingFileHandler or TimedRotatingFileHandler. But you can create your own handler by inherit the Handler class. Notifiers is a 3pp library that provides with extra handlers with the ability to send notifications to different services.

Best practices

  • Set different log levels for different environments. For example, you may set DEBUG level in development and ERROR level in production.
  • Set a specific format for the log messages, including the timestamp or the log level. Using a standard format makes it easier to read the log messages. Use the extra parameter to pass the data to the log message.
  • Use pipelines | to separate the different parts of the log message. It can be useful to filter the log messages, or even to parse them.
  • To include variables in your log message, don't use format or f-string in the log call, instead use the %s, like logger.info('Variable: %s', value).
  • Use logging.exception to log an exception message and the stack trace.
  • Set the different logger instance you are going to use with logging.getLogger. This way you can configure the logger in one place and use it in different modules.

logging library

This is the built-in Python logging library. It is very flexible and allows you to configure the log level, the log format, and the log destination.

Each logger has a name, and the loggers are organized in a tree-like structure. The root logger is the top-level logger, and all other loggers are children of the root logger.

src.intermediate.logging.default_logging(level)

Method to show default logging configuration.

Parameters:

Name Type Description Default
level int

level to set in logging

required
Source code in src/intermediate/logging/logging.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def default_logging(level: int):
    """Method to show default logging configuration.

    Args:
        level (int): level to set in logging
    """
    if level not in logging._levelToName:
        raise IndexError("Invalid level to set logging.")

    logging.debug("DEBUG logging")
    logging.info("INFO logging")
    logging.warning("WARNING logging")
    logging.error("ERROR logging")
    logging.critical("CRITICAL logging")

src.intermediate.logging.custom_logging_format(format, datefmt)

Method to show logging configuration format.

Other arguments worthy to mention are: filename: using the path as log file with FileHandler. filemode: specifies the mode to open the log file.

Source code in src/intermediate/logging/logging.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def custom_logging_format(format: str, datefmt: str):
    """Method to show logging configuration format.

    Other arguments worthy to mention are:
    filename: using the path as log file with FileHandler.
    filemode: specifies the mode to open the log file.
    """
    logging.basicConfig(
        level=logging.INFO,
        format=format,
        datefmt=datefmt,
    )
    logger = logging.getLogger(__name__)

    logger.info("INFO logging formatted")

loguru library

Loguru is a third-party library that simplifies the logging configuration to the bare minimum, such as log level and log format. But you can also can configure much more easily, such as:

  • color customization.
  • log rotation, retention and compression.
  • custom log levels.
  • lazy evaluation of log messages.

src.intermediate.logging.default_loguru()

Method to show default loguru configuration.

Source code in src/intermediate/logging/logging.py
47
48
49
50
51
52
53
def default_loguru():
    """Method to show default loguru configuration."""
    logger_loguru.debug("DEBUG loguru")
    logger_loguru.info("INFO loguru")
    logger_loguru.warning("WARNING loguru")
    logger_loguru.error("ERROR loguru")
    logger_loguru.critical("CRITICAL loguru")

src.intermediate.logging.custom_loguru_format_and_level(format, level)

Method to show loguru custom configuration.

Add custom configuration to loguru, such as format and level. Sink is the first argument, representing how/where to log. It can be sys.*, or a log file path or a loggingHandler.

More information in the official loguru documentation: https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.add

Source code in src/intermediate/logging/logging.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
def custom_loguru_format_and_level(format: str, level: str):
    """Method to show loguru custom configuration.

    Add custom configuration to loguru, such as format and level.
    Sink is the first argument, representing how/where to log.
    It can be sys.*, or a log file path or a loggingHandler.

    More information in the official loguru documentation:
    https://loguru.readthedocs.io/en/stable/api/logger.html#loguru._logger.Logger.add
    """
    logger_loguru.add(sys.stdout, format=format, level=level)

    logger_loguru.debug("DEBUG loguru formatted")
    logger_loguru.info("INFO loguru formatted")
    logger_loguru.warning("WARNING loguru formatted")
    logger_loguru.error("ERROR loguru formatted")
    logger_loguru.critical("CRITICAL loguru formatted")

References