首页 > 解决方案 > 如何使模块的日志记录静音?

问题描述

概述

我想httpimport用作几个脚本通用的日志库。该模块生成自己的日志,我不知道如何使其静音。

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

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

但它没有用。

细节

下面的代码是上面提到的“通用日志代码”的一个存根:

# 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,即来自其日志记录设置。

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


注意:这个问题最初是在 GitHub 存储库的问题部分提出的,httpimport但作者也不知道如何解决这个问题。

标签: pythonpython-3.xloggingpython-import

解决方案


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

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

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

解决方案

  1. 你可以这样做log.propagate = False,你会看到第二个 yay 不会显示。
  2. 您可以通过执行类似这样的操作将其Formatter直接附加到已经存在的根(无需自己添加另一个)HandlerHandler
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. 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)

推荐阅读