Python:如何进行延迟调试日志记录

时间:2014-01-27 09:21:06

标签: python logging lazy-evaluation

我有一些像这样的python:

def foo():
    logger = logging.getLogger()
    # do something here
    logger.debug('blah blah {}'.format(expensive_func()))

foo()

其中expensive_func()是一个返回字符串的函数,执行起来很昂贵。

开发时,日志级别设置为DEBUG,expensive_func()执行,消息记录,一切正常。

问题在于,当我将日志级别设置为严格大于DEBUG(例如WARNING)时,在生产环境中,显然expensive_func()的返回值不会被记录,但昂贵的函数本身仍将被执行

我的问题是:当日志记录级别为WARNING时,如何防止python出现昂贵的函数?

我不想删除该调试行或在昂贵的函数中添加if level > DEBUG: return之类的东西。

感谢。

修改

我刚刚访问了Lazy logger message string evaluation,但对此并不满意,主要是因为:

  1. 这是一些丑陋的东西;
  2. 即使我用一些Lazy类包装昂贵的函数,当我有两个昂贵的函数时,我会怎么做? (如下所示)。
  3. class Lazy:
        def __init__(self, func, *a, **ka):
            self.func= func
            self.a = a
            self.ka= ka
        def __str__(self):
            return str(self.func(*self.a, **self.ka))
    
    # Though this is ugly, it works
    logger.debug('Message: %s', Lazy(expensive_func))
    
    # What if I wanted to do this?
    # logger.debug('Message: {}'.format(expf_1(expf_2(some_arg))))
    # Maybe I can modify class Lazy to make something like this to work
    # but it really doesn't feel right
    # logger.debug('Message: {}', Lazy(expf_1, Lazy(expf_2, some_arg)))
    

3 个答案:

答案 0 :(得分:8)

查看文档的this part

更新:日志记录已经支持延迟评估,但与您的文章中描述的方式略有不同。例如,请参阅以下脚本:

import logging

def expensive_func(*args):
    print('Expensive func called: %s' % (args,))
    return sum(args)

class DeferredMessage(object):
    def __init__(self, func, *args):
        self.func = func
        self.args = args

    def __str__(self):
        return 'Message {0}'.format(self.func(*self.args))

if __name__ == '__main__':
    logging.basicConfig()
    logging.info(DeferredMessage(expensive_func, 1, 2))
    logging.warning(DeferredMessage(expensive_func, 3, 4))
    logging.error(DeferredMessage(expensive_func, 5, 6))

运行上述脚本时,应该打印

Expensive func called: (3, 4)
WARNING:root:Message 7
Expensive func called: (5, 6)
ERROR:root:Message 11

表明只在必要时调用潜在的昂贵功能。当然,上面的示例可以通用化,以允许将格式字符串传递给DeferredMessage,并使用kwargs,等等。

答案 1 :(得分:5)

正如Vinay Sajip建议的那样,您可以执行以下操作:

def foo():
    logger = logging.getLogger()
    if logger.isEnabledFor(logging.DEBUG):
        logger.debug('blah blah {}'.format(expensive_func()))
        logger.debug('Message: {}'.format(expf_1(expf_2(some_arg))))
        logger.debug('Message: {}', Lazy(expf_1, Lazy(expf_2, some_arg)))
foo()

哪个已经懒了!

那是因为那时的表达式

        logger.debug('blah blah {}'.format(expensive_func()))
        logger.debug('Message: {}'.format(expf_1(expf_2(some_arg))))
        logger.debug('Message: {}', Lazy(expf_1, Lazy(expf_2, some_arg)))

仅在logger.isEnabledFor(logging.DEBUG)返回True时进行评估,即当且仅当评估需要时才会进行评估。


更多

logging.info(DeferredMessage(expensive_func, 1, 2))

并不像人们想象的那样懒惰DeferredMessage(expensive_func, 1, 2)必须以渴望的方式进行评估。这比评估更慢:

    if logger.isEnabledFor(logging.DEBUG):

答案 2 :(得分:0)

您可以使用stringlike库为您的消息添加懒惰

E.g:

logger.debug(
    'blah blah {value}'
    .format(
        value=LazyString(expensive_func)
    )
)

自由链接:https://github.com/CovenantEyes/py_stringlike