如何在Python中禁用标准错误流的日志记录?这行不通:

import logging

logger = logging.getLogger()
logger.removeHandler(sys.stderr)
logger.warning('foobar')  # emits 'foobar' on sys.stderr

当前回答

通过更改“logging.config. log”中的一层。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,
    },
}

})

其他回答

我找到了一个解决方案:

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

这将防止日志被发送到包含控制台日志的上层记录器。

这将防止所有来自第三个库的日志记录,就像这里描述的那样 https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library

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

log_file = 'test.log'
info_format = '%(asctime)s - %(levelname)s - %(message)s'
logging.config.dictConfig({
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'info_format': {
            'format': info_format
        },
    },
    'handlers': {
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'info_format'
        },
        'info_log_file': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'INFO',
            'filename': log_file,
            'formatter': 'info_format'
        }
    },
    'loggers': {
        '': {
            'handlers': [
                'console',
                'info_log_file'
            ],
            'level': 'INFO'
        }
    }
})


class A:

    def __init__(self):
        logging.info('object created of class A')

        self.logger = logging.getLogger()
        self.console_handler = None

    def say(self, word):
        logging.info('A object says: {}'.format(word))

    def disable_console_log(self):
        if self.console_handler is not None:
            # Console log has already been disabled
            return

        for handler in self.logger.handlers:
            if type(handler) is logging.StreamHandler:
                self.console_handler = handler
                self.logger.removeHandler(handler)

    def enable_console_log(self):
        if self.console_handler is None:
            # Console log has already been enabled
            return

        self.logger.addHandler(self.console_handler)
        self.console_handler = None


if __name__ == '__main__':
    a = A()
    a.say('111')
    a.disable_console_log()
    a.say('222')
    a.enable_console_log()
    a.say('333')

控制台输出:

2018-09-15 15:22:23,354 - INFO - object created of class A
2018-09-15 15:22:23,356 - INFO - A object says: 111
2018-09-15 15:22:23,358 - INFO - A object says: 333

Test.log文件内容:

2018-09-15 15:22:23,354 - INFO - object created of class A
2018-09-15 15:22:23,356 - INFO - A object says: 111
2018-09-15 15:22:23,357 - INFO - A object says: 222
2018-09-15 15:22:23,358 - INFO - A object says: 333

使用装饰器找到了一个优雅的解决方案,它解决了以下问题:如果您正在编写一个具有多个函数的模块,每个函数都有几个调试消息,并且您希望禁用除当前关注的函数之外的所有函数的登录,该怎么办?

你可以使用装饰器:

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_being_focused内部调用function_already_debug,也不会显示来自function_already_debug的调试消息。 这确保您将只看到您所关注的函数的调试消息。

希望能有所帮助!

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

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