Use logging.Filter!
DuplicateFilter accepts two regex patterns or a string (which should be compiled into one) that should match the string you want to filter and you want to reset the filter to.
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!')
This is the resulting log:
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!
Only the "5 more generated" pending messages are probably not what you want, but hopefully this is a good starting point.
source
share