如何在python日志记录中过滤stdout

时间:2016-01-20 16:10:26

标签: python logging stdout

我正在使用图书馆'伐木'在我的脚本中记录信息和警告消息,无论如何我可以在打印到stdout时过滤掉密码(我有多个密码,并希望用星号代替)?

2 个答案:

答案 0 :(得分:2)

为了过滤掉stdout信息流中包含的特定字词(logging.DEBUGlogging.INFO信息的去处)和{{1} } stream(stderrlogging.WARNINGlogging.ERROR消息的位置),您可以使用一个简单的类替换原始流,该类在写出之前替换关键字:

logging.CRITICAL

将原始流替换为过滤后的原始流:

class PasswordFilter(object):
    def __init__(self, strings_to_filter, stream):
        self.stream = stream
        self.strings_to_filter = strings_to_filter

    def __getattr__(self, attr_name):
        return getattr(self.stream, attr_name)

    def write(self, data):
        for string in self.strings_to_filter:
            data = re.sub(r'\b{0}\b'.format(string), '*' * len(string), data)
        self.stream.write(data)
        self.stream.flush()

    def flush(self):
        self.stream.flush()

现在,设置日志记录并写一些日志消息:

top_secret_passwords = ['do not tell me', 'I am secret', 'important', 'foo',
                        'foobar']
sys.stdout = PasswordFilter(top_secret_passwords, sys.stdout)
sys.stderr = PasswordFilter(top_secret_passwords, sys.stderr)

输出将如下所示:

# set up your logging after activating the filter, won't work otherwise
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

logger.debug('You cannot see me anymore: {0}'.format(top_secret_passwords[0]))
logger.info('You cannot see me anymore: {0}'.format(top_secret_passwords[1]))
logger.warning('You cannot see me anymore: {0}'.format(top_secret_passwords[2]))
logger.error('You cannot see me anymore: {0}'.format(top_secret_passwords[3]))
logger.critical('You cannot see me anymore: {0}'.format(top_secret_passwords[4]))

答案 1 :(得分:2)

过滤掉模式,而不打印换行符

对@Dirk的Filter类的修改。

此版本不会打印出与输入模式匹配的任何行。跳过过滤的行后,它也不会打印出换行符

class Filter(object):
    def __init__(self, stream, re_pattern):
        self.stream = stream
        self.pattern = re.compile(re_pattern) if isinstance(re_pattern, str) else re_pattern
        self.triggered = False

    def __getattr__(self, attr_name):
        return getattr(self.stream, attr_name)

    def write(self, data):
        if data == '\n' and self.triggered:
            self.triggered = False
        else:
            if self.pattern.search(data) is None:
                self.stream.write(data)
                self.stream.flush()
            else:
                # caught bad pattern
                self.triggered = True

    def flush(self):
        self.stream.flush()

# example
sys.stdout = Filter(sys.stdout, r'Read -1')  # filter out any line which contains "Read -1" in it


# No lines (or newline breaks) will be printed to stdout after running the below.
for _ in range(10):
  print('Read -1 expected 4096')