有没有一种简单的方法可以在Python 3中禁用异常堆栈跟踪的日志记录,无论是在Handler
还是Formatter
中?
我需要在另一个Handler
中使用堆栈跟踪,因此在调用Logger
时设置exc_info=False
不是一个选项。除了定义自己的Formatter
之外,是否有更简单的方法?
有没有一种简单的方法可以在Python 3中禁用异常堆栈跟踪的日志记录,无论是在Handler
还是Formatter
中?
我需要在另一个Handler
中使用堆栈跟踪,因此在调用Logger
时设置exc_info=False
不是一个选项。除了定义自己的Formatter
之外,是否有更简单的方法?
禁用每个处理程序的回溯输出最简单的方法是添加一个自定义的logging.Filter子类
,该子类修改记录对象(而不是过滤记录)。
过滤器只需将记录上的exc_info
设置为None
即可:
class TracebackInfoFilter(logging.Filter):
"""Clear or restore the exception on log records"""
def __init__(self, clear=True):
self.clear = clear
def filter(self, record):
if self.clear:
record._exc_info_hidden, record.exc_info = record.exc_info, None
# clear the exception traceback text cache, if created.
record.exc_text = None
elif hasattr(record, "_exc_info_hidden"):
record.exc_info = record._exc_info_hidden
del record._exc_info_hidden
return True
# do not display tracebacks in messages handled with this handler,
# by setting the traceback cache to a non-empty string:
handler_with_no_tracebacks.addFilter(TracebackInfoFilter())
for handler in logger.handlers:
if not any(isinstance(f, TracebackInfoFilter) for f in handler.filters):
handler.addFilter(TracebackInfoFilter(clear=False))
logging.setLogRecordFactory()
函数注册自定义记录工厂;只需无条件地将记录的exc_info
属性设置为None
即可。record_factory = logging.getLogRecordFactory()
def clear_exc_text(*args, **kwargs):
record = record_factory(*args, **kwargs)
record.exc_info = None
return record
logging.setLogRecordFactory(clear_exc_text)
logging.LogRecord
类是默认的工厂,但上述函数将尽力与任何已设置的自定义工厂配合使用。Handler
子类,在Handler.handle()
中设置和清除exc_info
属性。class NoTracebackHandler(logging.Handler):
def handle(self, record):
info, cache = record.exc_info, record.exc_text
record.exc_info, record.exc_text = None, None
try:
super().handle(record)
finally:
record.exc_info = info
record.exc_text = cache
这项工作甚至可以比 Digoya的回答 更容易实现:
class NoTracebackFormatter(logging.Formatter):
def formatException(self, ei):
return ""
def formatStack(self, stack_info):
return ""
Johothon的回答很好而且直接,但它排除了所有的异常信息,而不仅仅是堆栈。异常的类型和参数对于开发运维人员和最终用户都是有用的,所以我修改了他们的代码以包含这些信息:
class NoTracebackFormatter(logging.Formatter):
def formatException(self, exc_info):
return '%s: %s' % (exc_info[0].__name__, exc_info[1])
def formatStack(self, stack_info):
return ""
handler.setFormatter(NoTracebackFormatter())
。回复晚了,但对其他人可能有用。您不需要烦恼 Handler
或 Filter
。您只需要继承自己的 Formatter
并跳过格式化异常的部分。这是我使用的代码片段:
class EnhancedFormatter(logging.Formatter):
def __init__(self, fmt=None, datefmt=None, style='%', validate=True, skip_traceback=False):
self.skip_traceback = skip_traceback
super(EnhancedFormatter, self).__init__(fmt, datefmt, style, validate)
def format(self, record) -> str:
record.message = record.getMessage()
if self.usesTime():
record.asctime = self.formatTime(record, self.datefmt)
s = self.formatMessage(record)
if not self.skip_traceback: # check here do you need to format traceback
if record.exc_info:
if not record.exc_text:
record.exc_text = self.formatException(record.exc_info)
if record.exc_text:
if s[-1:] != "\n":
s = s + "\n"
s = s + record.exc_text
if record.stack_info:
if s[-1:] != "\n":
s = s + "\n"
s = s + self.formatStack(record.stack_info)
return s
只需在实例化格式化程序类时设置skip_traceback
参数,然后使用它来确定是否需要格式化回溯信息。