ProgrammingWorld

Python Logging: How to Track and Debug Your Code Efficiently

13 January 2025

Photo by Vladyslava Andriyenko on Unsplash

Debugging is an essential part of software development, and efficient tracking of code execution can save developers hours of frustration. Python’s built-in logging module provides a robust way to handle these tasks, offering functionality that ranges from basic logging to advanced tracking systems.

In this comprehensive guide, we will explore Python’s logging module in depth, understand its features, and learn how to implement it effectively to track and debug your code.

What is Logging in Python?

Logging is a way of capturing information about the flow and behavior of your program as it runs. Instead of relying solely on print statements, the logging module allows you to:

  • Track events in your application.

  • Record errors and warnings.

  • Create detailed reports for debugging.

  • Control the level and format of information output.

The flexibility and customization of the logging module make it an indispensable tool for Python developers.

Why Use Python Logging Instead of Print Statements?

While print statements can be helpful for simple debugging, they lack the sophistication needed for larger projects. Here’s why you should prefer logging:

  1. Levels of Severity: The logging module categorizes logs into levels like DEBUG, INFO, WARNING, ERROR, and CRITICAL.

  2. Configurable Output: You can control the output format and destination, such as the console, files, or external systems.

  3. Performance: Logging can be enabled or disabled at runtime, reducing overhead in production.

  4. Thread Safety: The logging module is designed to handle multithreaded applications efficiently.

Getting Started with Python Logging

Basic Logging Example

Here’s a quick example to get you started:

import logging

# Configure logging
logging.basicConfig(level=logging.INFO)

# Log messages
logging.debug("This is a debug message")
logging.info("This is an info message")
logging.warning("This is a warning message")
logging.error("This is an error message")
logging.critical("This is a critical message")

Output:

This is an info message
This is a warning message
This is an error message
This is a critical message

Notice that the DEBUG message is not displayed because the default logging level is set to INFO. To see all messages, you can change the level to DEBUG.

Understanding Logging Levels

The logging module provides five standard levels of severity:

  1. DEBUG : Detailed information, for diagnosing issues.

  2. INFO : Confirmation that things are working as expected.

  3. WARNING : An indication that something unexpected happened.

  4. ERROR : A more serious problem preventing functionality.

  5. CRITICAL : A critical error causing program termination.

Setting the Logging Level

You can set the logging level during configuration:

logging.basicConfig(level=logging.DEBUG)

This ensures that all messages of the specified level and higher are logged.

Customizing Log Messages

The logging module allows you to format log messages for better readability.

Formatting Logs

Use the format parameter in basicConfig to customize log messages:

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s"
)

logging.info("This is an info message")

Output:

2025-01-13 14:30:25,123 - INFO - This is an info message

Common Format Specifiers

  • %(asctime)s: Timestamp of the log entry.

  • %(levelname)s: Logging level (e.g., INFO, WARNING).

  • %(message)s: The log message.

  • %(name)s: The name of the logger.

  • %(filename)s: The name of the file where the log was called.

Logging to a File

To store logs for future reference, you can log messages to a file instead of the console.

Example: Writing Logs to a File

logging.basicConfig(
    filename="app.log",
    level=logging.DEBUG,
    format="%(asctime)s - %(levelname)s - %(message)s"
)

logging.info("This message will be written to a file")

Output (in app.log):

2025-01-13 14:35:50,456 - INFO - This message will be written to a file

This is useful for applications running in production, as you can review the logs later to debug issues.

Using Loggers, Handlers, and Formatters

For advanced logging requirements, you can use the logging module’s hierarchical system involving loggers, handlers, and formatters.

1. Loggers

A Logger is the entry point for logging. It creates log messages and passes them to handlers.

2. Handlers

Handlers define where the log messages go (e.g., console, file, or external system).

3. Formatters

Formatters specify the layout of log messages.

Example: Advanced Configuration

import logging

# Create logger
logger = logging.getLogger("my_logger")
logger.setLevel(logging.DEBUG)

# Create file handler
file_handler = logging.FileHandler("app.log")
file_handler.setLevel(logging.ERROR)

# Create console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)

# Create formatter
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

# Add formatter to handlers
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

# Add handlers to logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)

# Log messages
logger.debug("Debug message")
logger.error("Error message")

Output (Console):

2025-01-13 14:45:00,789 - my_logger - DEBUG - Debug message
2025-01-13 14:45:00,790 - my_logger - ERROR - Error message

Output (File):

2025-01-13 14:45:00,790 - my_logger - ERROR - Error message

Logging Exceptions

The logging module allows you to log exceptions using the exc_info parameter.

Example: Logging Exceptions

try:
    1 / 0
except ZeroDivisionError:
    logging.error("An error occurred", exc_info=True)

Output:

ERROR:root:An error occurred
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

Rotating Log Files

For long-running applications, you might want to limit the size of log files. The RotatingFileHandler helps manage log files by rotating them when they reach a certain size.

Example: Rotating Log Files

from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler("app.log", maxBytes=2000, backupCount=5)
logging.basicConfig(handlers=[handler], level=logging.INFO)

for i in range(100):
    logging.info(f"Log message {i}")

This will create up to 5 backup log files (app.log.1, app.log.2, etc.), each with a maximum size of 2KB.

Best Practices for Python Logging

  1. Set Appropriate Log Levels: Use DEBUG for development and INFO or WARNING for production.

  2. Avoid Hardcoding Configurations: Use configuration files for log settings.

  3. Log Only What’s Necessary: Avoid logging sensitive data.

  4. Use Rotating Logs: Prevent disk space issues by using rotating log handlers.

  5. Document Logs: Ensure logs are readable and provide context for debugging.

Conclusion

The logging module in Python is a powerful tool that enables developers to track, debug, and manage their applications effectively. By using its advanced features like log levels, handlers, and formatters, you can create a robust logging system tailored to your application’s needs.

Whether you’re building a small script or a large-scale application, mastering Python’s logging capabilities will make your development process smoother and more efficient.

Happy coding! 🚀

Powered by wisp

Loading...
Related Posts
Python Decorators Explained with Simple Examples

Python Decorators Explained with Simple Examples

Python decorators are a powerful feature for enhancing or modifying the behavior of functions or methods. This blog explains decorators with simple examples, making it easy to understand how they work. Learn how to use them for cleaner, more maintainable code, and explore real-world use cases.

Read
Python Functions: Tips for Writing Clean and Reusable Code

Python Functions: Tips for Writing Clean and Reusable Code

Python functions are essential for writing clean, reusable, and maintainable code. This blog shares practical tips on how to write efficient functions, including proper naming conventions, avoiding redundancy, and leveraging Python's flexibility with default parameters, *args, and **kwargs. Perfect for developers aiming to improve their coding practices.

Read
Error Handling in Python: A Beginner’s Guide to Try-Except Blocks

Error Handling in Python: A Beginner’s Guide to Try-Except Blocks

Error handling is a critical skill for writing robust Python programs. This blog introduces beginners to Python's try-except blocks, explaining how to catch and handle exceptions effectively. Learn the basics of error handling, prevent program crashes, and write user-friendly code with practical examples.

Read
© ProgrammingWorld 2025
PrivacyTerms