为什么Python logging包不支持打印可变长度参数?

2 投票
5 回答
6438 浏览
提问于 2025-04-15 11:21

当我第一次学习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}

撰写回答