为什么Python logging包不支持打印可变长度参数?
当我第一次学习Python的时候,我习惯这样做:
print "text", lineNumber, "some dictionary", my_dict
当我写自己的日志记录功能时,我自然想要能够处理任意大小的项目列表,所以我这样做了:
def error(*args):
print ERR_PREFIX,
for _x in args:
print _x,
print "\r\n",
error("text", lineNumber, "some dictionary", my_dict)
现在我想开始使用日志记录包,因为它有很多额外的功能,我不想重复他们的工作。总体来看,它的设计很干净,可以做很多事情。但是我遇到了一个问题,就是我不能再用之前的方式把同样的项目列表传给它来打印了。相反,我必须把所有的调用改成更像这样:
error("text %d some dictionary %s" % (lineNumber, my_dict))
或者,我可以做一些非常傻的事情,比如这样:
error(' '.join(map, str(("text", lineNumber, "some dictionary", my_dict))))
我的问题是,为什么会省略这么明显的用例?如果你想从普通的'print'语句直接转到这个新奇的日志记录功能,难道不应该更简单吗?
作为一个后续问题,你能想到一种方法来重写Logger类以实现这个功能吗?
5 个回答
1
你关于日志记录的说法并不完全正确。
log= logging.getLogger( "some.logger" )
log.info( "%s %d", "test", value )
log.error("text %d some dictionary %s", lineNumber, my_dict)
你不需要特别使用字符串格式化符号 %
。
编辑
你可以利用你原来的“错误”函数。
def error( *args ):
log.error( " ".join( map( str, args ) ) )
这样可能会让转换变得简单一些。
你也可以这样做。
class MyErrorMessageHandler( object ):
def __init__( self, logger ):
self.log= logger
def __call__( self, *args ):
self.log.error( " ".join( map( str, args ) ) )
error= MyErrorMessageHandler( logging.getLogger("some.name") )
这样也可能是个不错的选择。
2
修改日志包(就像某个答案建议的那样)其实并不是个好主意,因为这会导致其他代码(比如你没写的标准库里的代码)在调用 logging.error() 时无法正常工作。
相反,你可以把你现有的 error() 函数改成调用 logging.error() 或者直接打印信息:
def error(*args):
logging.error('%s', ' '.join(map(str, args)))
(如果可能会有 Unicode 对象,你需要稍微小心一点,但大概意思就是这样。)
7
我建议你最好把现有的日志信息更新成日志模块所期待的样式,这样其他人查看你的代码时会更容易理解,因为如果不这样做,日志模块就不会按他们的预期工作了。
说完这些,下面的代码可以让日志模块按照你想要的方式运行。
import logging
import types
class ExtendedLogRecord(logging.LogRecord):
def getMessage(self):
"""
Return the message for this LogRecord.
Return the message for this LogRecord after merging any user-supplied
arguments with the message.
"""
if not hasattr(types, "UnicodeType"): #if no unicode support...
msg = str(self.msg)
else:
try:
msg = str(self.msg)
except UnicodeError:
msg = self.msg #Defer encoding till later
if self.args:
msg +=' '+' '.join(map(str,self.args))
return msg
#Patch the logging default logging class
logging.RootLogger.makeRecord=lambda self,*args: ExtendedLogRecord(*args)
some_dict={'foo':14,'bar':15}
logging.error('text',15,'some dictionary',some_dict)
输出:
ERROR:root:text 15 some dictionary {'foo': 14, 'bar': 15}