【问题标题】:No handlers could be found for logger找不到记录器的处理程序
【发布时间】:2017-10-26 13:29:45
【问题描述】:

我是 python 的新手。我正在尝试登录 python,但在尝试通过记录器实例打印一些警告时遇到 No handlers could be found for logger 错误。下面是我试过的代码

import logging
logger=logging.getLogger('logger')
logger.warning('The system may break down')

我收到此错误找不到记录器“记录器”的处理程序

让我感到困惑的是,当我第一次尝试使用 logging 然后通过 logger 打印警告时,它工作正常,就像

>>> import logging
>>> logging.warning('This is a WARNING!!!!')
WARNING:root:This is a WARNING!!!!
>>> 
>>> logger.warning('WARNING!!!!')
WARNING:logger:WARNING!!!!

有人可以对第二种情况下发生的事情有所了解吗?

【问题讨论】:

标签: python logging handler


【解决方案1】:

调用logging.basicConfig()

>>> import logging
>>> logging.basicConfig()
>>> logger = logging.getLogger('logger')
>>> logger.warning('The system may break down')
WARNING:logger:The system may break down

【讨论】:

  • 感谢分享!但我只是想知道为什么它在第二种情况下有效......
  • 因为如果未配置日志记录,logging.warning() 会调用 logging.basicConfig()
  • 除此之外,如果您还想添加信息日志,您可能需要将级别设置为 info logger.setLevel(logging.INFO)
【解决方案2】:

为了通过logger 记录一些消息,在Python 中,至少应将一个处理程序添加到logger 对象。默认情况下,debugwarnlogging 模块中的其他函数将调用basicConfig,这反过来又会将StreamHandler 添加到root logger

始终使用recommended 将所需的处理程序添加到您为模块编写的记录器对象中。

您可以参考official Python docs,其中有一个awesome tutorial,或者您可以更好地查看日志模块的源代码。

您可以通过以下方式在 Python shell 本身中检查源代码,

import logging
import inspect
print(inspect.getsource(logging))

最后,显式调用basicConfig 将解决问题。

import logging
logging.basicConfig()
logger = logging.getLogger('logger')
logger.warning('The system may break down')

【讨论】:

    【解决方案3】:

    除了 phd 的回答之外,调用 logging.basicConfig() 是一个方便的函数,它将为您提供默认的 StreamHandlerFormatter。如果您想快速拥有日志记录功能,这就足够了。您可以通过传递 basicConfig 一些参数来自定义它的行为:

    添加有用的参数:在消息旁边输出时间戳

    logger = logging.basicConfig(level=logging.DEBUG, 
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    

    这对于大多数一次性需求来说应该没问题。如果您需要对配置进行更多控制,您可以通过自己定义记录器的属性来添加更复杂的行为。

    复杂示例:不使用basicConfig 函数

    import logging
    logger = logging.getLogger("mylogger")
    streamHandler = logging.StreamHandler()
    streamHandler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    streamHandler.setFormatter(formatter)
    
    logger.addHandler(streamHandler)
    
    logger.info("Files copied")
    logger.warning("disk quota exceeded")
    >> 2017-12-06 11:11:12, 090 - mylogger - INFO Files copied
    >> 2017-12-06 11:11:12, 091 - mylogger - WARNING disk quota exceeded
    

    在更大的环境中,下一步是从先前创建的记录器派生一个新记录器,首先保持格式并保持“日志层次结构”

    logger2 = logging.getLogger("mylogger.new")
    logger2.info("New Logger info")
    >> 2017-12-06 11:11:12, 091 - mylogger.new - New logger info
    

    日志记录手册是一个很好的参考: https://docs.python.org/2/howto/logging-cookbook.html

    【讨论】:

    • “格式化程序”行中有一个错字 - 缺少“(”。我花了很长时间才明白为什么我在尝试运行该示例时遇到了一个神秘的错误
    【解决方案4】:

    如果您在使用sentry (No handlers could be found for logger "sentry.errors") 时收到此错误,可能是由于 SNI 支持的哨兵错误。

    查看https://github.com/getsentry/raven-python/issues/523 了解更多详情。一个快速的解决方法是用threaded+requests+https替换DSN方案:

    RAVEN_CONFIG = {
        'dsn': 'threaded+requests+https://xxxxxxxxxxxx@sentry.example.com/1',
    }
    

    【讨论】:

      【解决方案5】:

      为了完整起见:

      为了使这项工作在可能在其他地方使用或独立使用的模块级别上工作,您可以这样做

      logger = logging.getLogger(__name__)
      
      # create own logging handler if nobody changed the root logger.
      if not logging.root.handlers and not logger.handlers:
          handler = logging.StreamHandler()
          handler.formatter = logging.Formatter('%(asctime)s %(funcName)s %(levelname)s: %(message)s')
          logger.addHandler(handler)
      

      这允许独立运行模块并避免在已配置根记录器的上下文中使用它时发生冲突。

      请注意,帖子中描述的错误消息仅出现在 Python 2 中。如果层次结构中未定义任何处理程序,Python 3 会将消息打印到标准输出。

      【讨论】:

        猜你喜欢
        • 2012-11-11
        • 2011-09-03
        • 2015-04-27
        • 2015-02-09
        • 2016-01-05
        • 2016-07-24
        • 2018-11-12
        • 1970-01-01
        相关资源
        最近更新 更多