Skip to main content

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

FunctionDescriptionParametersReturn Type
getLogger(name=None)Get logger instancename: Logger name (str, optional)Logger

Logging Methods

MethodDescriptionLevelParameters
debug(msg, *args, **kwargs)Log debug message10msg: Message, *args: Format args, **kwargs: Extra info
info(msg, *args, **kwargs)Log info message20msg: Message, *args: Format args, **kwargs: Extra info
warning(msg, *args, **kwargs)Log warning message30msg: Message, *args: Format args, **kwargs: Extra info
error(msg, *args, **kwargs)Log error message40msg: Message, *args: Format args, **kwargs: Extra info
critical(msg, *args, **kwargs)Log critical message50msg: Message, *args: Format args, **kwargs: Extra info
exception(msg, *args, **kwargs)Log error with traceback40msg: Message, *args: Format args, **kwargs: Extra info
log(level, msg, *args, **kwargs)Log with custom levelCustomlevel: Log level, msg: Message, etc.

Configuration Methods

MethodDescriptionParametersReturn Type
setLevel(level)Set effective levellevel: Logging level (int/str)None
getEffectiveLevel()Get effective levelNoneint
isEnabledFor(level)Check if level enabledlevel: Logging level (int)bool
addHandler(hdlr)Add handlerhdlr: Handler instanceNone
removeHandler(hdlr)Remove handlerhdlr: Handler instanceNone
addFilter(filt)Add filterfilt: Filter instance/callableNone
removeFilter(filt)Remove filterfilt: Filter instance/callableNone

Properties

PropertyDescriptionTypeAccess
nameLogger namestrRead-only
levelLogger levelintRead/Write
parentParent loggerLoggerRead/Write
propagatePropagate to parentboolRead/Write
handlersList of handlerslistRead-only
disabledLogger disabled flagboolRead/Write

Advanced Methods

MethodDescriptionParametersReturn Type
filter(record)Apply filters to recordrecord: LogRecordbool
handle(record)Handle log recordrecord: LogRecordNone
makeRecord(...)Create LogRecordVarious record fieldsLogRecord
findCaller(...)Find caller infoStack/skip parameterstuple

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

OperationTime ComplexityNotes
logger.info()O(1)Fast message creation
Handler processingO(n)n = number of handlers
Filter evaluationO(m)m = number of filters
Format stringO(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

  • logging.Handler - Output destination management
  • logging.Formatter - Message formatting
  • logging.Filter - Fine-grained filtering
  • logging.config - Configuration utilities