When to Use Logging
| Task | Tool |
|---|---|
| Display console output for CLI scripts | print() |
| Report events during normal operation | logger.info() or logger.debug() |
| Issue a warning about a runtime event | logger.warning() |
| Report an error but continue running | logger.error() or logger.exception() |
| Report a critical error | logger.critical() |
| Suppress an error without raising exception | logger.error() |
Quick Start
import logging
# Configure basic logging
logging.basicConfig(level=logging.DEBUG)
# Create a logger
logger = logging.getLogger(__name__)
logger.debug('This is a debug message')
logger.info('This is an info message')
logger.warning('This is a warning message')
logger.error('This is an error message')
logger.critical('This is a critical message')
Logging Levels
Levels in order of severity:| Level | Value | When to Use |
|---|---|---|
DEBUG | 10 | Detailed diagnostic information |
INFO | 20 | Confirmation that things are working |
WARNING | 30 | Something unexpected happened |
ERROR | 40 | Serious problem, function couldn’t complete |
CRITICAL | 50 | Program may be unable to continue |
Logging to Files
Basic File Logging
File Modes
Format Strings
Common Format Attributes
%(name)s- Logger name%(levelname)s- Logging level%(message)s- Log message%(asctime)s- Timestamp%(filename)s- Source filename%(lineno)d- Line number%(funcName)s- Function name%(process)d- Process ID%(thread)d- Thread ID
Custom Formatting
Variable Data
Using Format Strings
Advanced Configuration
import logging
# Create logger
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG)
# Create console handler
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# Create formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Add formatter to handler
ch.setFormatter(formatter)
# Add handler to logger
logger.addHandler(ch)
import logging
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG)
# Console handler - only warnings and above
console = logging.StreamHandler()
console.setLevel(logging.WARNING)
# File handler - everything
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.DEBUG)
# Format both
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console.setFormatter(formatter)
file_handler.setFormatter(formatter)
# Add both handlers
logger.addHandler(console)
logger.addHandler(file_handler)
from logging.handlers import RotatingFileHandler
logger = logging.getLogger('my_app')
# Rotate after 10MB, keep 5 backup files
handler = RotatingFileHandler(
'app.log',
maxBytes=10*1024*1024, # 10MB
backupCount=5
)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
Exception Logging
Log Exceptions with Traceback
Log Without Traceback
Logger Hierarchy
Parent-Child Relationships
Best Practice: Module-Level Loggers
Configuration Files
INI Format
Dictionary Configuration
Library Logging
For Library Authors
Library Best Practices:
- Use
logging.getLogger(__name__)in each module - Add
NullHandler()to prevent warnings - Never configure handlers in library code
- Document what loggers your library uses
Common Patterns
Conditional Expensive Operations
Context Information
Web Request Logging
Troubleshooting
Debug Logging Setup
Summary
Key takeaways:- Use
logger = logging.getLogger(__name__)in each module - Configure logging once at application entry point
- Use appropriate log levels (DEBUG, INFO, WARNING, ERROR, CRITICAL)
- Never add handlers in library code
- Use
logger.exception()in except blocks - Format messages with placeholders, not string concatenation
