为什么python日志包不支持打印变长args?

时间:2009-05-01 17:44:04

标签: 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))))

问题是,为什么省略这样一个明显的用例?如果你想从典型的“打印”声明直接转到新的日志记录设施,这不应该更容易吗?

作为后续问题,您能想到一种覆盖Logger类来执行此操作的方法吗?

5 个答案:

答案 0 :(得分: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}

答案 1 :(得分:2)

修补日志包(建议作为一个答案)实际上是一个坏主意,因为这意味着其他代码(您没有编写,例如标准库中的内容)调用日志记录.error()将无法正常工作。

相反,您可以更改现有的error()函数来调用logging.error(),或者打印:

def error(*args):
  logging.error('%s', ' '.join(map(str, args)))

(如果可能有unicode对象,你需要更加小心,但是你明白了。)

答案 2 :(得分: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") )

也可能是适口的。

答案 3 :(得分:0)

嗯,打印和记录是两回事。按理说,这样他们的用法可能也会有很大不同。

答案 4 :(得分:0)

add a method to a class动态相对容易。为什么不将您的方法添加到Logging。