懒惰的记录器消息字符串评估
我在我的python应用程序中使用标准的python日志记录模块:
import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger("log") while True: logger.debug('Stupid log message " + ' '.join([str(i) for i in range(20)]) ) # Do something
问题是,虽然调试级别未启用,但每次循环迭代都会评估该愚蠢的日志消息,这会严重影响性能。
有没有解决方案?
在C ++中,我们有提供如下宏的log4cxx
包:
LOG4CXX_DEBUG(logger, messasage)
这有效评估
if (log4cxx::debugEnabled(logger)) { log4cxx.log(logger,log4cxx::LOG4CXX_DEBUG, message) }
但是由于Python中没有宏(AFAIK),如果有一种有效的日志记录方式?
日志记录模块已经部分支持你想要做的事情。 做这个:
log.debug("Some message: a=%s b=%s", a, b)
...而不是:
log.debug("Some message: a=%s b=%s" % (a, b))
日志记录模块足够智能,不会产生完整的日志消息,除非消息实际上被记录在某处。
要将此功能应用于您的特定请求,您可以创建一个lazyjoin类。
class lazyjoin:
def __init__(self, s, items):
self.s = s
self.items = items
def __str__(self):
return self.s.join(self.items)
像这样使用它(注意使用生成器表达式,增加懒惰):
logger.info('Stupid log message %s', lazyjoin(' ', (str(i) for i in range(20))))
这是一个展示这些作品的演示。
>>> import logging
>>> logging.basicConfig(level=logging.INFO)
>>> logger = logging.getLogger("log")
>>> class DoNotStr:
... def __str__(self):
... raise AssertionError("the code should not have called this")
...
>>> logger.info('Message %s', DoNotStr())
Traceback (most recent call last):
...
AssertionError: the code should not have called this
>>> logger.debug('Message %s', DoNotStr())
>>>
在演示中,logger.info()调用会触发断言错误,而logger.debug()没有达到那么远。
当然,以下内容不如宏观效率高:
if logger.isEnabledFor(logging.DEBUG):
logger.debug(
'Stupid log message ' + ' '.join([str(i) for i in range(20)])
)
但很简单,以懒惰的方式评估, 比接受的答案快4倍 :
class lazyjoin:
def __init__(self, s, items):
self.s = s
self.items = items
def __str__(self):
return self.s.join(self.items)
logger.debug(
'Stupid log message %s', lazyjoin(' ', (str(i) for i in range(20)))
)
请参阅我的设置的benchmark-src。
import logging
import time
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("log")
class Lazy(object):
def __init__(self,func):
self.func=func
def __str__(self):
return self.func()
logger.debug(Lazy(lambda: time.sleep(20)))
logger.info(Lazy(lambda: "Stupid log message " + ' '.join([str(i) for i in range(20)])))
# INFO:log:Stupid log message 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
如果您运行该脚本,您会注意到第一个logger.debug
命令不需要20秒即可执行。 这表明当日志记录级别低于设置级别时,不会评估参数。