Журнал Python: отключить трассировку стека
Есть ли простой способ отключить запись трассировки стека исключений в Python 3, либо в Handler
или же Formatter
?
Мне нужна трассировка стека в другом Handler
так что настройка exc_info=False
в призыве к Logger
это не вариант. Есть ли более простой способ, чем просто определить мой собственный Formatter
?
3 ответа
Самый простой способ отключить вывод трассировки для каждого обработчика - это добавить пользовательский logging.Filter
подкласс, который изменяет объект записи (а не отфильтровывает записи).
Фильтр просто должен установить exc_text
на записи в строку, заменяя None
дефолт:
class SetTracebackCacheFilter(logging.Filter):
"""Set the exception cache text on log records to a specific value"""
def __init__(self, exc_text):
self.exc_text = exc_text
def filter(self, record):
record.exc_text = self.exc_text
return True
и добавьте этот фильтр в ваш обработчик, установив кешированный текст в пустую строку:
# do not display tracebacks in messages handled with this handler,
# by setting the traceback cache to an empty string:
handler_with_no_tracebacks.addFilter(SetTracebackCacheFilter(''))
Это работает, потому что Formatter.format()
метод явно документы LogRecord.exc_text
в качестве атрибута, в котором кэшируется отформатированная трассировка:
Обратите внимание, что отформатированная информация об исключении кэшируется в атрибуте
exc_text
, Это полезно, потому что информация об исключении может быть выбрана и отправлена по проводам, но вы должны быть осторожны, если у вас более одногоFormatter
подкласс, который настраивает форматирование информации об исключении. В этом случае вам придется очистить кэшированное значение после того, как форматировщик выполнил свое форматирование, чтобы следующий форматировщик, обрабатывающий событие, не использовал кэшированное значение, а пересчитал его заново.
Приведенный выше фильтр использует это для предотвращения генерации текста трассировки. Каждый раз, когда сообщение передается обработчику, вышеупомянутый фильтр вызывается, чтобы увидеть, захочет ли обработчик обработать экземпляр записи, и мы "кешируем" пустой текст исключения.
Однако обработчики не копируют записи журнала, и любой другой обработчик, которому позже передается та же запись журнала, также игнорирует форматирование трассировки. Поэтому вам также необходимо настроить следующий обработчик, указанный в logger.handlers
список сразу после обработчика с указанным фильтром:
idx = logger.handlers.index(handler_with_no_tracebacks)
if len(logger.handlers) >= idx:
# clear the traceback text cache again for further handlers
logger.handlers[idx + 1].addFilter(SetTracebackCacheFilter(None))
Если вы хотите отключить все выходные данные трассировки везде, то, возможно, добавление настраиваемого фильтра ко всем обработчикам или регистраторам становится утомительным. В этом случае другой вариант заключается в регистрации пользовательской фабрики записей с logging.setLogRecordFactory()
функция; просто установите exc_text
приписать записи к пустой строке:
record_factory = logging.getLogRecordFactory()
def clear_exc_text(*args, **kwargs):
record = record_factory(*args, **kwargs)
record.exc_text = ''
return record
logging.setLogRecordFactory(clear_exc_text)
Обратите внимание, что фабрика по умолчанию это просто logging.LogRecord
класс, но вышеупомянутая функция делает все возможное для работы с любой уже установленной фабрикой.
Ни фильтр, ни фабрика пользовательских записей не очищают exc_info
кортеж, так что вы можете получить доступ к этому где-то еще.
Конечно, вы также можете создать свой собственный Handler
подкласс, где Handler.handle()
устанавливает и очищает exc_text
атрибут:
class NoTracebackHandler(logging.Handler):
def handle(self, record):
old, record.exc_text = record.exc_text, ''
try:
super().handle(record)
finally:
record.exc_text = old
Это можно сделать даже проще, чем ответ Дигои :
class NoTracebackFormatter(logging.Formatter):
def formatException(self, ei):
return ""
def formatStack(self, stack_info):
return ""
(Проверено на Python 3.9)
Поздний ответ, но это может быть полезно для кого-то еще. Вам не нужно беспокоиться о
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
аргумент при создании экземпляра класса форматирования, а затем используйте его, чтобы определить, нужно ли вам форматировать трассировку или нет.