I'm using library 'logging' to log info and warning messages in my scripts, is there anyway I can filter out passwords (I have more than one passwords and would like to get them replaced with asterisks) while printing into stdout?
In order to filter out specific words contained in your password list from the stdout
stream (that's where logging.DEBUG
and logging.INFO
messages go) and the stderr
stream (that's where logging.WARNING
, logging.ERROR
and logging.CRITICAL
messages go), you can replace the original streams with a simple class that replaces the critical words before writing them out:
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()
Replace the original streams with the filtered ones like that:
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)
Now, set up logging and write some log messages:
# 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]))
The output will look like this:
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: ******
A modification to @Dirk's Filter class.
This version will not print out any line which matches the input pattern. It will also not print out a newline break after a filtered line has been skipped
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')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With