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

bli*_*ile 61 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)
Run Code Online (Sandbox Code Playgroud)

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

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

理想情况下,我希望能够告诉记录器从"ModuleX,ModuleY"打印消息并忽略所有其他消息.

我查看了以下内容,但我不想在每次调用导入函数之前禁用/启用日志记录: logging - 如何忽略导入的模块日志?

Bak*_*riu 46

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

您可以通过使用根记录器来解决此问题.要执行此操作,只需将名称作为参数传递,例如模块的名称:

logger = logging.getLogger('my_module_name')
# as before
Run Code Online (Sandbox Code Playgroud)

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


显然你必须使用logger.debug而不是logging.debug因为后者是一个调用debug根记录器方法的便利函数.

高级日志教程中提到了这一点.它还允许您以简单的方式知道哪个模块触发了日志消息.

  • 我正在使用`__name__` r创建一个记录器,但我仍然可以看到导入模块的日志.我正在尝试使用ini配置文件配置日志记录.我该怎么做? (17认同)
  • 使用“__name__”创建记录器对我来说也不起作用。也许是因为我使用的是独立脚本而不是“模块”?对我有用的是通过“logging.getLogger("matplotlib").setLevel(logging.WARNING)”为导入的模块(在我的例子中为“matpplotlib”)配置日志记录,并通过“logging.basicConfig”为我的脚本配置日志记录。 (14认同)
  • 我不知道为什么这在Python中如此困难。这是可悲的 (5认同)
  • @IanS 不,这就是为什么库不应该**使用根记录器。请向该库打开错误报告,并告诉他们使用“logging.getLogger(__name__)”代替。 (5认同)
  • 我只是想强调你的行“显然你必须使用`logger.debug`而不是`logging.debug`”的价值。使用 _logging_ 而不是 _logger_ 是一个很容易犯的错误,但它会取代您想要设置的所有巧妙配置。我在过去的几个小时里就过着这样的生活! (4认同)

Bre*_*bel 34

如果你打算使用python logging包,那么在每个使用它的模块中定义一个记录器是一种常见的约定.

logger = logging.getLogger(__name__)
Run Code Online (Sandbox Code Playgroud)

许多流行的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)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,当您尝试使用`logging.basicConfig(...)`在官方基础教程中配置您的记录器时,所有记录器现在都将输出到`logging.lastResort`(从Python 3.2开始,这是stderr)如果没有给出处理程序或你设置的处理程序.所以不要使用它,否则你将继续获取所有日志消息. (10认同)

小智 22

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

我从matplotlib获取调试日志,尽管在https://docs.python.org/3.5/howto/logging.html#logging-advanced-tutorialhttps://matplotlib.org/faq/troubleshooting_faq上提供了相当简单的文档 . HTML.我在一个文件的main()中启动我的记录器并导入一个函数来从另一个文件创建一个图(我导入了matplotlib).

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

在我的主文件中:

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

def main():
  ...
Run Code Online (Sandbox Code Playgroud)

在我的plot.py文件中:

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

def generatePlot():
  ...
Run Code Online (Sandbox Code Playgroud)

  • 我收到错误:“Logger”对象没有属性“DEBUG”。`logger.DEBUG` 应该是 `logging.DEBUG` (2认同)
  • 在导入模块之后,我将 `matplotlib` 的日志记录设置为 `W​​ARNING`,因为在导入之前添加它会产生 lint 错误。它仍然对我有用。如果有帮助的话,我在 Python 3.7 中使用“matplotlib==3.3.2”。 (2认同)

avv*_*avv 17

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

import logging.config
logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': True,
})
Run Code Online (Sandbox Code Playgroud)

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

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

  • 例如,这适用于 `request`,但当导入的模块在您稍后调用的类中创建它们的记录器时,它将不起作用,就像调用 `BackgroundScheduler.BackgroundScheduler()` 时的 `APScheduler` 一样。请参阅此处以获取解决方案:/sf/answers/3422403981/ (2认同)

小智 16

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

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

Run Code Online (Sandbox Code Playgroud)

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

  • 我使用了这个,而不是禁用logging.getLogger(log_name).setLevel(logging.WARNING) (3认同)

小智 8

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

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


lok*_*oki 8

受到@brendan的回答的启发,我创建了一个简单的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)
Run Code Online (Sandbox Code Playgroud)

您可以从参数中找到记录器的名称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的答案相反,没有必要把它放在外面main(),等等。


小智 6

你可以使用类似的东西:

logging.getLogger("imported_module").setLevel(logging.WARNING)
logging.getLogger("my_own_logger_name").setLevel(logging.DEBUG)
Run Code Online (Sandbox Code Playgroud)

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

注意: "imported_module"可以替换为imported_module.__name__(不带引号),如果您喜欢这样做,"my_own_logger_name"可以替换为__name__


归档时间:

查看次数:

33647 次

最近记录:

6 年,4 月 前