ChatGPT解决这个技术问题 Extra ChatGPT

Python Logging - 禁用导入模块的日志记录

我正在使用 Python 日志记录模块,并希望禁用由我导入的第三方模块打印的日志消息。例如,我正在使用如下内容:

logger = logging.getLogger()
logger.setLevel(level=logging.DEBUG)
fh = logging.StreamHandler()
fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
fh.setFormatter(fh_formatter)
logger.addHandler(fh)

这会在我执行 logger.debug("my message!") 时打印出我的调试消息,但它也会从我导入的任何模块(例如请求和许多其他内容)中打印出调试消息。

我只想查看我感兴趣的模块的日志消息。是否可以让日志模块执行此操作?

理想情况下,我希望能够告诉记录器打印来自“ModuleX,ModuleY”的消息并忽略所有其他消息。

我查看了以下内容,但我不想在每次调用导入函数之前禁用/启用日志记录:logging - how to ignore imported module logs?


w
wisbucky

问题是不带参数调用 getLogger 会返回 root 记录器,因此当您将级别设置为 logging.DEBUG 时,您也在为使用该记录器的其他模块设置级别。

您可以通过简单地不使用根记录器来解决这个问题。为此,只需将名称作为参数传递,例如模块的名称:

logger = logging.getLogger('my_module_name')
# as before

这将创建一个新的记录器,因此它不会无意中更改其他模块的日志记录级别。

显然,您必须使用 logger.debug 而不是 logging.debug,因为后者是调用根记录器的 debug 方法的便捷函数。

Advanced Logging Tutorial 中提到了这一点。它还允许您以简单的方式知道哪个模块触发了日志消息。


我正在使用 __name__ r 创建一个记录器,但我仍然看到来自导入模块的日志。我正在尝试使用 ini 配置文件配置日志记录。我应该怎么做?
使用 __name__ 创建记录器对我也不起作用。也许是因为我使用的是独立脚本而不是“模块”?对我有用的是通过 logging.getLogger("matplotlib").setLevel(logging.WARNING) 为导入的模块(在我的情况下为 matpplotlib)配置日志记录,并通过 logging.basicConfig 为我的脚本配置日志记录。
我只是想强调您的行“显然您必须使用 logger.debug 而不是 logging.debug”的价值。使用 logging 而不是 logger 是一个容易犯的错误,但它篡夺了您想要设置的所有巧妙配置。我已经度过了最后几个小时的生活!
我不知道为什么这在 python 中如此困难。这是可悲的
@IanS 不,这就是库应该使用根记录器的原因。请打开该库的错误报告并告诉他们改用 logging.getLogger(__name__)
T
Tomerikoo

不确定这是否适合发布,但我被困了很长时间并想帮助任何有同样问题的人,因为我在其他任何地方都没有找到它!

尽管遵循了 logging advanced tutorialtroubleshooting 中非常简单的文档,但我还是从 matplotlib 获取调试日志。我在一个文件的 main() 中启动我的记录器并导入一个函数以从另一个文件(我已导入 matplotlib)创建一个绘图。

对我有用的是在导入 matplotlib 之前设置它的级别,而不是像我在主文件中的其他模块那样设置它之后。这对我来说似乎违反直觉,所以如果有人了解如何为尚未导入的记录器设置配置,我很想知道它是如何工作的。谢谢!

在我的主文件中:

import logging
import requests
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logging.getLogger('requests').setLevel(logging.DEBUG)

def main():
  ...

在我的 plot.py 文件中:

import logging
logging.getLogger('matplotlib').setLevel(logging.WARNING)
import matplotlib.pyplot as plt

def generatePlot():
  ...

我收到错误:“记录器”对象没有属性“调试”。 logger.DEBUG 应该是 logging.DEBUG
谢谢!这真的很有帮助!我在我的主要日志配置之后和将导入 matplotlib 的命令之前设置了 matplotlib 日志级别。解决了!
我已将 matplotlib 的日志记录设置为 WARNING 在导入模块之后,因为在导入之前添加它会产生 lint 错误。它仍然对我有用。如果有帮助,我将在 Python 3.7 中使用 matplotlib==3.3.2
B
Brendan Abel

如果您要使用 python logging 包,在每个使用它的模块中定义一个记录器是一个常见的约定。

logger = logging.getLogger(__name__)

许多流行的 python 包都这样做,包括 requests。如果包使用此约定,则很容易为其启用/禁用日志记录,因为记录器名称将与包相同(或将是该记录器的子级)。您甚至可以将其记录到与其他记录器相同的文件中。

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

requests_logger = logging.getLogger('requests')
requests_logger.setLevel(logging.DEBUG)

handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
logger.addHandler(handler)
requests_logger.addHandler(handler)

请注意,当您尝试使用 logging.basicConfig(...) 像在官方基础教程中那样配置您的记录器时,如果没有给定处理程序或处理程序,所有记录器现在将输出到 logging.lastResort(从 Python 3.2 开始,即 stderr)你设置。所以不要使用它,否则您将继续收到所有日志消息。
u
user1717828

这将禁用所有现有记录器,例如由导入模块创建的记录器,同时仍使用根记录器(并且无需加载外部文件)。

import logging.config
logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': True,
})

请注意,您需要先导入所有不想记录的模块!否则,这些将不会被视为“现有记录器”。然后它将禁用这些模块中的所有记录器。这可能会导致您也错过重要的错误!

有关使用相关配置选项的更详细示例,请参阅 https://gist.github.com/st4lk/6287746here 是使用 YAML 和 coloredlog 库进行配置的(部分工作)示例。


例如,这适用于 request,但当导入的模块在您稍后调用的类中创建其记录器时,它将不起作用,就像您调用 BackgroundScheduler.BackgroundScheduler()APScheduler 所做的那样。请参阅此处获取解决方案:stackoverflow.com/a/48891485/2441026
这适用于我的 yaml 配置文件
请注意,您必须import logging.config,而不仅仅是记录。
如果导入的模块最初有一个处理程序或其他东西,这是否也会禁用这些处理程序?
a
apex-meme-lord

@Bakuriu 非常优雅地解释了该功能。相反,您可以使用 getLogger() 方法来检索和重新配置/禁用不需要的记录器。

我还想添加 logging.fileConfig() 方法接受一个名为 disable_existing_loggers 的参数,它将禁用以前定义的任何记录器(即,在导入的模块中)。


K
Kamiku

你可以使用类似的东西:

logging.getLogger("imported_module").setLevel(logging.WARNING)
logging.getLogger("my_own_logger_name").setLevel(logging.DEBUG)

这会将我自己的模块的日志级别设置为 DEBUG,同时防止导入的模块使用相同的级别。

注意:"imported_module" 可以替换为 imported_module.__name__(不带引号),如果您愿意,"my_own_logger_name" 可以替换为 __name__


E
Eduardo Davalos

在此线程和其他论坛中尝试了各种答案后,我发现这种方法可以有效地使其他模块的记录器静音。这是受到以下链接的启发:

https://kmasif.com/2019-11-12-ignore-logging-from-imported-module/

import logging
# Initialize your own logger
logger = logging.getLogger('<module name>')
logger.setLevel(logging.DEBUG)

# Silence other loggers
for log_name, log_obj in logging.Logger.manager.loggerDict.items():
     if log_name != '<module name>':
          log_obj.disabled = True

请注意,您可能希望在导入其他模块后执行此操作。但是,我发现这是禁用其他模块记录器的一种方便快捷的方法。


A
Aseem

我有同样的问题。我有一个 logging_config.py 文件,我将它导入到所有其他 py 文件中。在 logging_config.py 文件中,我将 root logger 日志记录级别设置为 ERROR(默认情况下是警告):

logging.basicConfig(
    handlers=[
        RotatingFileHandler('logs.log',maxBytes=1000, backupCount=2),
        logging.StreamHandler(), #print to console
    ],
    level=logging.ERROR
)

在其他模块中,我导入 logging_config.py 并声明一个新记录器并将其级别设置为调试:

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

这样,我在我的 py 文件中登录的所有内容都会被记录,但不会记录由导入的模块(如 urllib、request、boto3 等)在调试和信息级别记录的内容。如果这些导入模块中有一些错误,那么它会被记录下来,因为我将根记录器级别设置为错误。


M
MaxCode

只需执行以下操作即可解决问题:

logging.config.dictConfig({'disable_existing_loggers': True,})

注意:无论您将这一行放在哪里,请确保项目中所有位置的所有导入都在该文件本身内完成。 :)


AttributeError:模块“日志记录”没有属性“配置”
@ciurlaro:导入 logging.config
A
Andrea Bisello

要考虑的另一件事是 Logger 类的 propagate 属性。

例如,用于处理soap调用的py-suds库,甚至放到ERROR

logging.getLogger('suds.client').setLevel(logging.ERROR)
logging.getLogger('suds.transport').setLevel(logging.ERROR)
logging.getLogger('suds.xsdschema').setLevel(logging.ERROR)
logging.getLogger('suds.wsdl').setLevel(logging.ERROR)

记录有关名为 sxbasics.py 的模块的日志创建大量日志

https://i.stack.imgur.com/CoLUb.png

那是因为日志的传播默认为 True,设置为 False,相反,我恢复了 514MB 的日志。

import logging
logging.getLogger("suds").propagate = False
logging.getLogger('suds.client').setLevel(logging.ERROR)
logging.getLogger('suds.transport').setLevel(logging.ERROR)
logging.getLogger('suds.xsdschema').setLevel(logging.ERROR)
logging.getLogger('suds.wsdl').setLevel(logging.ERROR)

l
loki

@brendan's answer 的启发,我创建了一个简单的 logger_blocklist,我可以在其中添加我想要提高级别的所有记录器。因此,我能够一次将它们全部静音:

import logging

logging.basicConfig(level=logging.DEBUG)

logger_blocklist = [
    "fiona",
    "rasterio",
    "matplotlib",
    "PIL",
]

for module in logger_blocklist:
    logging.getLogger(module).setLevel(logging.WARNING)

您可以从 format="%(name)s" 参数中找到记录器的名称,该参数也包含在 logging.basicConfig() 中,例如:DEBUG:matplotlib.font_manager:findfont: score(FontEntry(fname='/usr/share/fonts/truetype/ubuntu/Ubuntu-R.ttf', name='Ubuntu', style='normal', variant='normal', weight=400, stretch='normal', size='scalable')) = 10.05

在这种情况下,您希望将记录器 matplotlib 添加到您的阻止列表中。

@Finn's answer 不同,它没有必要放在 main() 之外,等等。