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

时间:2010-02-15 14:48:06

标签: python logging console stdout

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

#!/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")

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

17 个答案:

答案 0 :(得分:174)

我找到了解决方案:

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

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

答案 1 :(得分:79)

我用:

logger = logging.getLogger()
logger.disabled = True
... whatever you want ...
logger.disabled = False

答案 2 :(得分:60)

您可以使用:

logging.basicConfig(level=your_level)

其中 your_level 就是其中之一:

      'debug': logging.DEBUG,
      'info': logging.INFO,
      'warning': logging.WARNING,
      'error': logging.ERROR,
      'critical': logging.CRITICAL

因此,如果您将 your_level 设置为 logging.CRITICAL ,您将只收到以下发送的重要消息:

logging.critical('This is a critical error message')

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

有关详细信息,请查看logging examples.

以相同的方式更改每个处理程序使用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)

答案 3 :(得分:43)

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

更接近原始海报的代码/意图,这适用于我在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")

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

答案 4 :(得分:35)

上下文管理器

import logging 
class DisableLogger():
    def __enter__(self):
       logging.disable(logging.CRITICAL)
    def __exit__(self, a, b, c):
       logging.disable(logging.NOTSET)

使用示例:

with DisableLogger():
    do_something()

答案 5 :(得分:25)

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

root_logger = logging.getLogger()
root_logger.disabled = True

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

从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)

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

答案 6 :(得分:22)

完全禁用日志记录

logging.disable(sys.maxint) # Python 2

logging.disable(sys.maxsize) # Python 3

启用日志记录

logging.disable(logging.NOTSET)

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

logging.getLogger().disabled = True

,对于大于50的某些n

logging.disable(n)

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

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

可以通过

来预防
logging.disable(sys.maxint)

据我所知(在审核source之后)是完全禁用日志记录的唯一方法。

答案 7 :(得分:10)

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

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

logging.getLogger().addHandler(MyLogHandler())

更简单的方法是:

logging.getLogger().setLevel(100)

答案 8 :(得分:5)

日志记录中有the following structure

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

日志记录中有the following process(以流程图表示):

Logging flow.

因此,要禁用特定的记录器,您可以执行以下操作之一:

  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(以防止使用当前流{{1}的logging.lastResort处理程序logging.StreamHandler处理事件) }和级别sys.stderrset the attribute propagate of the logger to False(以防止事件由记录器的祖先记录器的处理程序处理)。

    • 使用主要API:

      logging.WARNING
    • 使用配置API:

      import logging
      
      logger = logging.getLogger("foo")
      for handler in logger.handlers.copy():
          logger.removeHandler(handler)
      logger.addHandler(logging.NullHandler())
      logger.propagate = False
      

警告。 —与方法1和2相反,方法1和方法2仅阻止记录器 记录的事件及其记录祖先的处理程序发出,方法3还可以防止由记录器的后代记录器 记录的事件(例如import logging.config logging.config.dictConfig({ "version": 1, "handlers": { "null": { "class": "logging.NullHandler" } }, "loggers": { "foo": { "handlers": ["null"], "propagate": False } } }) )由记录器的处理程序及其祖先记录器发出。

注意。—将记录器的属性logging.getLogger("foo.bar")设置为disabled并不是另一种方法,因为它不是公共API的一部分。参见https://bugs.python.org/issue36318

True

答案 9 :(得分:2)

你也可以:

handlers = app.logger.handlers
# detach console handler
app.logger.handlers = []
# attach
app.logger.handlers = handlers

答案 10 :(得分:2)

我不太了解日志记录模块,但我正在以通常只想禁用调试(或信息)消息的方式使用它。您可以使用Handler.setLevel()将日志记录级别设置为CRITICAL或更高。

此外,您可以通过打开文件来替换sys.stderr和sys.stdout。见http://docs.python.org/library/sys.html#sys.stdout。但我不建议这样做。

答案 11 :(得分:1)

通过在“ logging.config.dictConfig”中更改一个级别,您可以将整个日志记录级别提高到一个新级别。

logging.config.dictConfig({
'version': 1,
'disable_existing_loggers': False,
'formatters': {
    'console': {
        'format': '%(name)-12s %(levelname)-8s %(message)s'
    },
    'file': {
        'format': '%(asctime)s %(name)-12s %(levelname)-8s %(message)s'
    }
},
'handlers': {
    'console': {
        'class': 'logging.StreamHandler',
        'formatter': 'console'
    },
#CHANGE below level from DEBUG to THE_LEVEL_YOU_WANT_TO_SWITCH_FOR
#if we jump from DEBUG to INFO
# we won't be able to see the DEBUG logs in our logging.log file
    'file': {
        'level': 'DEBUG',
        'class': 'logging.FileHandler',
        'formatter': 'file',
        'filename': 'logging.log'
    },
},
'loggers': {
    '': {
        'level': 'DEBUG',
        'handlers': ['console', 'file'],
        'propagate': False,
    },
}

})

答案 12 :(得分:1)

这将防止来自第三个库的所有日志记录(如此处所述) https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library

logging.getLogger('somelogger').addHandler(logging.NullHandler())

答案 13 :(得分:0)

如果您要暂时禁用某个记录器,请执行以下操作。

示例日志

2019-10-02 21:28:45,663 django.request PID: 8  Internal Server Error: /service_portal/get_all_sites

代码

django_request_logger = logging.getLogger('django.request')
django_request_logger.disabled = True
django_request_logger.disabled = False

答案 14 :(得分:0)

使用装饰器找到了一种优雅的解决方案,该解决方案解决了以下问题:如果您要编写一个具有多个功能的模块,每个功能具有多个调试消息,并且您希望禁用所有功能,则该怎么办?功能,但您当前关注的是那一个?

您可以使用装饰器来做到这一点:

import logging, sys
logger = logging.getLogger()
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)


def disable_debug_messages(func):
    def wrapper(*args, **kwargs):
        prev_state = logger.disabled
        logger.disabled = True
        result = func(*args, **kwargs)
        logger.disabled = prev_state
        return result
    return wrapper

然后,您可以执行以下操作:

@disable_debug_messages
def function_already_debugged():
    ...
    logger.debug("This message won't be showed because of the decorator")
    ...

def function_being_focused():
    ...
    logger.debug("This message will be showed")
    ...

即使您从function_already_debugged内部调用function_being_focused,也不会显示来自function_already_debugged的调试消息。 这样可以确保您只看到您关注的功能中的调试消息。

希望有帮助!

答案 15 :(得分:0)

您可以更改特定处理程序的调试模式级别,而不是完全禁用它。

因此,如果您遇到某种情况,则只想停止控制台的调试模式,但仍然需要保留其他级别,例如Error。您可以按照以下步骤进行操作

# create logger
logger = logging.getLogger(__name__)

def enableConsoleDebug (debug = False):
    #Set level to logging.DEBUG to see CRITICAL, ERROR, WARNING, INFO and DEBUG statements
    #Set level to logging.ERROR to see the CRITICAL & ERROR statements only
    logger.setLevel(logging.DEBUG)

    debugLevel = logging.ERROR
    if debug:
        debugLevel = logging.DEBUG

    for handler in logger.handlers:
        if type(handler) is logging.StreamHandler:
            handler.setLevel (debugLevel)

答案 16 :(得分:-1)

子类化您想要暂时禁用的处理程序:

class ToggledHandler(logging.StreamHandler):
"""A handler one can turn on and off"""

def __init__(self, args, kwargs):
    super(ToggledHandler, self).__init__(*args, **kwargs)
    self.enabled = True  # enabled by default

def enable(self):
    """enables"""
    self.enabled = True

def disable(self):
    """disables"""
    self.enabled = False

def emit(self, record):
    """emits, if enabled"""
    if self.enabled:
        # this is taken from the super's emit, implement your own
        try:
            msg = self.format(record)
            stream = self.stream
            stream.write(msg)
            stream.write(self.terminator)
            self.flush()
        except Exception:
            self.handleError(record)

通过名称查找处理程序非常简单:

_handler = [x for x in logging.getLogger('').handlers if x.name == your_handler_name]
if len(_handler) == 1:
    _handler = _handler[0]
else:
    raise Exception('Expected one handler but found {}'.format(len(_handler))

一旦发现:

_handler.disable()
doStuff()
_handler.enable()