如何在Python中禁用和重新启用控制台日志记录?

sor*_*rin 134 python console logging stdout

我正在使用Python的日志记录模块,我想暂时禁用控制台日志记录,但它不起作用.

#!/usr/bin/python
import logging

logger = logging.getLogger() # this gets the root logger
# ... here I add my own handlers 
#logger.removeHandler(sys.stdout)
#logger.removeHandler(sys.stderr)

print logger.handlers 
# this will print [<logging.StreamHandler instance at ...>]
# but I may have other handlers there that I want to keep

logger.debug("bla bla")
Run Code Online (Sandbox Code Playgroud)

上面的代码显示了bla blaon stdout,我不知道如何安全地禁用控制台处理程序.我怎么能确定我暂时删除了控制台StreamHandler而不是另一个?

sor*_*rin 183

我找到了一个解决方案:

logger = logging.getLogger('my-logger')
logger.propagate = False
# now if you use logger it will not log to console.
Run Code Online (Sandbox Code Playgroud)

这将阻止将日志记录发送到包含控制台日志记录的上部记录程序.

  • 我不认为这是一个很好的解决方案.不传播到更高的记录器可能会产生其他不良后果. (8认同)
  • 停止消息传播还不够。[自 Python 3.2 起](https://docs.python.org/3/howto/logging.html#what-happens-if-no-configuration-is-provided),“logging.lastResort”处理程序仍会记录消息在没有其他处理程序的情况下,严重性为“logging.WARNING”并大于“sys.stderr”。[查看我的答案](/sf/answers/4293316961/)。 (3认同)
  • 如果您只想过滤某个日志级别以下的消息(例如,所有`INFO`消息),您可以将第二行更改为`logger.setLevel(logging.WARNING)` (2认同)
  • 之后您将如何重新启用日志? (2认同)
  • **没有答案**,因为阻止传播有效地禁用了根记录程序的所有处理程序,并且该问题明确指出了*(...),但是我可能要保留其他处理程序*,这表明打算禁用默认的StreamHandler。根记录器**仅**。 (2认同)

inf*_*ito 92

我用:

logger = logging.getLogger()
logger.disabled = True
... whatever you want ...
logger.disabled = False
Run Code Online (Sandbox Code Playgroud)

  • 这也适用于`logging`模块级别以完全禁用日志*,例如:`import logging; logging.disable(logging.CRITICAL);`:https://docs.python.org/2/library/logging.html#logging.disable (9认同)
  • **不是答案** - 问题是如何禁用默认的StreamHandler****. (4认同)

Vad*_*kus 66

您可以使用:

logging.basicConfig(level=your_level)
Run Code Online (Sandbox Code Playgroud)

其中your_level是其中之一:

      'debug': logging.DEBUG,
      'info': logging.INFO,
      'warning': logging.WARNING,
      'error': logging.ERROR,
      'critical': logging.CRITICAL
Run Code Online (Sandbox Code Playgroud)

因此,如果将your_level设置为logging.CRITICAL,则只会发送以下关键消息:

logging.critical('This is a critical error message')
Run Code Online (Sandbox Code Playgroud)

your_level设置为logging.DEBUG将显示所有级别的日志记录.

有关更多详细信息,请查看日志记录示例.

以相同的方式更改每个Handler的级别使用Handler.setLevel()函数.

import logging
import logging.handlers

LOG_FILENAME = '/tmp/logging_rotatingfile_example.out'

# Set up a specific logger with our desired output level
my_logger = logging.getLogger('MyLogger')
my_logger.setLevel(logging.DEBUG)

# Add the log message handler to the logger
handler = logging.handlers.RotatingFileHandler(
          LOG_FILENAME, maxBytes=20, backupCount=5)

handler.setLevel(logging.CRITICAL)

my_logger.addHandler(handler)
Run Code Online (Sandbox Code Playgroud)

  • 这通常是有用的信息,但问题是如何禁用控制台日志记录,而不是如何添加其他处理程序.如果您使用应用于原始示例的上述代码检查my_logger.handlers,您将看到两个处理程序 - 您的新文件处理程序和原始流处理程序. (5认同)
  • 记录.CRITICAL+1 (2认同)

小智 45

(长期存在的问题,但未来的搜索者)

更接近原始海报的代码/意图,这在python 2.6下适合我

#!/usr/bin/python
import logging

logger = logging.getLogger() # this gets the root logger

lhStdout = logger.handlers[0]  # stdout is the only handler initially

# ... here I add my own handlers 
f = open("/tmp/debug","w")          # example handler
lh = logging.StreamHandler(f)
logger.addHandler(lh)

logger.removeHandler(lhStdout)

logger.debug("bla bla")
Run Code Online (Sandbox Code Playgroud)

我必须解决的问题是添加新的stdout处理程序删除它; 如果没有处理程序,则记录器代码似乎会自动重新添加标准输出.

  • 序列`logger = logging.getLogger(); lhStdout = logger.handlers[0]` 是错误的,因为根记录器最初没有处理程序 – `python -c "import logging; assert not logging.getLogger().handlers"`。通过 Python 2.7.15 和 Python 3.6.6 验证。 (4认同)

pym*_*men 36

上下文管理器

import logging 
class DisableLogger():
    def __enter__(self):
       logging.disable(logging.CRITICAL)
    def __exit__(self, a, b, c):
       logging.disable(logging.NOTSET)
Run Code Online (Sandbox Code Playgroud)

使用示例:

with DisableLogger():
    do_something()
Run Code Online (Sandbox Code Playgroud)

  • 问题询问如何禁用默认的 StreamHandler **only**。 (2认同)
  • 如果您喜欢披萨上的异国水果。当然。 (2认同)

sta*_*fry 33

要完全禁用日志记录:

logging.disable(sys.maxint) # Python 2

logging.disable(sys.maxsize) # Python 3
Run Code Online (Sandbox Code Playgroud)

要启用日志记录:

logging.disable(logging.NOTSET)
Run Code Online (Sandbox Code Playgroud)

其他答案提供的工作不能完全解决问题,例如

logging.getLogger().disabled = True
Run Code Online (Sandbox Code Playgroud)

对于n超过50的人,

logging.disable(n)
Run Code Online (Sandbox Code Playgroud)

第一个解决方案的问题是它只适用于根记录器.例如,使用logging.getLogger(__name__)此方法禁用的其他记录器不会被禁用.

第二种解决方案会影响所有日志.但它将输出限制在高于给定值的水平,因此可以通过以大于50的级别记录来覆盖它.

这可以通过以下方式预防

logging.disable(sys.maxint)
Run Code Online (Sandbox Code Playgroud)

据我所知(在查看源代码之后)是完全禁用日志记录的唯一方法.

  • 当问题询问如何禁用标准 StreamHandler **only** 时投反对票 (2认同)

and*_*tti 25

这里有一些非常好的答案,但显然最简单的是没有考虑太多(仅限于infinito).

root_logger = logging.getLogger()
root_logger.disabled = True
Run Code Online (Sandbox Code Playgroud)

这会禁用根记录器,从而禁用所有其他记录器.我还没有真正测试,但它也应该是最快的.

从python 2.7中的日志代码我看到了这一点

def handle(self, record):
    """
    Call the handlers for the specified record.

    This method is used for unpickled records received from a socket, as
    well as those created locally. Logger-level filtering is applied.
    """
    if (not self.disabled) and self.filter(record):
        self.callHandlers(record)
Run Code Online (Sandbox Code Playgroud)

这意味着当它被禁用时,不会调用任何处理程序,例如,过滤到非常高的值或设置无操作处理程序应该更有效.

  • 如果您正在处理多个记录器或多个处理程序,这可能会出现问题。例如,如果您仍想记录到文件但想在特定情况下禁用流处理程序。 (2认同)
  • *这将禁用根记录器,因此所有其他记录器* - 严格来说禁用根记录器不会禁用任何其他记录器。除了问题询问禁用默认 StreamHandler **only **。 (2认同)

Mag*_*ero 12

日志具有以下结构

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

日志记录有以下过程(用流程图表示):

记录流。

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

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

  2. lambda record: False向记录器添加过滤器。

  3. 除去记录器的现存的处理器,添加处理程序logging.NullHandler()的记录器(以防止从该处理程序被处理的事件logging.lastResort是一种logging.StreamHandler使用当前流sys.stderr和一个电平logging.WARNING)和属性集propagate的记录器,以False(以防止正被处理的事件由记录器的祖先记录器的处理程序)。

    • 使用主 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
      
      Run Code Online (Sandbox Code Playgroud)
    • 使用配置 API:

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

警告。— 策略 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
Run Code Online (Sandbox Code Playgroud)


Ehs*_*ghi 10

无需转移标准输出.这是更好的方法:

import logging
class MyLogHandler(logging.Handler):
    def emit(self, record):
        pass

logging.getLogger().addHandler(MyLogHandler())
Run Code Online (Sandbox Code Playgroud)

更简单的方法是:

logging.getLogger().setLevel(100)
Run Code Online (Sandbox Code Playgroud)

  • 在Python 2.7+中,可以使用[NullHandler()](https://docs.python.org/2/library/logging.handlers.html#nullhandler) (4认同)
  • 当阅读`logging.basicConfig()`函数的描述(我的重点)时,可以看出为什么这样做(禁用默认的StreamHandler): *通过使用默认的Formatter创建一个StreamHandler并将其添加到日志系统中,可以看到日志系统的基本配置根记录器。函数 debug()、info()、warning()、error() 和 critical() 将自动调用 basicConfig() **如果没有为根记录器定义处理程序**。* – https://docs.python .org/3/library/logging.html#logging.basicConfig (2认同)