Handlers#

The handler in the logging library is a tool that allows you to specify the direction in which new records from the logger will appear.

Check list of the usefull handlers.

import logging

Add/list/remove#

Use:

  • Logger.addHandler: method to add handler.

  • Logger.handlers: is a list that contains all awailable handlers.

  • Logger.removeHandler: method to remove handler.


The following cell creates a logger and handler that we’ll use as an example.

my_logger = logging.getLogger("crud logger")
handler = logging.StreamHandler()

Next code adds handler to the logger.

my_logger.addHandler(handler)

Here is how the handlers attribute of the logger looks.

my_logger.handlers
[<StreamHandler stderr (NOTSET)>]

There is one element - logger that we’ve just added.

Following cell applies removeHandler method.

my_logger.removeHandler(handler)

The next cell shows that there are no handlers left in the logger after handler removal.

my_logger.handlers
[]

Several handlers#

A great option is that you can add multiple handlers to a logger, allowing the same messages to be sent to different sources sulmatenously.


Here is an example to illustrate the point. There are two handlers. They print in a format that allows you to identify which logger printed the line. The first logger has a “DEBUG” level and the second has an “ERROR” level, so it’ll print fewer messages. Both are added to the same logger.

my_logger = logging.getLogger("test")

stream_handler1 = logging.StreamHandler()
stream_handler1.setLevel("DEBUG")
stream_handler1.setFormatter(
    logging.Formatter("Stream handler1 %(message)s")
)

stream_handler2 = logging.StreamHandler()
stream_handler2.setLevel("ERROR")
stream_handler2.setFormatter(
    logging.Formatter("Stream handler2 %(message)s")
)

my_logger.addHandler(stream_handler1)
my_logger.addHandler(stream_handler2)

Now lets try to execute some log commands from logger.

my_logger.debug("debug")
my_logger.info("info")
my_logger.warning("warning")
my_logger.error("error")
my_logger.critical("critical")
my_logger.handlers.clear()
Stream handler1 debug
Stream handler1 info
Stream handler1 warning
Stream handler1 error
Stream handler2 error
Stream handler1 critical
Stream handler2 critical

As a result, you can see that some messages were replied to twice, but each logging command was called once. This happens because error and critical messages were generated by both handlers added to the logger in question.

Custom handler#

There are a set of conditions for a Python class to function as a logging handler. You can check them here. So presumably you can make a class that satisfies these requirements and use it as a logger. For example, a handler that publishes messages to Slack chat. This section explores how you can create your own logging handler.

The minimal requirement is to create a class that inherits from logging.Handler and defines the emit method to specify the handler’s behavior.


The following cell defines the simplest handler you can make - on each try it just applies print to the same messages.

from logging import LogRecord

class ToyHandler(logging.Handler):
    def emit(self, record: LogRecord) -> None:
        print("This is a message from simple custom logger.")

The following cell shows how such a handler can be used.

toy_logger = logging.getLogger("toy")
toy_logger.addHandler(ToyHandler())
toy_logger.error("hello")
This is a message from simple custom logger.