📝 Using Logging
Logging is a better alternative to print statements for tracking application behavior. Python's logging module provides structured, configurable output that's essential for debugging and monitoring applications.
import logging
# Basic logging setup
logging.basicConfig(level=logging.INFO)
# Create log messages
logging.debug("This is a debug message")
logging.info("Application started")
logging.warning("This is a warning")
logging.error("An error occurred")
logging.critical("Critical system failure")
🎯 Basic Logging
Logging provides different levels of messages for various situations.
Simple Logging Examples
import logging
# Configure logging to show all levels
logging.basicConfig(level=logging.DEBUG)
def divide_numbers(a, b):
logging.info(f"Dividing {a} by {b}")
if b == 0:
logging.error("Division by zero attempted")
return None
result = a / b
logging.info(f"Division result: {result}")
return result
# Test the function
result1 = divide_numbers(10, 2)
result2 = divide_numbers(10, 0)
Logging with Different Levels
import logging
# Set up logging
logging.basicConfig(level=logging.DEBUG)
def process_user_data(user_data):
logging.debug(f"Processing user data: {user_data}")
if not user_data:
logging.warning("Empty user data received")
return {}
if "email" not in user_data:
logging.error("Missing required field: email")
return None
logging.info("User data processed successfully")
return {"status": "processed"}
# Test with different scenarios
process_user_data({"name": "Alice", "email": "alice@example.com"})
process_user_data({"name": "Bob"}) # Missing email
process_user_data({}) # Empty data
Logging Exceptions
import logging
logging.basicConfig(level=logging.INFO)
def safe_file_operation(filename):
try:
logging.info(f"Attempting to read file: {filename}")
with open(filename, 'r') as file:
content = file.read()
logging.info("File read successfully")
return content
except FileNotFoundError:
logging.error(f"File not found: {filename}")
return None
except Exception as e:
logging.exception("Unexpected error occurred") # Includes traceback
return None
# Test file operations
content = safe_file_operation("existing_file.txt")
content = safe_file_operation("missing_file.txt")
📋 Log Level Reference
Level | Numeric Value | When to Use |
---|---|---|
DEBUG | 10 | Detailed diagnostic info |
INFO | 20 | General information |
WARNING | 30 | Something unexpected |
ERROR | 40 | Serious problem |
CRITICAL | 50 | Very serious error |
🔧 Logging Configuration
Basic Configuration
import logging
# Configure logging format
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def user_login(username):
logging.info(f"User login attempt: {username}")
if username == "admin":
logging.info("Admin user logged in successfully")
return True
else:
logging.warning(f"Unknown user login attempt: {username}")
return False
# Test user login
user_login("admin")
user_login("hacker")
Logging to File
import logging
# Configure logging to file
logging.basicConfig(
filename='application.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def database_operation(operation, table):
logging.info(f"Database operation: {operation} on table {table}")
try:
# Simulate database operation
if table == "users":
logging.info("Operation completed successfully")
return True
else:
logging.error(f"Table '{table}' not found")
return False
except Exception as e:
logging.exception("Database operation failed")
return False
# Test database operations
database_operation("SELECT", "users")
database_operation("INSERT", "invalid_table")
Custom Logger
import logging
# Create custom logger
logger = logging.getLogger('my_application')
logger.setLevel(logging.DEBUG)
# Create handler for console output
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# Create formatter
formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
# Add handler to logger
logger.addHandler(console_handler)
def api_request(endpoint):
logger.debug(f"API request details: {endpoint}")
logger.info(f"Making API request to: {endpoint}")
if endpoint.startswith("/api/"):
logger.info("API request successful")
return {"status": "success"}
else:
logger.error("Invalid API endpoint")
return {"status": "error"}
# Test API requests
api_request("/api/users")
api_request("/invalid/endpoint")
📊 Logging Configuration Options
Basic Configuration Parameters
Parameter | Purpose | Example |
---|---|---|
level | Minimum log level | logging.INFO |
format | Message format | '%(levelname)s - %(message)s' |
filename | Log to file | 'app.log' |
filemode | File mode | 'a' (append) or 'w' (write) |
Format Specifiers
Specifier | Meaning | Example |
---|---|---|
%(asctime)s | Timestamp | 2024-03-15 14:30:45,123 |
%(levelname)s | Log level | INFO |
%(message)s | Log message | User logged in |
%(name)s | Logger name | my_app |
%(filename)s | Source filename | main.py |
%(lineno)d | Line number | 42 |
🛠️ Practical Logging Examples
Application Startup Logging
import logging
# Configure application logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def initialize_application():
logging.info("Application starting up")
# Initialize components
components = ["database", "cache", "api_server"]
for component in components:
logging.info(f"Initializing {component}")
# Simulate initialization
if component == "database":
logging.info("Database connection established")
elif component == "cache":
logging.warning("Cache server running on backup port")
elif component == "api_server":
logging.info("API server started on port 8080")
logging.info("Application startup completed")
initialize_application()
Error Tracking
import logging
logging.basicConfig(level=logging.INFO)
def process_orders(orders):
logging.info(f"Processing {len(orders)} orders")
processed = 0
errors = 0
for order_id, order in enumerate(orders, 1):
try:
logging.debug(f"Processing order {order_id}: {order}")
if "total" not in order:
raise ValueError("Missing total amount")
if order["total"] <= 0:
raise ValueError("Invalid total amount")
processed += 1
logging.info(f"Order {order_id} processed successfully")
except ValueError as e:
errors += 1
logging.error(f"Order {order_id} failed: {e}")
except Exception as e:
errors += 1
logging.exception(f"Unexpected error in order {order_id}")
logging.info(f"Order processing complete: {processed} successful, {errors} errors")
# Test order processing
orders = [
{"id": 1, "total": 25.99},
{"id": 2, "total": -5.00}, # Invalid amount
{"id": 3, "product": "item"} # Missing total
]
process_orders(orders)
🎯 Key Takeaways
🚀 What's Next?
Learn how to implement retry logic to make your applications more resilient to temporary failures.
Continue to: Implement Retry Logic
Was this helpful?
Track Your Learning Progress
Sign in to bookmark tutorials and keep track of your learning journey.
Your progress is saved automatically as you read.