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

时间:2016-02-10 20:17:05

标签: 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("我的消息!")时会打印出我的调试消息,但它也会打印出我导入的任何模块的调试消息(例如请求和a其他事情的数量。)

我希望只看到我感兴趣的模块的日志消息。是否可以让日志记录模块执行此操作?

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

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

11 个答案:

答案 0 :(得分:36)

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

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

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

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

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

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

答案 1 :(得分:24)

如果你要使用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)

答案 2 :(得分:11)

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

尽管遵循了非常简单的文档,但我还是从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(logger.DEBUG)

def main():
  ...

在我的plot.py文件中:

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

def generatePlot():
  ...

答案 3 :(得分:7)

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

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

答案 4 :(得分:2)

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

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

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

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

答案 5 :(得分:2)

您可以使用类似的内容:

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__代替,如果那样的话。

答案 6 :(得分: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并声明一个新的记录器,并将其级别设置为调试:

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

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

答案 7 :(得分:1)

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

例如,用于处理肥皂呼叫的py-suds库,甚至置于错误状态

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)

logs记录有关名为sxbasics.py creation的模块的日志,其中包含大量日志

enter image description here

因为默认情况下日志的传播为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)

答案 8 :(得分:1)

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

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

注意:无论您在哪里放置此行,请确保项目中所有地方的所有导入均在该文件本身内完成。 :)

答案 9 :(得分:1)

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

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

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

答案 10 :(得分:0)

在我看来,唯一有用的方法是将不需要的记录器的propagate属性强制设置为False,即

logging.getLogger("module").propagate = False

如果结果为false,则不会将日志记录消息传递给祖先记录程序的处理程序。