Python Logging Handlers — Core Concepts
Python’s logging module separates what you log from where it goes. Handlers are the “where” — pluggable destinations attached to loggers. Understanding the built-in handler catalog lets you build flexible logging pipelines without adding dependencies.
The handler lifecycle
Every handler follows the same steps:
- Receive a
LogRecordfrom a logger. - Check its own level filter (a handler can be stricter than the logger).
- Format the record using its assigned
Formatter. - Emit the formatted output to the destination (file, socket, email).
If emission fails, the handler calls handleError() instead of crashing your application.
Common built-in handlers
| Handler | Destination | When to use |
|---|---|---|
StreamHandler | stdout / stderr | Local development, container logs |
FileHandler | Single file | Simple apps, known disk capacity |
RotatingFileHandler | Rotating files by size | Long-running services with bounded disk |
TimedRotatingFileHandler | Rotating files by time | Daily log archives |
SysLogHandler | syslog daemon | Linux system integration |
SocketHandler | TCP socket | Centralized log collector |
DatagramHandler | UDP socket | Fire-and-forget log shipping |
SMTPHandler | Critical alerts to on-call engineers | |
HTTPHandler | HTTP endpoint | Webhook-based alerting (Slack, PagerDuty) |
QueueHandler | queue.Queue | Non-blocking logging in latency-sensitive code |
NullHandler | Nowhere | Library code (avoids “no handler found” warning) |
Attaching multiple handlers
A single logger can have many handlers with different levels:
logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)
console = logging.StreamHandler()
console.setLevel(logging.INFO) # screen sees INFO+
file_h = logging.FileHandler("app.log")
file_h.setLevel(logging.DEBUG) # file catches everything
This pattern keeps your terminal clean while preserving full detail on disk.
Formatters matter
Handlers emit raw LogRecord objects by default, which look ugly. Always attach a formatter:
fmt = logging.Formatter("%(asctime)s %(name)s %(levelname)s %(message)s")
console.setFormatter(fmt)
file_h.setFormatter(fmt)
For JSON output, write a custom formatter or use python-json-logger.
Rotation parameters
RotatingFileHandler(filename, maxBytes=5_000_000, backupCount=3) keeps at most 4 files (current + 3 backups). When the current file hits 5 MB, it rotates. Old files beyond backupCount are deleted automatically.
TimedRotatingFileHandler(filename, when="midnight", backupCount=7) rotates daily and keeps a week of history.
Common misconception
“Adding more handlers makes logging slow.” In practice, StreamHandler and FileHandler add microseconds per call. The real bottleneck is logging inside tight loops — the message formatting itself, not the handler dispatch. Use QueueHandler with a QueueListener if you need truly non-blocking emission.
Libraries should use NullHandler only
If you’re writing a library (not an application), add exactly one handler:
logging.getLogger("mylibrary").addHandler(logging.NullHandler())
This prevents the “No handlers could be found” warning while letting the application owner decide where logs go.
One thing to remember: Handlers are pluggable destinations. Pick the right combination once at application startup and every logger in your codebase benefits automatically through Python’s logger hierarchy.
See Also
- Python Alerting Patterns Alerting is a smoke detector for your code — it wakes you up when something is burning, not when someone is cooking.
- Python Correlation Ids Correlation IDs are name tags for requests — they let you follow one visitor's journey through a crowded theme park of services.
- Python Grafana Dashboards Python Grafana turns boring numbers from your Python app into colorful, real-time dashboards — like a car's dashboard but for your code.
- Python Log Aggregation Elk ELK collects scattered log files from all your services into one searchable place — like gathering every sticky note in the office into a single filing cabinet.
- Python Logging Best Practices Treat logs like a flight recorder so you can understand failures after they happen, not just during development.