如何在Python中禁用标准错误流的日志记录?这行不通:
import logging
logger = logging.getLogger()
logger.removeHandler(sys.stderr)
logger.warning('foobar') # emits 'foobar' on sys.stderr
如何在Python中禁用标准错误流的日志记录?这行不通:
import logging
logger = logging.getLogger()
logger.removeHandler(sys.stderr)
logger.warning('foobar') # emits 'foobar' on sys.stderr
当前回答
(早就死了的问题,但对未来的搜索者来说)
更接近最初海报的代码/意图,这适用于我在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处理程序后删除它;如果没有处理程序,记录器代码将自动重新添加标准输出。
IndexOutOfBound修复:如果你得到一个IndexOutOfBound错误,而实例化lhStdout,移动实例化后添加你的文件处理程序,即。
...
logger.addHandler(lh)
lhStdout = logger.handlers[0]
logger.removeHandler(lhStdout)
其他回答
日志有以下结构:
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的调试消息。 这确保您将只看到您所关注的函数的调试消息。
希望能有所帮助!
子类化你想要暂时禁用的处理程序:
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()
我找到了一个解决方案:
logger = logging.getLogger('my-logger')
logger.propagate = False
# now if you use logger it will not log to console.
这将防止日志被发送到包含控制台日志的上层记录器。
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