Python Logging Formatting Techniques

Are you struggling with logging messages that look like they were written by a robot? In this tutorial, we’re going to explore some fun and exciting ways to format your log messages using Python’s built-in logging module.

First things first: what is logging in Python? It’s a powerful tool for tracking errors, debugging code, and keeping tabs on important events that happen during runtime. By default, it uses the ‘basicConfig()’ function to set up a logger object with some basic settings like log level (debug, info, warning, error, critical) and output format.

But let’s spice things up! Did you know that Python logging supports three different formatting styles: ‘%’, ‘{‘, and ‘$’? That’s right, You can choose the one that suits your fancy or mix them all together for a truly unique log message experience. Let’s dig into this at each style:

1) The classic ‘%’ format string: This is what you get by default when using Python logging. It uses placeholders like ‘%(levelname)s’, ‘%(asctime)s’, and ‘%(message)s’ to insert values into the log message. For example, this code snippet will print a debug-level log message with the current time and logger name:

# Import the logging module
import logging

# Create a logger object with the name of the current module
logger = logging.getLogger(__name__)

# Create a formatter object with a format string that includes placeholders for the log message's timestamp, log level, and message
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')

# Create a handler object to handle the log messages and set its formatter to the one we created above
handler = logging.StreamHandler()
handler.setFormatter(formatter)

# Add the handler to the logger object
logger.addHandler(handler)

# Use the debug method of the logger object to print a log message with the current time and the string "Hello, world!"
logger.debug("Hello, world!")

# The logger object will use the handler and formatter to print the log message in the specified format to the console.

2) The ‘{‘ format string: This style uses curly braces to insert values into the log message. It’s a bit more flexible than ‘%’, as you can use any valid Python expression inside the brackets. For example, this code snippet will print an info-level log message with the current time and logger name, but also includes the number of times that function has been called:

# Import the necessary modules
import logging
from functools import wraps

# Create a logger object with the name of the current module
logger = logging.getLogger(__name__)

# Create a formatter for the log messages
formatter = logging.Formatter('{asctime} [{levelname}] {message}{newline}', style='{')

# Create a handler to output the log messages to the console
handler = logging.StreamHandler()
handler.setFormatter(formatter)

# Add the handler to the logger
logger.addHandler(handler)

# Define a function to be logged
def my_function():
    # Use the logger to output an info-level log message with the current value of my_counter
    logger.info("Function called {} times.".format(my_counter))
    
    # Increment the counter for the next call
    global my_counter
    my_counter += 1

# Initialize the counter to zero
my_counter = 0

# Define a wrapper function to log the calls to my_function
@wraps(my_function)
def wrapper(*args, **kwargs):
    # Use the logger to output a debug-level log message before calling my_function
    logger.debug("Calling function...")
    
    # Call my_function and store the result
    result = my_function(*args, **kwargs)
    
    # Return the result
    return result

3) The ‘$’ format string: This style uses dollar signs to insert values into the log message. It’s similar to ‘{‘, but with a slightly different syntax. For example, this code snippet will print an error-level log message with the current time and logger name, but also includes the traceback information:

# Import necessary libraries
import logging # Importing the logging library to create log messages
from functools import wraps # Importing the wraps function from functools library to preserve function metadata
import traceback # Importing the traceback library to print exception information

# Create a logger object
logger = logging.getLogger(__name__) # Creating a logger object with the name of the current module
formatter = logging.Formatter('$asctime $levelname$message$newline', style='$') # Creating a formatter object with a custom format using dollar sign as the style
handler = logging.StreamHandler() # Creating a handler object to handle the log messages
handler.setFormatter(formatter) # Setting the formatter for the handler
logger.addHandler(handler) # Adding the handler to the logger object

# Define a function
def my_function():
    logger.debug("Calling function...") # Logging a debug message to indicate the function is being called
    
    try:
        # do something that might raise an exception
        1 / 0 # Attempting to divide by zero to trigger an exception
    except Exception as e:
        logger.error("An error occurred:", exc_info=True) # Logging an error message with the exception information
        traceback.print_exc() # Printing the traceback information to the console

# Wrap the function with a decorator
@wraps(my_function) # Using the wraps function to preserve the metadata of the original function
def wrapper(*args, **kwargs):
    logger.debug("Calling function...") # Logging a debug message to indicate the function is being called
    result = my_function(*args, **kwargs) # Calling the original function and storing the result
    return result # Returning the result of the original function

Three different ways to format your log messages using Python’s logging module. Whether you prefer the classic ‘%’, the flexible ‘{‘, or the powerful ‘$’, there’s a style that suits your needs.

SICORPS