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

import logging

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

当前回答

日志有以下结构:

loggers are arranged according to a namespace hierarchy with dot separators; each logger has a level (logging.WARNING by default for the root logger and logging.NOTSET by default for non-root loggers) and an effective level (the effective level of the parent logger for non-root loggers with a level logging.NOTSET and the level of the logger otherwise); each logger has a list of filters; each logger has a list of handlers; each handler has a level (logging.NOTSET by default); each handler has a list of filters.

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

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

Set the level of the logger to logging.CRITICAL + 1. Using the main API: import logging logger = logging.getLogger("foo") logger.setLevel(logging.CRITICAL + 1) Using the config API: import logging.config logging.config.dictConfig({ "version": 1, "loggers": { "foo": { "level": logging.CRITICAL + 1 } } }) Add a filter lambda record: False to the logger. Using the main API: import logging logger = logging.getLogger("foo") logger.addFilter(lambda record: False) Using the config API: import logging.config logging.config.dictConfig({ "version": 1, "filters": { "all": { "()": lambda: (lambda record: False) } }, "loggers": { "foo": { "filters": ["all"] } } }) Remove the existing handlers of the logger, add a handler logging.NullHandler() to the logger (to prevent events from being handled by the handler logging.lastResort which is a logging.StreamHandler using the current stream sys.stderr and a level logging.WARNING) and set the attribute propagate of the logger to False (to prevent events from being handled by the handlers of the ancestor loggers of the logger). Using the main 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 Using the config 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"))被记录器的处理程序及其祖先记录器发出。

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

import logging

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

其他回答

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

你可以使用装饰器:

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的调试消息。 这确保您将只看到您所关注的函数的调试消息。

希望能有所帮助!

完全禁用日志记录:

logging.disable(sys.maxint) # Python 2

logging.disable(sys.maxsize) # Python 3

启用日志记录:

logging.disable(logging.NOTSET)

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

logging.getLogger().disabled = True

当n大于50时,

logging.disable(n)

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

第二个解决方案确实会影响所有日志。但是它将输出限制在给定级别之上,因此可以通过记录级别大于50的日志来覆盖它。

这可以通过

logging.disable(sys.maxint)

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

我找到了一个解决方案:

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

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

使用上下文管理器-[最简单]

import logging 

class DisableLogger():
    def __enter__(self):
       logging.disable(logging.CRITICAL)
    def __exit__(self, exit_type, exit_value, exit_traceback):
       logging.disable(logging.NOTSET)

使用示例:

with DisableLogger():
    do_something()

如果你需要[更复杂的]细粒度的解决方案,你可以看看AdvancedLogger

AdvancedLogger can be used for fine grained logging temporary modifications

How it works:
Modifications will be enabled when context_manager/decorator starts working and be reverted after

Usage:
AdvancedLogger can be used
- as decorator `@AdvancedLogger()`
- as context manager `with  AdvancedLogger():`

It has three main functions/features:
- disable loggers and it's handlers by using disable_logger= argument
- enable/change loggers and it's handlers by using enable_logger= argument
- disable specific handlers for all loggers, by using  disable_handler= argument

All features they can be used together

AdvancedLogger的用例

# Disable specific logger handler, for example for stripe logger disable console
AdvancedLogger(disable_logger={"stripe": "console"})
AdvancedLogger(disable_logger={"stripe": ["console", "console2"]})

# Enable/Set loggers
# Set level for "stripe" logger to 50
AdvancedLogger(enable_logger={"stripe": 50})
AdvancedLogger(enable_logger={"stripe": {"level": 50, "propagate": True}})

# Adjust already registered handlers
AdvancedLogger(enable_logger={"stripe": {"handlers": "console"}

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

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