Подавление нескольких сообщений с одинаковым содержимым в модуле ведения журнала Python AKA log compression

по дизайну, мое приложение иногда производит повторяющиеся ошибки, которые заполняют файл журнала и делают его раздражающим для чтения. Это выглядит так:

WARNING:__main__:CRON10: clock unset or no wind update received in 60 sec -> supressed rrd update
WARNING:__main__:CRON10: clock unset or no wind update received in 60 sec -> supressed rrd update
WARNING:__main__:CRON10: clock unset or no wind update received in 60 sec -> supressed rrd update
WARNING:__main__:CRON10: clock unset or no wind update received in 60 sec -> supressed rrd update

как я могу использовать модуль ведения журнала Python для подавления повторяющихся сообщений и вывода чего-то большего стиля rsyslog (http://www.rsyslog.com/doc/rsconf1_repeatedmsgreduction.html):

WARNING:__main__:CRON10: clock unset or no wind update received in 60 sec -> supressed rrd update
--- The last message repeated 3 times

есть ли способ расширить ведение журнала или мне нужно написать полностью собственный регистратор?

В код, который я использую для ведения журнала:

logging.basicConfig(format='%(asctime)s %(message)s')
logging.basicConfig(level=logging.info)
logger = logging.getLogger(__name__)
hdlr = logging.FileHandler(LOGFILE)
hdlr.setFormatter(formatter)
logger.addHandler(hdlr) 

есть идеи по этому поводу?

1 ответов


вы можете создать logging.Filter это будет отслеживать последнюю зарегистрированную запись и отфильтровывать любые повторяющиеся (похожие) записи, что-то вроде:

import logging

class DuplicateFilter(logging.Filter):

    def filter(self, record):
        # add other fields if you need more granular comparison, depends on your app
        current_log = (record.module, record.levelno, record.msg)
        if current_log != getattr(self, "last_log", None):
            self.last_log = current_log
            return True
        return False

затем просто добавьте его в регистратор/обработчик вы используете (т. е. hdlr.addFilter(DuplicateFilter())) или корневой регистратор для фильтрации всех журналов по умолчанию. Вот простой тест:

import logging

logging.warn("my test")
logging.warn("my repeated test")
logging.warn("my repeated test")
logging.warn("my repeated test")
logging.warn("my other test")

logger = logging.getLogger()  # get the root logger
logger.addFilter(DuplicateFilter())  # add the filter to it

logging.warn("my test")
logging.warn("my repeated test")
logging.warn("my repeated test")
logging.warn("my repeated test")
logging.warn("my other test")

это будет напечатано:

WARNING:root:my test
WARNING:root:my repeated test
WARNING:root:my repeated test
WARNING:root:my repeated test
WARNING:root:my other test
WARNING:root:my test
WARNING:root:my repeated test
WARNING:root:my other test