我在我的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
问题是虽然调试级别未启用,但是在每次循环迭代时都会评估该愚蠢的日志消息,这会严重损害性能 .
Is there any solution for this?
在C中我们有 log4cxx
包,提供如下宏:LOG4CXX_DEBUG(logger, messasage)
这有效地评估为
if (log4cxx::debugEnabled(logger)) {
log4cxx.log(logger,log4cxx::LOG4CXX_DEBUG, message)
}
但是由于Python(AFAIK)中没有宏,是否有一种有效的记录方法?
5 回答
如果运行该脚本,您会注意到第一个
logger.debug
命令执行时间不超过20秒 . 这表示当日志记录级别低于设置级别时,不会计算参数 .日志记录模块已经部分支持您要执行的操作 . 做这个:
......而不是这个:
日志记录模块足够智能,不会产生完整的日志消息,除非消息实际记录在某处 .
要将此功能应用于您的特定请求,您可以创建一个lazyjoin类 .
像这样使用它(注意使用生成器表达式,增加了懒惰):
这是一个显示此工作的演示 .
在演示中,logger.info()调用命中了断言错误,而logger.debug()没有达到那么远 .
当然,以下内容不如宏有效:
但很简单,evaluates in lazy fashion并且是 4 times faster than the accepted answer :
有关我的设置,请参阅benchmark-src .
正如Shane指出的那样,使用
......而不是这个:
如果实际记录了消息,则仅通过执行字符串格式化来节省一些时间 .
但是,这并不能完全解决问题,因为您可能需要预先处理值以格式化为字符串,例如:
在这种情况下,即使没有记录,也会计算
obj.get_a()
和obj.get_b()
.解决方法是使用lambda函数,但这需要一些额外的机制:
...然后您可以使用以下内容进行登录:
在这种情况下,只有
log.debug
决定执行格式化时才会调用lambda函数,因此调用__str__
方法 .请注意:该解决方案的开销可能会超出收益:-)但至少在理论上,它可以完成完全懒惰的日志记录 .
我在场,
Lazyfy
:用法:
原来的例子:
如您所见,这也涵盖了另一个使用lambda函数的答案,但使用了
value
属性和扩展的更多内存 . 但是,它可以节省更多内存:Usage of slots?最后,到目前为止,最有效的解决方案仍然是以下建议另一个答案: