Python日志记录:仅打印一次消息

时间:2015-08-11 22:46:57

标签: python

我正在使用python 3中的def canned_example(): logger.warning("This function hasn't been created yet") for i in range(10): canned_example() 模块,并希望特定的警告消息只显示一次。 问题是检查是在循环内:

def canned_example():
    logger.warning("This function hasn't been created yet", norepeat=True)


for i in range(10):
    canned_example()

是否在日志记录模块中设置了一个标志,表示此特定警告只显示一次?另一种方法是保留不同标志的记录,但如果可能的话,我想保持简单。

更新:Amir Yazdanbakhsh在评论中发布了一个答案,允许我们对所有邮件执行此操作。理想情况下,我想要一些每消息标志:

{{1}}

3 个答案:

答案 0 :(得分:5)

定义一个过滤器,用于跟踪记录的内容,并在循环期间将其附加到记录器。此示例将记住它看到的每条消息,并且只允许记录第一个匹配项。

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)

答案 1 :(得分:4)

“误用”functools lru_cache 是一个小技巧,但要容易得多。

from functools import lru_cache
from logging import getLogger

# Keep track of 10 different messages and then warn again
@lru_cache(10)
def warn_once(logger: Logger, msg: str):
    logger.warning(msg)

如果需要,您可以增加 10 以抑制更多,或将其设置为 None 以存储抑制所有重复的内容。

这个答案也完全满足了只抑制特定重复警告的要求,因为 logger.warning("message") 根本没有被过滤。

此外,此解决方案的内存效率更高,因为重复的日志不会多次保留在内存中。

答案 2 :(得分:2)

这是@chepner答案的修改后的变体。当记录的内容不是字符串(即异常)时,我遇到了一些问题,想使用上下文管理器更方便地添加和删除过滤器:

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)

用法:

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