Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To create a custom handler with Python’s standard-library logging package, subclass logging.Handler, implement emit(record) to deliver each log record to your destination, then attach the instance to a logger with addHandler(). Use a built-in handler, formatter, or filter instead when that already meets the need.

Example: write formatted records to a custom destination

This template prints the formatted message as a stand-in for a destination-specific operation. Replace print(message) with the operation your handler owns, such as sending data to a service. The example is illustrative; its destination operation is not a production transport.

import logging


class CustomHandler(logging.Handler):
    def emit(self, record: logging.LogRecord) -> None:
        try:
            message = self.format(record)
            # Replace this with the destination operation.
            print(message)
        except Exception:
            self.handleError(record)


logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

handler = CustomHandler()
handler.setLevel(logging.INFO)
handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
logger.addHandler(handler)

logger.info("Ready")

When logger.info("Ready") is called, the logger passes an eligible record to its handlers. The handler formats it with the formatter configured on that instance, then emit() performs the destination-specific work. The example’s formatter produces a message prefixed with the severity level.

Decide whether you need a custom handler

Subclass Handler when the destination or delivery behavior is genuinely custom. Application code should not instantiate the base Handler directly; the Python Logging HOWTO recommends using a suitable handler class instead. Python Logging HOWTO

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • Use a built-in handler if it supports the destination. The HOWTO identifies StreamHandler and FileHandler as common choices.
  • Use a formatter to change how records are presented, rather than writing a new destination handler just to change the output layout.
  • Use a filter or adapter when you need selection or contextual changes to log records.
  • Use a custom handler for destination-specific behavior that existing handlers do not provide.

Set levels, formatting, and filters

Logger and handler levels act at different stages. A logger’s level determines which events it passes onward; a handler’s level determines the minimum severity it will emit. In the example, both are set to INFO, so lower-severity events are filtered before they reach the handler, while the handler also declines records below its own threshold. Add filters when level thresholds alone are not enough to select or modify records.

Set a formatter on the handler with handler.setFormatter(...); self.format(record) in emit() uses that configured formatter. If you attach multiple handlers, configure each one for its own destination and output requirements.

Keep slow destination work off the logging caller

Network requests and email delivery can take time. Synchronous destination work can also block an asynchronous application’s event loop. For performance-sensitive logging, Python’s logging cookbook describes attaching a QueueHandler to enqueue records quickly and using a QueueListener to hand them to destination handlers on another thread. Python Logging Cookbook

Choose queue behavior deliberately: a bounded queue can fill, so decide what the application should do when it does. Moving work to a listener thread does not by itself make multiple processes safe writers to the same file. For multi-process logging, use an explicit coordination or queue/listener design suited to the deployment and verify it against the Python version and process model in use.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Handle failures and release resources

If destination work raises an exception inside emit(), call self.handleError(record) as in the example. Python documents this as the handler error-reporting path; whether the error is visible depends on logging.raiseExceptions. Avoid reporting a handler failure by logging through that same failing handler, which can cause recursive failures. Python logging.Handler reference

logging.shutdown() flushes and closes handlers, and the logging package registers it to run automatically at interpreter exit. If a custom handler owns external resources, define cleanup that fits the handler lifecycle and the destination’s requirements; do not assume interpreter shutdown replaces every application-specific cleanup need. Python logging reference: shutdown

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Configure handlers in code or with logging configuration

You can create loggers, handlers, and formatters directly in code, load configuration with fileConfig(), or pass a dictionary to dictConfig(). The logging cookbook also documents using user-defined handlers with dictionary configuration. Choose the approach that fits how the application manages configuration; the custom handler still needs to provide its destination behavior through emit().

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.