Python Logging: Production Patterns and Best Practices
Master Python logging for production systems.
20+ years shipping production Python across data and backend systems. Everything here is grounded in real deployments.
- ✓Basic Python syntax and functions
- ✓Understanding of file I/O and exception handling
- ✓Familiarity with multi-threading or asyncio (for advanced sections)
- Use the built-in
loggingmodule instead of print statements. - Configure loggers with appropriate levels (DEBUG, INFO, WARNING, ERROR, CRITICAL).
- Use structured logging (JSON) for machine parsing.
- Implement log rotation to manage disk space.
- Centralize logs with tools like ELK or Datadog.
Think of logging like a flight recorder for your code. It records events, errors, and important milestones so you can replay what happened when something goes wrong. Just as a pilot uses the black box to understand a crash, you use logs to debug production issues.
In production, your code runs without a debugger. When something breaks, you need a detailed record of what happened. That's where logging comes in. Python's built-in logging module is powerful but often misused. Many developers start with print() statements, but that's like using a sticky note when you need a filing cabinet. In this tutorial, you'll learn production-ready logging patterns: how to configure loggers, use structured logging, handle log rotation, and avoid common mistakes. We'll cover real-world scenarios like debugging a silent failure in a web service and tracing requests across microservices. By the end, you'll be able to set up a logging system that helps you sleep better at night.
Why Logging Matters in Production
When your application runs on a server, you can't attach a debugger. Logs are your eyes and ears. They help you understand the flow of execution, detect anomalies, and diagnose failures. Without proper logging, you're flying blind. Consider a web service that occasionally returns 500 errors. Without logs, you have no idea why. With structured logs, you can see the exact request parameters, the stack trace, and the database query that failed. Logging also aids in auditing, compliance, and performance monitoring. In this section, we'll explore the core concepts of Python's logging module: loggers, handlers, formatters, and filters. You'll learn how to set up a basic configuration that scales.
basicConfig multiple times; it's a no-op after the first call. Use a configuration file or dictConfig.basicConfig for simple setups, but move to dictConfig for production.Structured Logging with JSON
Plain text logs are hard to parse. Structured logging outputs logs in JSON format, making it easy for log aggregation tools like ELK, Splunk, or Datadog to index and search. Each log entry becomes a JSON object with fields like timestamp, level, logger, message, and custom context. Python's logging module can be extended with a custom formatter that outputs JSON. Alternatively, you can use libraries like python-json-logger. In this section, we'll implement a JSON formatter from scratch and show how to add extra context (e.g., request ID, user ID) using the extra parameter or a custom filter.
Log Rotation and Management
Log files grow indefinitely and can fill up your disk. Python's logging.handlers module provides RotatingFileHandler and TimedRotatingFileHandler to manage log files. RotatingFileHandler rotates logs when they reach a certain size, keeping a specified number of backup files. TimedRotatingFileHandler rotates at specific intervals (e.g., daily). In production, you should also consider log compression and cleanup. We'll demonstrate how to configure rotation and discuss best practices like using a separate partition for logs and setting appropriate retention policies.
Logging in Multi-Threaded and Async Applications
In multi-threaded applications, logging from multiple threads can cause interleaved messages. Python's logging module is thread-safe, but you need to ensure that your handlers are also thread-safe. For async applications using asyncio, logging can be tricky because the default logging is blocking. You can use a queue-based handler to offload logging to a separate thread. We'll show how to use QueueHandler and QueueListener for non-blocking logging in async apps.
Centralized Logging and Monitoring
In a distributed system, logs are scattered across multiple servers. Centralized logging aggregates logs into a single platform for search, alerting, and visualization. Common solutions include the ELK stack (Elasticsearch, Logstash, Kibana), Graylog, and cloud services like AWS CloudWatch or Datadog. Python applications can send logs directly to these systems using handlers like logstash.LogstashHandler or watchtower for CloudWatch. We'll show how to send structured logs to a remote syslog server and discuss best practices for log shipping.
Best Practices and Common Pitfalls
In this final section, we summarize best practices: use appropriate log levels, avoid logging sensitive data, log at the right granularity, and use lazy evaluation for expensive log messages. Common pitfalls include logging in tight loops, using instead of logging, and forgetting to configure logging in library code. We'll also discuss how to use print()logging.getLogger(__name__) to create hierarchical loggers and how to configure logging via a dictionary for complex applications.
The Silent Crash: When Logs Don't Log
- Always flush logs immediately in production (use
delay=Falsefor file handlers). - Log exceptions with
in except blocks.logger.exception() - Use structured logging to capture context (request ID, user ID).
- Test your logging configuration under load.
- Centralize logs for search and alerting.
import logging; logging.basicConfig(level=logging.DEBUG)logging.getLogger().addHandler(logging.StreamHandler())| File | Command / Code | Purpose |
|---|---|---|
| basic_logging.py | logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(level... | Why Logging Matters in Production |
| json_logging.py | class JsonFormatter(logging.Formatter): | Structured Logging with JSON |
| log_rotation.py | from logging.handlers import RotatingFileHandler | Log Rotation and Management |
| async_logging.py | from logging.handlers import QueueHandler, QueueListener | Logging in Multi-Threaded and Async Applications |
| centralized_logging.py | from logging.handlers import SysLogHandler | Centralized Logging and Monitoring |
| best_practices.py | LOGGING_CONFIG = { | Best Practices and Common Pitfalls |
Key takeaways
Interview Questions on This Topic
Explain the logging levels in Python and when to use each.
Frequently Asked Questions
20+ years shipping production Python across data and backend systems. Everything here is grounded in real deployments.
That's Advanced Python. Mark it forged?
3 min read · try the examples if you haven't