Source code for semantic_release.cli.masking_filter
from__future__importannotationsimportloggingimportrefromcollectionsimportdefaultdictfromtypingimportIterablelog=logging.getLogger(__name__)# https://relaxdiego.com/2014/07/logging-in-python.html# Updated/adapted for Python3
[docs]defadd_mask_for(self,data:str,name:str="redacted")->MaskingFilter:ifdataanddatanotinself._UNWANTED:log.debug("Adding redact pattern %r to _redact_patterns",name)self._redact_patterns[name].add(data)returnself
[docs]deffilter(self,record:logging.LogRecord)->bool:# Note if we blindly mask all types, we will actually cast arguments to# log functions from external libraries to strings before they are# formatted into the message - for example, a dependency calling# log.debug("%d", 15) will raise a TypeError as this filter would# otherwise convert 15 to "15", and "%d" % "15" raises the error.# One may find a specific example of where this issue could manifest itself# here: https://github.com/urllib3/urllib3/blob/a5b29ac1025f9bb30f2c9b756f3b171389c2c039/src/urllib3/connectionpool.py#L1003# Anything which could reasonably be expected to be logged without being# cast to a string should be excluded from the cast here.record.msg=self.mask(record.msg)ifrecord.argsisNone:passelifisinstance(record.args,dict):record.args={k:viftype(v)in(bool,int,float)elseself.mask(str(v))fork,vinrecord.args.items()}else:record.args=tuple(argiftype(arg)in(bool,int,float)elseself.mask(str(arg))forarginrecord.args)returnTrue
[docs]defmask(self,msg:str)->str:ifnotisinstance(msg,str):log.debug(# type: ignore[unreachable]"cannot mask object of type %s",type(msg))returnmsgformask,valuesinself._redact_patterns.items():repl_string=(self.REPLACE_STRifnotself._use_named_maskselsef"<{mask!r} (value removed)>")fordatainvalues:ifisinstance(data,str):msg=msg.replace(data,repl_string)elifisinstance(data,re.Pattern):msg=data.sub(repl_string,msg)returnmsg