Python logging: print message only once

Define a filter which keeps track of what was logged, and attach it to your logger for the duration of the loop. This example will remember each message it sees, and only allow the first occurrence to be logged.

class DuplicateFilter(object):
    def __init__(self):
        self.msgs = set()

    def filter(self, record):
        rv = record.msg not in self.msgs
        self.msgs.add(record.msg)
        return rv

dup_filter = DuplicateFilter()
logger.addFilter(dup_filter)
for i in range(10):
    canned_example()
logger.removeFilter(dup_filter)

This is a modified variant of @chepner's answer. I had some issues getting it to work when the thing logged wasn't a string (i.e. an exception) and wanted to make use of context managers to more conveniently add and remove the filter:

class DuplicateFilter:
    """
    Filters away duplicate log messages.
    Modified version of: https://stackoverflow.com/a/31953563/965332
    """

    def __init__(self, logger):
        self.msgs = set()
        self.logger = logger

    def filter(self, record):
        msg = str(record.msg)
        is_duplicate = msg in self.msgs
        if not is_duplicate:
            self.msgs.add(msg)
        return not is_duplicate

    def __enter__(self):
        self.logger.addFilter(self)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.logger.removeFilter(self)

Usage:

logger = logging.getLogger(__name__)

with DuplicateFilter(logger):
    for _ in range(5):
        logger.info("This will only show up once!")
        logger.error(Exception("So will this!"))   # This didn't work in @chepner's example

Tags:

Python