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:

  1. Receive a LogRecord from a logger.
  2. Check its own level filter (a handler can be stricter than the logger).
  3. Format the record using its assigned Formatter.
  4. 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

HandlerDestinationWhen to use
StreamHandlerstdout / stderrLocal development, container logs
FileHandlerSingle fileSimple apps, known disk capacity
RotatingFileHandlerRotating files by sizeLong-running services with bounded disk
TimedRotatingFileHandlerRotating files by timeDaily log archives
SysLogHandlersyslog daemonLinux system integration
SocketHandlerTCP socketCentralized log collector
DatagramHandlerUDP socketFire-and-forget log shipping
SMTPHandlerEmailCritical alerts to on-call engineers
HTTPHandlerHTTP endpointWebhook-based alerting (Slack, PagerDuty)
QueueHandlerqueue.QueueNon-blocking logging in latency-sensitive code
NullHandlerNowhereLibrary 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.

pythonloggingoperations

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.