logging.Logger
The Logger class is the main interface for the logging system. Logger objects are created using the logging.getLogger(name) function and form a hierarchy based on their names using dot notation.
Basic Usage
Simple Example
import logging
# Get a logger instance
logger = logging.getLogger('my_app')
# Set logging level
logger.setLevel(logging.DEBUG)
# Create console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# Create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
# Add handler to logger
logger.addHandler(console_handler)
# Log messages
logger.debug("Debug message") # Won't appear (below handler level)
logger.info("Info message") # Will appear
logger.warning("Warning message") # Will appear
logger.error("Error message") # Will appear
Logger Hierarchy
import logging
# Parent logger
parent_logger = logging.getLogger('myapp')
# Child loggers inherit from parent
module_logger = logging.getLogger('myapp.module')
db_logger = logging.getLogger('myapp.database')
api_logger = logging.getLogger('myapp.api.v1')
# Configure parent - children inherit settings
parent_logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
parent_logger.addHandler(handler)
# Child loggers can have additional handlers
db_logger.addHandler(logging.FileHandler('database.log'))
Core Methods
import logging
logger = logging.getLogger(__name__)
# Logging methods (in order of severity)
logger.debug("Detailed information for debugging")
logger.info("General information about program execution")
logger.warning("Something unexpected happened")
logger.error("A serious problem occurred")
logger.critical("Very serious error occurred")
# Exception logging (includes traceback)
try:
1 / 0
except ZeroDivisionError:
logger.exception("Division by zero occurred")
# Generic logging with custom level
logger.log(logging.WARNING, "Custom level message")
Logger API Reference
Logger Creation
| Function | Description | Parameters | Return Type |
|---|---|---|---|
getLogger(name=None) | Get logger instance | name: Logger name (str, optional) | Logger |
Logging Methods
| Method | Description | Level | Parameters |
|---|---|---|---|
debug(msg, *args, **kwargs) | Log debug message | 10 | msg: Message, *args: Format args, **kwargs: Extra info |
info(msg, *args, **kwargs) | Log info message | 20 | msg: Message, *args: Format args, **kwargs: Extra info |
warning(msg, *args, **kwargs) | Log warning message | 30 | msg: Message, *args: Format args, **kwargs: Extra info |
error(msg, *args, **kwargs) | Log error message | 40 | msg: Message, *args: Format args, **kwargs: Extra info |
critical(msg, *args, **kwargs) | Log critical message | 50 | msg: Message, *args: Format args, **kwargs: Extra info |
exception(msg, *args, **kwargs) | Log error with traceback | 40 | msg: Message, *args: Format args, **kwargs: Extra info |
log(level, msg, *args, **kwargs) | Log with custom level | Custom | level: Log level, msg: Message, etc. |
Configuration Methods
| Method | Description | Parameters | Return Type |
|---|---|---|---|
setLevel(level) | Set effective level | level: Logging level (int/str) | None |
getEffectiveLevel() | Get effective level | None | int |
isEnabledFor(level) | Check if level enabled | level: Logging level (int) | bool |
addHandler(hdlr) | Add handler | hdlr: Handler instance | None |
removeHandler(hdlr) | Remove handler | hdlr: Handler instance | None |
addFilter(filt) | Add filter | filt: Filter instance/callable | None |
removeFilter(filt) | Remove filter | filt: Filter instance/callable | None |
Properties
| Property | Description | Type | Access |
|---|---|---|---|
name | Logger name | str | Read-only |
level | Logger level | int | Read/Write |
parent | Parent logger | Logger | Read/Write |
propagate | Propagate to parent | bool | Read/Write |
handlers | List of handlers | list | Read-only |
disabled | Logger disabled flag | bool | Read/Write |
Advanced Methods
| Method | Description | Parameters | Return Type |
|---|---|---|---|
filter(record) | Apply filters to record | record: LogRecord | bool |
handle(record) | Handle log record | record: LogRecord | None |
makeRecord(...) | Create LogRecord | Various record fields | LogRecord |
findCaller(...) | Find caller info | Stack/skip parameters | tuple |
Common Errors and Troubleshooting
Typical Error Messages
import logging
# Error 1: No handlers configured
logger = logging.getLogger('test')
logger.warning("This might not appear anywhere")
# Solution: Add a handler or use basicConfig()
# Error 2: Level too low
logger = logging.getLogger('test')
logger.setLevel(logging.ERROR)
logger.info("This won't appear") # Level too low
# Solution: Set appropriate level
# Error 3: Handler level conflicts
logger = logging.getLogger('test')
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setLevel(logging.ERROR) # Handler blocks lower levels
logger.addHandler(handler)
logger.info("This won't appear") # Handler level too high
Debugging Tips
import logging
# Check effective level
logger = logging.getLogger('test')
print(f"Effective level: {logger.getEffectiveLevel()}")
print(f"Level name: {logging.getLevelName(logger.getEffectiveLevel())}")
# Check if level is enabled
if logger.isEnabledFor(logging.DEBUG):
print("Debug logging is enabled")
# List all handlers
for handler in logger.handlers:
print(f"Handler: {handler.__class__.__name__}, Level: {handler.level}")
# Check propagation
print(f"Propagates to parent: {logger.propagate}")
print(f"Parent logger: {logger.parent.name if logger.parent else 'None'}")
Error Handling Patterns
import logging
logger = logging.getLogger(__name__)
try:
# Risky operation
result = risky_operation()
except ValueError as e:
logger.error("ValueError occurred: %s", e)
# Re-raise if needed
raise
except Exception as e:
logger.exception("Unexpected error occurred")
# Log full traceback with exception()
Primary Use Cases
1. Application Logging Setup
Use Case: Configure logging for a Python application Why Logger: Centralized control over log output and formatting
import logging
import logging.handlers
def setup_logging(app_name, log_file=None, level=logging.INFO):
"""Setup application logging configuration."""
# Create main application logger
logger = logging.getLogger(app_name)
logger.setLevel(level)
# Create formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(level)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# File handler (optional)
if log_file:
file_handler = logging.handlers.RotatingFileHandler(
log_file, maxBytes=10*1024*1024, backupCount=5
)
file_handler.setLevel(level)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
return logger
# Usage
logger = setup_logging('myapp', 'app.log')
logger.info("Application started")
2. Module-Level Logging
Use Case: Add logging to individual modules in a larger application Why Logger: Hierarchical naming allows fine-grained control
import logging
# Module: database.py
logger = logging.getLogger(__name__) # Gets 'myapp.database'
class DatabaseConnection:
def connect(self):
logger.info("Connecting to database")
try:
# Connection logic
self.connection = create_connection()
logger.info("Database connection established")
except Exception as e:
logger.error("Failed to connect to database: %s", e)
raise
def execute_query(self, query):
logger.debug("Executing query: %s", query)
try:
result = self.connection.execute(query)
logger.debug("Query returned %d rows", len(result))
return result
except Exception as e:
logger.error("Query failed: %s", e)
raise
3. Error Tracking and Debugging
Use Case: Track errors and debug information in production Why Logger: Structured error reporting with context
import logging
import traceback
logger = logging.getLogger(__name__)
class APIHandler:
def process_request(self, request_data):
request_id = request_data.get('id', 'unknown')
# Use extra parameter for context
extra = {'request_id': request_id}
logger.info("Processing request", extra=extra)
try:
# Process request
result = self.validate_and_process(request_data)
logger.info("Request processed successfully", extra=extra)
return result
except ValidationError as e:
logger.warning("Validation failed: %s", e, extra=extra)
return {'error': 'Invalid request'}
except Exception as e:
# Log full exception with context
logger.exception("Unexpected error processing request", extra=extra)
return {'error': 'Internal server error'}
def validate_and_process(self, data):
# Validation and processing logic
if not data.get('required_field'):
raise ValidationError("Missing required field")
return {'status': 'success'}
class ValidationError(Exception):
pass
4. Performance Monitoring
Use Case: Monitor application performance and timing Why Logger: Structured performance data collection
import logging
import time
from functools import wraps
logger = logging.getLogger(__name__)
def log_performance(func):
"""Decorator to log function execution time."""
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
func_name = f"{func.__module__}.{func.__qualname__}"
logger.debug("Starting %s", func_name)
try:
result = func(*args, **kwargs)
execution_time = time.time() - start_time
logger.info(
"Function %s completed in %.3f seconds",
func_name, execution_time,
extra={'execution_time': execution_time, 'function': func_name}
)
return result
except Exception as e:
execution_time = time.time() - start_time
logger.error(
"Function %s failed after %.3f seconds: %s",
func_name, execution_time, e,
extra={'execution_time': execution_time, 'function': func_name}
)
raise
return wrapper
# Usage
@log_performance
def expensive_operation(data):
time.sleep(2) # Simulate expensive operation
return f"Processed {len(data)} items"
result = expensive_operation([1, 2, 3, 4, 5])
Performance Considerations
Time Complexity Summary
| Operation | Time Complexity | Notes |
|---|---|---|
logger.info() | O(1) | Fast message creation |
| Handler processing | O(n) | n = number of handlers |
| Filter evaluation | O(m) | m = number of filters |
| Format string | O(k) | k = complexity of format |
Lazy Evaluation Best Practices
import logging
logger = logging.getLogger(__name__)
# ❌ Avoid - always evaluates expensive_operation()
logger.debug("Result: " + expensive_operation())
# ✅ Better - only evaluates if debug enabled
logger.debug("Result: %s", expensive_operation())
# ✅ Best - check level first for very expensive operations
if logger.isEnabledFor(logging.DEBUG):
logger.debug("Result: %s", expensive_operation())
Memory Usage Tips
import logging
# Use appropriate levels to reduce log volume
logger = logging.getLogger(__name__)
# Production: Set higher level to reduce overhead
if production_mode:
logger.setLevel(logging.WARNING)
else:
logger.setLevel(logging.DEBUG)
# Use rotating handlers to manage disk space
handler = logging.handlers.RotatingFileHandler(
'app.log', maxBytes=50*1024*1024, backupCount=10
)
When to Use Logger
Ideal Use Cases
- Application debugging: Track program flow and variable states
- Error monitoring: Capture and report application errors
- Audit trails: Record user actions and system events
- Performance monitoring: Track execution times and resource usage
- System integration: Log interactions between components
- Production troubleshooting: Investigate issues in live systems
- Compliance logging: Meet regulatory logging requirements
- Development debugging: Understand code execution during development
When NOT to Use Logger
- High-frequency events: Microsecond-level timing (use profilers instead)
- Binary data logging: Large binary payloads (use specialized tools)
- Real-time streaming: Sub-millisecond latency requirements
- Simple scripts: One-off utilities where print() suffices
- Security-sensitive data: Passwords, keys, personal data
- High-volume metrics: Use dedicated metrics systems (Prometheus, etc.)
Alternative Solutions
- Print statements: Simple debugging in development
- Metrics systems: Prometheus, StatsD for numerical data
- Tracing systems: Jaeger, Zipkin for distributed tracing
- Error tracking: Sentry, Rollbar for error aggregation
- Audit systems: Dedicated audit logging solutions
- Performance profilers: cProfile, line_profiler for detailed analysis
Additional Learning Resources
Official Python Resources
- Library Documentation: logging — Logging facility for Python
- Tutorial: Logging HOWTO
- Advanced Tutorial: Advanced Logging Tutorial
- Cookbook: Logging Cookbook
Related Documentation
- logging.Handler - Output destination management
- logging.Formatter - Message formatting
- logging.Filter - Fine-grained filtering
- logging.config - Configuration utilities