Exploring Python Logging Libraries: A Comprehensive Guide

Bruno Peixoto
3 min readDec 13, 2023

--

Logging is a crucial aspect of software development, aiding developers in debugging, monitoring, and understanding the behaviour of their applications. In the Python ecosystem, several logging libraries cater to different needs. In this guide, we’ll explore and compare four popular logging libraries: logging, loguru, structlog, and eliot.

Introduction

Logging is an essential part of any software development lifecycle. It allows developers to record information about the execution of their code, helping them understand and diagnose issues effectively. Python, a versatile language, offers multiple logging libraries, each with its strengths and use cases.

The Logging Libraries

1. logging Module

The built-in logging module is a fundamental part of the Python standard library. It provides a versatile and extensible logging framework that supports various log levels, custom formatting, and multiple handlers.

import logging

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logging.info('This is an info message.')

2. Loguru

Loguru is a third-party logging library known for its simplicity and powerful features. It simplifies logging configuration and offers a clear and expressive syntax.

from loguru import logger

logger.info('This is an info message.')

3. Structlog

Structlog is designed for structured logging, making it easy to log contextual information. It's well-suited for scenarios where structured logs are essential, such as when working with JSON.

import structlog

structlog.configure(logger_factory=structlog.PrintLoggerFactory())
structlog.get_logger().info('This is an info message.')

4. Eliot

Eliot is another structured logging library with a focus on simplicity and clarity. It provides a clear and concise API for emitting structured log messages.

from eliot import to_file, log_message

to_file(open("eliot_log.log", "w"))
log_message(message_type="info", message="This is an info message.")

Usage and Comparison

This section will demonstrate how to use each logging library to log messages at different levels (debug, info, warning, error, and critical). We’ll compare each library's syntax, features, and ease of use.

Configuration

Logging configuration plays a crucial role in any logging framework. We’ll explore how to configure each library, including setting log levels, formatting, and adding handlers.

A More Extensive Example

To further illustrate the capabilities of each logging library, let’s consider a more extensive example where we simulate a simple application with different modules, each requiring specific logging configurations.

1. logging Module

In the logging module, we'll set up loggers for two modules: module1 and module2. Each module will have its own log file, and we'll demonstrate the use of different log levels.

import logginglogging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')# Module 1
module1_logger = logging.getLogger('module1')
module1_logger.setLevel(logging.INFO)
module1_handler = logging.FileHandler('logs/module1.log')
module1_logger.addHandler(module1_handler)
# Module 2
module2_logger = logging.getLogger('module2')
module2_handler = logging.FileHandler('logs/module2.log')
module2_logger.addHandler(module2_handler)
# Log messages
module1_logger.info('Module 1 info message.')
module2_logger.warning('Module 2 warning message.')

2. Loguru

In the Loguru example, we'll utilize its simplified syntax for handling multiple loggers and demonstrate log rotation.

from loguru import logger  # Module 1 
logger_module1 = logger.bind(logger='module1') logger_module1.add('logs/module1.log', rotation='500 MB', level='INFO')
# Module 2
logger_module2 = logger.bind(logger='module2') logger_module2.add('logs/module2.log', rotation='500 MB', level='WARNING')
# Log messages logger_module1.info('Module 1 info message.')
logger_module2.warning('Module 2 warning message.')
# Log messages
logger.info('Module 1 info message.')
logger.warning('Module 2 warning message.')

3. Structlog

For Structlog, we'll showcase its structured logging by including contextual information in the log messages.

import structlog# Module 1
module1_logger = structlog.get_logger(module='module1')
# Module 2
module2_logger = structlog.get_logger(module='module2')
# Log messages with context
module1_logger.info('Info message from Module 1', module='module1', user='john_doe')
module2_logger.warning('Warning message from Module 2', module='module2', user='jane_doe')

4. Eliot

In the Eliot example, we'll use tasks to categorize log messages for better organization and clarity.

from eliot import to_file, start_actionto_file(open('logs/eliot.log', 'w'))# Module 1
with start_action(action_type='module1:info'):
print('Module 1 info message.')
# Module 2
with start_action(action_type='module2:warning'):
print('Module 2 warning message.')

This more extensive example demonstrates how each logging library handles multiple modules, log levels, and specific configurations. Adjust the examples according to your project’s needs and preferences.

Conclusion

Choosing the right logging library depends on your specific needs and preferences. We’ve explored four popular Python logging libraries, each with its strengths. Whether you prioritize simplicity, structured logging, or extensibility, there’s a logging library to suit your requirements.

--

--

Bruno Peixoto

A person. Also engineer by formation, mathematician and book reader as hobby.