Logging Module: Professional Application Logging
TL;DR
The logging module provides flexible, configurable logging with different levels (DEBUG, INFO, WARNING, ERROR, CRITICAL), handlers for various outputs, and formatters for customized log messages.
Interesting!
Python’s logging module is thread-safe by default and supports hierarchical loggers - child loggers automatically inherit configuration from parent loggers, making complex application logging manageable.
Basic Logging
python code snippet start
import logging
# Configure basic logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Create logger
logger = logging.getLogger(__name__)
# Log messages at different levels
logger.debug("This is a debug message") # Won't show (level too low)
logger.info("Application started") # Will show
logger.warning("This is a warning") # Will show
logger.error("An error occurred") # Will show
logger.critical("Critical system failure") # Will show
python code snippet end
Professional Logging Setup
python code snippet start
import logging
import logging.handlers
from pathlib import Path
def setup_logging():
# Create logs directory
log_dir = Path("logs")
log_dir.mkdir(exist_ok=True)
# Create logger
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
# Create formatters
detailed_formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
)
simple_formatter = logging.Formatter('%(levelname)s - %(message)s')
# File handler (rotating)
file_handler = logging.handlers.RotatingFileHandler(
log_dir / "app.log",
maxBytes=10*1024*1024, # 10MB
backupCount=5
)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(detailed_formatter)
# Console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(simple_formatter)
# Add handlers to logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)
return logger
# Usage
logger = setup_logging()
logger.info("Logging system initialized")
python code snippet end
Structured Logging
python code snippet start
import logging
import json
from datetime import datetime
class JSONFormatter(logging.Formatter):
def format(self, record):
log_data = {
'timestamp': datetime.fromtimestamp(record.created).isoformat(),
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
'function': record.funcName,
'line': record.lineno
}
# Add extra fields if present
if hasattr(record, 'user_id'):
log_data['user_id'] = record.user_id
if hasattr(record, 'request_id'):
log_data['request_id'] = record.request_id
return json.dumps(log_data)
# Setup structured logging
logger = logging.getLogger("structured")
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)
# Log with extra context
logger.info("User login", extra={'user_id': 123, 'request_id': 'abc-123'})
python code snippet end
Exception Logging
python code snippet start
def risky_operation(x, y):
try:
result = x / y
logger.info(f"Division successful: {x}/{y} = {result}")
return result
except ZeroDivisionError:
logger.error(f"Division by zero attempted: {x}/{y}", exc_info=True)
raise
except Exception as e:
logger.critical(f"Unexpected error in division: {e}", exc_info=True)
raise
# Usage
try:
risky_operation(10, 0)
except Exception:
logger.exception("Operation failed") # Automatically includes traceback
python code snippet end
Configuration-Based Logging
python code snippet start
import logging.config
import yaml
# logging_config.yaml
config = """
version: 1
formatters:
default:
format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
detailed:
format: '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
handlers:
console:
class: logging.StreamHandler
level: INFO
formatter: default
stream: ext://sys.stdout
file:
class: logging.handlers.RotatingFileHandler
level: DEBUG
formatter: detailed
filename: logs/app.log
maxBytes: 10485760
backupCount: 5
loggers:
myapp:
level: DEBUG
handlers: [console, file]
propagate: no
root:
level: WARNING
handlers: [console]
"""
# Load configuration
config_dict = yaml.safe_load(config)
logging.config.dictConfig(config_dict)
# Use configured logger
logger = logging.getLogger("myapp")
logger.info("Configuration-based logging active")
python code snippet end
The logging module provides enterprise-grade logging capabilities essential for monitoring, debugging, and maintaining production applications.
Logging works hand-in-hand with proper exception handling to create robust, maintainable applications that provide clear feedback when things go wrong.
Reference: Python Logging Module Documentation