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


100

我正在使用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-如何忽略导入的模块日志?

Answers:


69

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

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

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

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


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

在“高级日志记录教程”中对此进行了提及。它还允许您以简单的方式知道哪个模块触发了日志消息。


36
我正在用__name__r创建一个记录器,但仍然可以看到导入模块的日志。我正在尝试使用ini配置文件配置日志记录,我该怎么办?
杜尔加·斯瓦鲁普

8
使用创建记录器__name__对我也不起作用。也许是因为我使用的是独立脚本而不是“模块”?对我有用的是matpplotlib通过logging.getLogger("matplotlib").setLevel(logging.WARNING)和为我的脚本配置导入模块的日志记录(以我为例)logging.basicConfig
bli

1
我只是想强调“显然,您必须使用logger.debug而不是logging.debug”这一行的价值。使用日志记录而不是记录器是一个容易犯的错误,但它会篡改您要设置的所有聪明配置。我已经花了最后几个小时住在这里!
timdadev

@bli开发库与开发可执行文件之间的日志记录有很大的不同。基本上是:如果你正在写一个模块/包其目的是要导入你应该没有任何配置。该模块应仅包含logger = logging.getLogger('package.my_module')和您可以调用logger.debug/warning,不得配置日志记录级别或处理程序。当您编写二进制应用程序时应确定各种日志和处理程序的级别。包含日志记录配置的库始终是一个问题。
Bakuriu

就我而言,我导入的包使用根记录器(通过logging.info)。有什么方法可以专门禁用此程序包中的根日志吗?
IanS

45

如果要使用pythonlogging包,则通常会在使用它的每个模块中定义一个记录器。

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)

15
请注意,当您尝试像在官方基本教程中那样配置记录器时,logging.basicConfig(...)所有记录器现在都将输出到logging.lastResort(未提供处理程序)(从Python 3.2开始,为stderr)(如果未指定处理程序)或您设置的处理程序。因此,请不要使用它,否则您将继续获取所有日志消息。
user136036 '18

43

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

尽管遵循了日志记录高级教程故障排除中非常简单的文档,但我还是从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():
  ...

我收到错误消息:“记录器”对象没有属性“ DEBUG”。 logger.DEBUG应该是logging.DEBUG
foxiris

谢谢!真的有帮助!我在主要日志记录配置之后和将导入matplotlib的命令之前设置了matplotlib日志记录级别。解决了!
gph

我已经为设置日志记录matplotlibWARNING 我已经导入模块,因为进口将给予绒的错误之前添加。它仍然为我工作。matplotlib==3.3.2如果有帮助,我正在Python 3.7中使用。
-2

9

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

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


9

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

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

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

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


你有什么问题?
user1767754

1
request例如,这有效,但是当导入的模块在您稍后将要调用的类中创建记录器时,它将无法工作,就像APScheduler您调用时所做的那样BackgroundScheduler.BackgroundScheduler()。解决方案请参见此处:stackoverflow.com/a/48891485/2441026
user136036

这适用于我使用yaml配置文件的情况
user4015990

4

您可以使用类似:

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__


1

我有同样的问题。我有一个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并声明一个新的记录器,并将其级别设置为debug:

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

这样,我登录py文件中的所有内容都会被记录下来,但是不会记录由urllib,request,boto3等导入模块在调试和信息级别记录的内容。如果这些导入模块中存在某些错误,则将其记录下来,因为我将根记录程序级别设置为ERROR。


0

另一个要考虑的是繁殖Logger类的属性。

例如,用于处理肥皂呼叫的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的模块的日志大量的日志

在此处输入图片说明

因为默认情况下日志的传播为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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.