Python使用参数中的函数记录开销

时间:2015-07-26 09:24:24

标签: python logging

我正在使用python日志模块(python 3.4.3)。 假设我的日志记录级别设置为INFO,我想使用函数作为我的日志消息的参数。

现在我希望当日志级别降低(例如警告)时,不执行参数函数。

这是真的吗?

示例(控制台):

>>> import math
>>> import logging
>>> logging.basicConfig(level=logging.INFO)
>>> logging.debug('Factorial of 100000=',math.factorial(100000))
>>> */empty output but slightly delayed, small CPU peak/*
>>> logging.debug('Factorial of 10=',math.factorial(10))
>>> */empty output but instant, no noticeable CPU usage/*

该功能可能未执行,但仍有明显的延迟。有人可以解释我可能的原因吗?

2 个答案:

答案 0 :(得分:3)

调用之前的函数参数评估

logging.debug('Factorial of 100000=', math.factorial(100000)) 调用之前,您看到传递给logging.debug()的参数需要 评估 ,并且评估math.factorial(100000)需要时间

如果最终函数在调用中什么都不做,那么参数仍然会被评估

并不重要

从概念上讲,您可以将其视为正在进行

value = math.factorial(100000)           # This gets evaluated
logging.debug('Factorial is %d', value)  # Even if this is a "no op" call, 
                                         # the arg evaluation still takes place

解决方法

import math
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger()

if logger.getEffectiveLevel() <= logging.DEBUG:    # Or use == if you want DEBUG only
    logger.debug('Factorial is %d', math.factorial(100000))

使用Python 3&#39; logger.getEffectiveLevel()

鉴于水平按照

排序
CRITICAL    50
ERROR       40
WARNING     30
INFO        20
DEBUG       10
NOTSET      0

您可以看到我们的if块(包含<= logging.DEBUG)只会在DEBUG及更低版本上运行(因此DEBUGNOTSET

答案 1 :(得分:1)

问题是你在打电话之前评估了这个功能。解决这个问题的一种方法是使用bakkal描述的logger.getEffectiveLevel()。但这可能有点冗长。解决此问题的另一种方法是创建一个中间对象,以传递给执行其__str__函数工作的记录器。这会延迟函数调用,直到日志记录模块确定将发出消息。

例如:

import logging
import math

class CallableMsg:
    def __init__(self, func, *args, **kwargs):
        self.func = func
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        return str(self.func(*self.args, **self.kwargs))

logging.basicConfig(level=logging.INFO)

# single arg log
logging.info(CallableMsg(math.factorial, 10)) 
# using the CallableMsg in a format string
logging.info("10! = %s", CallableMsg(math.factorial, 10))
# factorial function never gets evaluated for the debug call
logging.debug(CallableMsg(math.factorial, 1000000))

如果出现错误,日志记录模块也足以保留实际进行日志调用的行。

logging.info(CallableMsg(math.factorial, -1))

输出:

--- Logging error ---
Traceback (most recent call last):
  File "C:\Python34\lib\logging\__init__.py", line 971, in emit
    msg = self.format(record)
  File "C:\Python34\lib\logging\__init__.py", line 821, in format
    return fmt.format(record)
  File "C:\Python34\lib\logging\__init__.py", line 558, in format
    record.message = record.getMessage()
  File "C:\Python34\lib\logging\__init__.py", line 319, in getMessage
    msg = str(self.msg)
  File "C:python\run.py", line 12, in __str__
    return str(self.func(*self.args, **self.kwargs))
ValueError: factorial() not defined for negative values
Call stack:
  File "<string>", line 1, in <module>
  File "C:\Python34\lib\idlelib\run.py", line 126, in main
    ret = method(*args, **kwargs)
  File "C:\Python34\lib\idlelib\run.py", line 353, in runcode
    exec(code, self.locals)
  File "C:\python\run.py", line 18, in <module>
    logging.info(CallableMsg(math.factorial, -1))
Message: <__main__.CallableMsg object at 0x02ECF970>
Arguments: ()