【问题标题】:Python disabled logging slowing scriptPython禁用了日志记录减慢脚本
【发布时间】:2022-01-18 20:30:57
【问题描述】:

我正在为我的脚本使用内置的 Python“日志记录”模块。当我将冗长转换为“信息”时,似乎我的“调试”消息显着降低了我的脚本速度。

我的一些“调试”消息会打印大型字典,我猜 Python 在实现“调试”消息被禁用之前会扩展文本。示例:

import pprint
pp = pprint.PrettyPrinter(indent=4)
logger.debug(f"Large Dict Object: {pp.pformat(obj)}")

如何提高我的表现?我更喜欢仍然使用 Python 的内置日志记录模块。但是需要想出一个“干净”的方法来解决这个问题。

【问题讨论】:

    标签: python python-3.x performance logging optimization


    【解决方案1】:

    dankal444提到的功能已经有a feature的日志记录了,稍微整洁一点:

    if logger.isEnabledFor(logging.DEBUG):
        logger.debug(f"Large Dict Object: {pp.pformat(obj)}")
    

    另一种可能的方法是使用 %-formatting,它只在实际需要时进行格式化(日志事件必须由处理程序和记录器处理才能到达该点)。我知道 f-strings 是新的(ish)热点并且是高性能的,但这一切都取决于确切的情况,哪个会提供最好的结果。

    利用惰性 %-formatting 的示例:

    class DeferredFormatHelper:
        def __init__(self, func, *args, *kwargs):
            self.func = func  # assumed to return a string
            self.args = args
            self.kwargs = kwargs
    
        def __str__(self):
            # This is called because the format string contains
            # a %s for this logging argument, lazily if and when
            # the formatting needs to happen
            return self.func(*self.args, **self.kwargs)
    
    if logger.isEnabledFor(logging.DEBUG):
        arg = DeferredFormatHelper(pp.pformat, obj)
        logger.debug('Large Dict Object: %s', arg)
    

    【讨论】:

    • 更懒惰的,因为如果需要的话,%-formatting 会在日志调用之后的某个时间应用。 f-string 格式化发生在日志调用之前,即使消息由于记录器或处理程序级别或过滤器阻止它而永远不会发出。
    • 我说的是例如logger.debug('foo %i', n) - 注意细微的差别。
    • 延迟的东西有意义吗,由if 保护?似乎如果你到达那里,你记录它。
    • 确实有道理。您将进行日志调用,但这并不一定意味着它将获得输出。你看过所有的文档吗?
    • 所以即使logger.isEnabledFor(logging.DEBUG) 为真,logger.debug 也可能没有记录?文档听起来像是后者恰恰意味着 logger.debug 确实记录了(虽然不,抱歉,页面很长,我没有全部阅读)。
    【解决方案2】:

    检查当前级别是否足够好:

    if logger.getEffectiveLevel() <= logging.DEBUG:
        logger.debug(f"Large Dict Object: {pp.pformact(obj)}")
        
    

    这不是超级干净,但我能想到的最好的。如果出现性能瓶颈,您只需要解决这个问题

    【讨论】:

      【解决方案3】:

      我无法验证您的瓶颈在哪里,但如果是因为 pprint 库,您的记录器将永远没有机会对此做任何事情。重写以澄清。

      from pprint import PrettyPrinter
      import logging
      
      logger = logging.getLogger()
      
      large_object = {"very": "large container"}
      pp = PrettyPrinter(indent=4)
      
      # This is done first.
      formatted_msg = pp.pformat(large_object)
      # It's already formatted when it's sent to your logger.
      logger.debug(f"Large dict object: {formatted_msg}")
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-31
        • 2015-02-23
        • 2014-07-16
        • 1970-01-01
        • 2012-01-06
        • 1970-01-01
        • 2013-06-06
        相关资源
        最近更新 更多