如何在 python 日志记录中过滤标准输出
How to filter stdout in python logging
我正在使用库 'logging' 在我的脚本中记录信息和警告消息,我是否可以过滤掉密码(我有多个密码,希望将它们替换为星号)在打印到标准输出时?
为了从 stdout
流(logging.DEBUG
和 logging.INFO
消息所在的位置)和 stderr
流中过滤掉密码列表中包含的特定单词(这就是 logging.WARNING
、logging.ERROR
和 logging.CRITICAL
消息所在的位置),您可以用简单的 class 替换原始流,在写出之前替换关键词:
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: ******
过滤模式,不打印换行符
对@Dirk 过滤器的修改class。
此版本不会打印出与输入模式匹配的任何行。在跳过过滤行后,它也不会打印出换行符
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')
我正在使用库 'logging' 在我的脚本中记录信息和警告消息,我是否可以过滤掉密码(我有多个密码,希望将它们替换为星号)在打印到标准输出时?
为了从 stdout
流(logging.DEBUG
和 logging.INFO
消息所在的位置)和 stderr
流中过滤掉密码列表中包含的特定单词(这就是 logging.WARNING
、logging.ERROR
和 logging.CRITICAL
消息所在的位置),您可以用简单的 class 替换原始流,在写出之前替换关键词:
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: ******
过滤模式,不打印换行符
对@Dirk 过滤器的修改class。
此版本不会打印出与输入模式匹配的任何行。在跳过过滤行后,它也不会打印出换行符
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')