如何静音模块的日志记录?

How to silence the logging of a module?

概述

我想使用 httpimport 作为多个脚本通用的日志记录库。这个模块会生成自己的日志,我不知道如何静音。

在其他情况下,例如这个,我会使用

logging.getLogger('httpimport').setLevel(logging.ERROR)

但是没有用。

详情

以下代码是上述"common logging code"的存根:

# toconsole.py

import logging
import os

log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s %(message)s')
handler_console = logging.StreamHandler()
level = logging.DEBUG if 'DEV' in os.environ else logging.INFO
handler_console.setLevel(level)
handler_console.setFormatter(formatter)
log.addHandler(handler_console)

# disable httpimport logging except for errors+
logging.getLogger('httpimport').setLevel(logging.ERROR)

简单的用法如

import httpimport

httpimport.INSECURE = True
with httpimport.remote_repo(['githublogging'], 'http://localhost:8000/') :
    from toconsole import log

log.info('yay!')

给出以下输出

[!] Using non HTTPS URLs ('http://localhost:8000//') can be a security hazard!
2019-08-25 13:56:48,671 yay!
yay!

第二个(裸)yay! 必须来自 httpimport,即来自其日志记录设置。

如何禁用此类模块的日志记录,或者更好 - 提高其级别以便仅记录错误+?


注意:这个问题 initially askedhttpimport 的 GitHub 存储库的问题部分,但作者也不知道如何解决这个问题。

发生这种情况的原因是,当您执行 import httpimport 时,他们会对日志机器进行初始配置。这种情况发生 right here。这意味着根记录器已经附加了一个 StreamHandler。正因为如此,以及所有记录器都继承自根记录器的事实,当您执行 log.info('yay') 时,它不仅会使用您的 HandlerFormatter,还会将它们传播到根记录器,它也发出消息。

请记住,在应用程序启动时首先调用 basicConfig 的人会设置根记录器的默认配置,除非另有说明,否则所有记录器都会继承该默认配置。

如果您有复杂的日志记录配置,您需要确保在执行任何可能调用 basicConfig 的第三方导入之前调用它。 basicConfig 幂等的 意味着第一次调用就完成了交易,后续调用无效。

解决方案

  1. 你可以做 log.propagate = False 你会发现第二个 yay 不会显示。
  2. 您可以通过执行类似的操作将 Formatter 直接附加到已经存在的根 Handler(无需自己添加另一个 Handler
root = logging.getLogger('')
formatter = logging.Formatter('%(asctime)s %(message)s')
root_handler = root.handlers[0]
root_handler.setFormatter(formatter)
  1. 您可以在初始化应用程序时执行 basicConfig 调用(如果您有这样的可用配置,初始 FormattersHandlers,等等。这将优雅地将所有内容整齐地附加到根记录器)然后你只会做像 logger = logging.getLogger(__name__)logger.info('some message') 这样的事情,它们会按照你期望的方式工作,因为它会一直传播到根记录器已经有了你的配置。

  2. 您可以通过执行

  3. 之类的操作来删除根记录器上存在的初始 Handler
root = logging.getLogger('')
root.handlers = []

...以及更多解决方案,但您明白了。

另请注意,logging.getLogger('httpimport').setLevel(logging.ERROR) 这非常有效。该记录器不会记录 logging.ERROR 以下的任何消息,只是问题不在于此。

如果你想完全禁用记录器,你可以做 logger.disabled = True(同样请注意,问题不是来自 httpimport 记录器,如前所述)

一个例子演示

用这个改变你的toconsole.py,你就不会看到第二个了。

import logging
import os

log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)

root_logger = logging.getLogger('')
root_handler = root_logger.handlers[0]
formatter = logging.Formatter('%(asctime)s %(message)s')
root_handler.setFormatter(formatter)

# or you could just keep your old code and just add log.propagate = False
# or any of the above solutions and it would work

logging.getLogger('httpimport').setLevel(logging.ERROR)

httpimport 的作者在这里。 我完全忘记了我正在使用 basicConfig logger 东西。

它现在已在 master 中修复 (0.7.2) - 将包含在下一个 PyPI 版本中: https://github.com/operatorequals/httpimport/commit/ff2896c8f666c3f16b0f27716c732d68be018ef7