python – 如何限制相同日志消息的数量?

我使用
logging模块来警告某些例程的问题.这些例程可以在返回到正常操作之前运行若干次(例如,对失败但最终经历的API的重复查询).每个失败的呼叫都会触发日志条目.

有没有办法限制相同日志消息的数量?
我希望在输出n个相同的消息后触发此限制,然后可能会通知生成更多n(因此不会使日志文件混乱)并在收到恢复日志后重置.这是理想的情况 – 我正在研究如何解决问题.

我找到的最接近的是conditional release of logs,但我不知道这可以如何适应我的情况.
 另一种可能性是将限制放在syslog级别(在rsyslog或syslog-ng中),但这是一个“每个进程”设置,所以我可能会丢失有用的日志(那些将在循环生成的日志之间进入)

最佳答案 使用logging.Filter!

DuplicateFilter采用两个正则表达式模式或一个字符串(要编译成一个),一个应该与要过滤掉的字符串匹配,另一个要重置过滤器.

import logging
import os
import re
import sys

from sre_parse import Pattern


class DuplicateFilter(logging.Filter):
    def __init__(self, match_against, reset_at_message, hide_at_count=5, name=''):
        super(DuplicateFilter, self).__init__(name)

        if isinstance(match_against, Pattern):
            self.match_against = match_against
        else:
            self.match_against = re.compile(match_against)

        if isinstance(reset_at_message, Pattern):
            self.reset_at_message = reset_at_message
        else:
            self.reset_at_message = re.compile(reset_at_message)

        self.hide_at_count = hide_at_count

        self.count = 0

    def filter(self, record: logging.LogRecord):
        _ = super(DuplicateFilter, self).filter(record)
        if not _:
            return _

        msg = record.getMessage()

        if self.match_against.match(msg):
            self.count += 1

            if self.count >= self.hide_at_count:
                return False

        elif self.reset_at_message.match(msg):
            record.msg = os.linesep.join([
                '{:d} more generated'.format(self.count - self.hide_at_count),
                record.msg
            ])
            self.count = 0

        return True

handler = logging.StreamHandler(sys.stdout)
handler.addFilter(DuplicateFilter('Filter me!', 'Reset at me'))

logging.basicConfig(level='INFO', handlers=[handler, ])

log = logging.getLogger()

for _ in range(10):
    log.info('Filter me!')

log.info('Reset at me')

for _ in range(3):
    log.info('Filter me!')

这是结果日志:

INFO:root:Filter me!
INFO:root:Filter me!
INFO:root:Filter me!
INFO:root:Filter me!
INFO:root:5 more generated
Reset at me
INFO:root:Filter me!
INFO:root:Filter me!
INFO:root:Filter me!

只是预先挂起“5更多生成”的消息可能不是你想要的,但希望这是一个很好的起点.

点赞