Skip to content

Ultimate Guide to Python Logging Best Practices with Examples

Logdy - a real-time web-based logs browser

Logdy is a web-based logs viewer and parser that simplifies the process of monitoring and analyzing log files. It provides a user-friendly web interface for formatting, filtering, and visualizing logs from various sources such as local development environments, PM2, Kubernetes, Docker, Apache, and more. Logdy offers features like live log tailing, customizable column selection, faceted filtering, traces visualization, and easy integration with different logging systems. Read more

Introduction to Python Logging

Logging is a critical component of software development, serving as a way to record information about the operations of a program. This is especially crucial in Python applications, where understanding the flow of execution and the state of the system can help developers diagnose issues and optimize performance. For instance, using Python's built-in logging module, developers can easily track events by inserting statements like logging.info('Starting the application') or logging.error('Exception occurred', exc_info=True) at strategic points in their code. This not only aids in debugging during development but also provides valuable insights in production, helping track down errors and understand user behavior. Effective logging practices enable developers to see not just what goes wrong, but also provide a context of what was happening around the time of an issue, making it easier to resolve problems quickly and efficiently.

Best Practices for Python Logging

Adopting best practices for logging in Python is essential for maintaining scalable, maintainable, and debuggable code. Firstly, always use the built-in Python logging module instead of the print statement. This allows you to control the severity levels of messages and manage outputs more flexibly. For example, configure logging at the start of your script with logging.basicConfig(level=logging.INFO) to capture all informational messages and above. It's also crucial to include contextual information in your logs to make them more informative. You can do this by using formatted strings, like logging.debug(f'Variable x has value {x}'). Furthermore, avoid hardcoding severity levels; instead, use environment variables or configuration files to set them, allowing different settings for development and production environments. This approach enhances security and makes your logging more adaptable. Lastly, use log rotation to prevent log files from consuming too much disk space, either by configuring logging.handlers.RotatingFileHandler or using external tools like Logrotate. Implementing these practices will significantly improve the way you track and analyze operations in your Python applications.

Sign up for updates about latest features in Logdy

It's a double opt-in, you'll receive a link to confirm subscription. We will only send you Logdy product updates

Real-world Examples

To illustrate the implementation of logging best practices in Python, consider a scenario where a Python application needs to handle user login and data retrieval operations. Here’s how you can set up logging:

  1. Basic Configuration: Start by setting up the basic configuration for logging. This includes setting the log level and the log file name.
python
import logging
logging.basicConfig(filename='app.log', level=logging.INFO)
  1. Logging Exceptions: Ensure that you log exceptions to help with debugging. Use the exc_info parameter to log stack traces.
python
try:
    # Code that might throw an exception
    result = 10 / 0
except Exception as e:
    logging.error('Failed to divide by zero', exc_info=True)
  1. Contextual Information: Add contextual information to your logs to provide more insights. This can be done using formatted strings.
python
user_id = 1234
logging.info(f'User {user_id} logged in successfully.')
  1. Dynamic Log Levels: Adjust log levels dynamically based on the environment. This can be controlled using environment variables.
python
import os
log_level = os.getenv('LOG_LEVEL', 'INFO')
logging.basicConfig(level=getattr(logging, log_level.upper()))
  1. Log Rotation: Implement log rotation to manage log file sizes and prevent them from growing indefinitely.
python
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler('app.log', maxBytes=2000, backupCount=5)
logging.getLogger('').addHandler(handler)

These examples demonstrate how to apply best practices in logging within a Python application effectively. Each snippet is tailored to enhance the logging approach, making the application easier to maintain and debug.

Structured Logging Implementation

Structured logging is a method of recording logs in a consistent, predetermined format, typically JSON, which makes it easier to analyze and query the logs. Unlike traditional logging, which involves plain text messages, structured logging captures each element of the log as a distinct field. This approach is particularly useful in Python applications for improving log analysis and management. Here’s how you can implement structured logging in Python using the json module and Python’s logging library:

  1. Configure Structured Logging: Set up the logging configuration to output logs in JSON format.
python
import logging
import json
from pythonjsonlogger import jsonlogger

logger = logging.getLogger()
logHandler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter()
logHandler.setFormatter(formatter)
logger.addHandler(logHandler)
logger.setLevel(logging.INFO)
  1. Log Messages as JSON: Use the logger to create log entries that are structured as JSON objects.
python
logger.info({'user_id': '12345', 'event': 'login_attempt', 'status': 'successful'})
  1. Customize JSON Output: Modify the JSON output by adding custom fields or formatting based on the context of the event.
python
class CustomJsonFormatter(jsonlogger.JsonFormatter):
    def add_fields(self, log_record, record, message_dict):
        super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)
        log_record['custom_field'] = 'custom_data'

formatter = CustomJsonFormatter()
logHandler.setFormatter(formatter)

These steps provide a foundational guide for implementing structured logging in Python applications, ensuring logs are not only informative but also easier to parse and analyze. This structured approach enhances both the clarity and utility of log data, facilitating better debugging and monitoring of application behavior.

Error Handling Best Practices

Effective error handling is crucial for robust Python applications, and logging plays a pivotal role in capturing and diagnosing errors. Best practices suggest using Python's built-in logging module to log exceptions and errors comprehensively. For instance, always log the stack trace along with the error message, which can be done using logging.exception() within an exception block. Here’s an example:

python
try:
    # Attempt to open a non-existent file
    with open('non_existent_file.txt', 'r') as file:
        data = file.read()
except FileNotFoundError as e:
    logging.exception('File not found error occurred')

This automatically logs the stack trace, making it easier to trace the error's origin. Additionally, categorizing errors can aid in quicker resolution; use different log levels to differentiate between critical errors and warnings. For example, use logging.critical() for system outages and logging.warning() for recoverable issues. Furthermore, enrich your logs with contextual information to provide insights into the state of the application at the time of the error. This can be achieved by logging relevant data:

python
user_id = get_user_id()
try:
    process_transaction(user_id)
except TransactionFailed as e:
    logging.error(f'Transaction failed for user {user_id}', exc_info=True)

These practices ensure that logs are not only informative but also actionable, significantly aiding in the debugging process and improving application reliability.

How Logdy can help?

Last updated: