The Boilerplate for Logging in Python

Created on Mar 2, 2022

Finding bugs is a common problem in any programming project. To make it easier to find bugs, you probably want to write some print statements to help you debug.

Is it helpful? yes. Is it the right way to track events in your code, especially in a big project? no.

Python has a built-in logging module that you can use to log messages. Logging not only helps you debug the issues in your code. It also helps you understand the flow of your code especially when you ship to production.

It is a very useful tool to identify how your code is behaving whether it is working as expected or not. If not, it can show you different hierarchies of how severe the issue is whether it is an error, a warning, or a debug mode.

Without having logging, it’s difficult to keep your code maintainable for a long time. Especially when this code is mature.

In this tutorial, I’ll show you a boilerplate for logging that you can use in your next project. Instead of looking at the documentation every time.

Division Example

Let’s take this division example especially when we divide by zero:

def divide(dividend, divisor):
    try:
        return dividend / divisor
    except ZeroDivisionError:
        return "Zero Division error."

print(divide(6, 0))

In this case, when we divided 6 by 0 we returned a message string. This message shows that a zero division error during the ZeroDivisionError exception occurred.

What’s the problem with that? The issue here is that we don’t know when that happened and how severe the issue is. Is it a warning? an error? or just a piece of information you’re printing to the console?

The built-in Python’s logging module helps you better log your code with its features. Let’s see how we can use it in this context:

import logging

# Define a logger instance
logger = logging.getLogger(__name__)
# Define a stream handler for the console output
handler = logging.StreamHandler()

# Customize the formatter on the console
formatter = logging.Formatter(
    "%(asctime)s -  %(name)s: %(levelname)s - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
    )
# Add the formatter to the handler
handler.setFormatter(formatter)

# Add the stream handler to the logger that we will use
logger.addHandler(handler)
# Set the level of logging to be INFO instead of the default WARNING
logger.setLevel(logging.INFO)

def divide(dividend, divisor):
    try:
        logger.info(f"Dividing {dividend} by {divisor}")
        return dividend / divisor
    except ZeroDivisionError:
        logger.info("Zero Division error.")

print(divide(6, 0))

which would return helpful information like this:

2022-02-23 13:24:41 -  __main__: INFO - Dividing 6 by 0
2022-02-23 13:24:41 -  __main__: INFO - Zero Division error.

Wrap Up

In this boilerplate, you’ve seen how to log messages to the console. You’ve formatted the logs to start with a date and time followed by the name of the module, level of logging, and the log message itself.