【问题标题】:How to filter stdout in python logging如何在 python 日志记录中过滤标准输出
【发布时间】:2016-04-26 14:07:12
【问题描述】:

我正在使用库'logging'在我的脚本中记录信息和警告消息,无论如何我可以在打印到标准输出时过滤掉密码(我有多个密码并希望用星号替换它们) ?

【问题讨论】:

  • 如何将“密码”发送到日志记录?
  • 要屏蔽的密码存储在一个列表中。
  • 您能否举例说明何时打印密码? (不要发布实际密码)

标签: python logging stdout


【解决方案1】:

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

对@Dirk 的过滤器类的修改。

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

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')

【讨论】:

    【解决方案2】:

    为了从stdout 流(logging.DEBUGlogging.INFO 消息所在的位置)和stderr 流(logging.WARNINGlogging.ERROR 所在的位置)中过滤掉密码列表中包含的特定单词和logging.CRITICAL messages go),您可以用一个简单的类替换原始流,该类在写出关键字之前替换它们:

    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]))
    

    输出将如下所示:

    DEBUG:__main__:You cannot see me anymore: **************
    INFO:__main__:You cannot see me anymore: ***********
    WARNING:__main__:You cannot see me anymore: *********
    ERROR:__main__:You cannot see me anymore: ***
    CRITICAL:__main__:You cannot see me anymore: ******
    

    【讨论】:

    • 这不适用于包含特殊正则表达式字符的字符串。此外,re.escape() 不应在 re.sub() 中使用。一个更简单的解决方案是在 write() 中使用new_string = len(string) * "*",然后使用data.replace(string, new_string)
    猜你喜欢
    • 2016-09-24
    • 2017-04-13
    • 2018-05-27
    • 1970-01-01
    • 2020-10-12
    • 1970-01-01
    • 2015-05-21
    • 2011-10-19
    • 1970-01-01
    相关资源
    最近更新 更多