【问题标题】:Fully disable python logging完全禁用 python 日志记录
【发布时间】:2015-02-23 04:08:21
【问题描述】:

在我的代码中,我使用logging.info(...,在此之前我使用logging.basicConfig(filename=... 进行配置。是否可以在不做任何事情的情况下将日志记录行保留在代码中?

【问题讨论】:

标签: python logging


【解决方案1】:

你可以使用:

logging.disable(logging.CRITICAL)

发送至disable all logging calls,其级别为 CRITICAL 或以下。实际上,这会禁用所有日志记录调用。

您可以通过执行以下操作再次启用所有记录器的日志记录(在它们自己的日志记录级别):

logging.disable(logging.NOTSET)

【讨论】:

    【解决方案2】:

    编辑:disabled 似乎不应该供公众使用。查看 Maggyero 对替代解决方案的回答。

    只需禁用日志处理程序,它就不会再写入任何内容了。

    logging.getLogger().disabled = True
    

    请注意,每个记录器都可以有处理程序,因此可能会有更多。

    【讨论】:

    • 您禁用记录器的第二个解决方案是一个很好的解决方案。但是,您设置空处理程序列表的第一个解决方案是错误的。首先因为它不是线程安全的(你应该使用removeHandler 方法,它使用threading.RLock() 实例来实现)。其次,因为logging.lastResort 处理程序将在没有处理程序的情况下使用。相反,您应该添加一个logging.NullHandler() 实例(以避免logging.lastResort 处理程序)并将propagate 设置为False 以避免日志记录传播到父记录器的处理程序。
    • lastResort 处理程序在 Python 2 中不存在(它是在 3.2 中添加的)所以在 5 年前写这篇文章时我不知道它;)docs.python.org/3.2/library/logging.html#logging.lastResort 至于线程安全,这在这里完全无关紧要。替换变量没有锁定安全问题。不过,我将删除第一个解决方案,使用 lastResort 处理程序不再是一个好的解决方案。
    • 即使lastResort处理程序不存在,"No handlers could be found for logger X"消息也会打印在sys.stderr上,这不是所谓的“完全禁用日志记录”。
    • 只有在设置raiseExceptions 时才会出现这种情况(对于 Python 2),不建议在生产系统上使用。所以消息会被系统吞下。
    • 最后使用 disabled 属性并不是一个好主意,因为它实际上不是公共 API 的一部分(参见 my discussionlogging 库的作者 Vinay Sajip 的合影)。因此正确的解决方案是使用lambda record: False 过滤器或logging.NullHandler() 处理程序而不进行传播。
    【解决方案3】:

    日志有the following structure:

    • 记录器根据命名空间层次结构排列,带有点分隔符;
    • 每个记录器都有一个级别(根记录器默认为logging.WARNING,非根记录器默认为logging.NOTSET)和一个有效级别(非根记录器的父记录器的有效级别,级别为logging.NOTSET,否则为记录器的级别);
    • 每个记录器都有一个过滤器列表
    • 每个记录器都有一个处理程序列表
    • 每个处理程序都有一个级别(默认为logging.NOTSET);
    • 每个处理程序都有一个过滤器列表

    Logging 有the following process(用流程图表示):

    因此,要禁用特定记录器,您可以采用以下策略之一:

    1. 将记录器的级别设置为logging.CRITICAL + 1

      • 使用主 API:

        import logging
        
        logger = logging.getLogger("foo")
        logger.setLevel(logging.CRITICAL + 1)
        
      • 使用配置 API:

        import logging.config
        
        logging.config.dictConfig({
            "version": 1,
            "loggers": {
                "foo": {
                    "level": logging.CRITICAL + 1
                }
            }
        })
        
    2. 向记录器添加过滤器lambda record: False

      • 使用主 API:

        import logging
        
        logger = logging.getLogger("foo")
        logger.addFilter(lambda record: False)
        
      • 使用配置 API:

        import logging.config
        
        logging.config.dictConfig({
            "version": 1,
            "filters": {
                "all": {
                    "()": lambda: (lambda record: False)
                }
            },
            "loggers": {
                "foo": {
                    "filters": ["all"]
                }
            }
        })
        
    3. 删除记录器的现有处理程序add a handler logging.NullHandler() to the logger(以防止事件被处理程序logging.lastResort处理,这是一个logging.StreamHandler使用当前流sys.stderr和一个级别logging.WARNING)和@987654325 @(防止事件被记录器的祖先记录器的处理程序处理)。

      • 使用主 API:

        import logging
        
        logger = logging.getLogger("foo")
        for handler in logger.handlers.copy():
            try:
                logger.removeHandler(handler)
            except ValueError:  # in case another thread has already removed it
                pass
        logger.addHandler(logging.NullHandler())
        logger.propagate = False
        
      • 使用配置 API:

        import logging.config
        
        logging.config.dictConfig({
            "version": 1,
            "handlers": {
                "null": {
                    "class": "logging.NullHandler"
                }
            },
            "loggers": {
                "foo": {
                    "handlers": ["null"],
                    "propagate": False
                }
            }
        })
        

    警告。 - 与策略 1 和 2 相反,策略 3还可以防止由记录器(例如logging.getLogger("foo.bar"))的后代记录器记录的事件被记录器及其祖先记录器的处理程序发出。

    注意。 — 将记录器的属性 disabled 设置为 True 不是另一种策略,因为它不是公共 API 的一部分(参见 https://bugs.python.org/issue36318):

    import logging
    
    logger = logging.getLogger("foo")
    logger.disabled = True  # DO NOT DO THIS
    

    【讨论】:

    • 应该注意filter() 方法有一个小警告。它不会像处理程序和级别那样传播:saltycrane.com/blog/2014/02/… 所以如果你想过滤你需要遍历所有处理程序的所有内容。
    • 请注意,添加NullHandler() 仅在没有现有处理程序的情况下才有效。否则完全是徒劳的。
    • Levelshandlers 不会“传播”:如果不是,logger 的 有效级别 是从父 loggers 的级别继承的指定,并且 日志记录 传播到父记录器的处理程序。但这是一个很好的观点:如果你想过滤所有内容,你需要遍历,更准确地说,所有 child loggers(如果你将过滤器附加到 loggers,就像这里)或所有 parent处理程序(如果您将过滤器附加到处理程序,就像在您的博客示例中一样)。我已经更新了我的答案,谢谢。
    • 如果我想重新激活日志记录,一旦它被使用主 api 禁用?我有一个烧瓶服务器,我想根据每个请求激活/停用日志记录。
    • @LeeviL 我想说只是做相反的操作:如果您使用第一种解决方案启用日志记录,请删除logging.NullHandler()并将propagate属性设置为True;如果您使用第二种解决方案启用了日志记录,请删除 lambda record: False 过滤器。
    【解决方案4】:

    如果你想完全禁用日志首先应该在 logging.basicConfig() 中设置 levelevl 等于 logging.NOTSET 因为是零级别,然后是 logging.getLogger( ).disabled 设置 True 或 Falsehttps://docs.python.org/2/library/logging.html

    完全禁用示例:

    import logging
    
    if __name__ == '__main__':
         logging.disable(logging.NOTSET)
    
         logging.basicConfig(
         format="%(levelname) -10s %(asctime)s %(filename)s:%(lineno)s  %(message)s",
         level=logging.NOTSET)
    
         logging.getLogger().disabled = True  # True, False
    
         logging.critical("Critical")
         logging.error("Error")
         logging.warning("Warning")
         logging.info("Info")
         logging.debug("Debug")
    

    【讨论】:

      猜你喜欢
      • 2019-12-23
      • 2018-01-29
      • 2021-06-09
      • 2021-12-19
      • 2018-08-03
      • 2023-03-20
      • 1970-01-01
      • 2014-07-16
      • 2011-02-16
      相关资源
      最近更新 更多