Я не верю, что обработчик - это ваше решение. Перейти на фильтр:
import os.path
import traceback
import logging
_LOGGING_FILE = os.path.normcase(logging.addLevelName.__code__.co_filename)
_CURRENT_FILE = os.path.normcase(__file__)
_ELIMINATE_STACK = (_CURRENT_FILE, _LOGGING_FILE)
class AddStackFilter(logging.Filter):
def __init__(self, levels=None):
self.levels = levels or set()
def get_stack(self):
# Iterator over file names
filenames = iter(_ELIMINATE_STACK)
filename = next(filenames, "")
frames = traceback.walk_stack(None)
# Walk up the frames
for frame, lineno in frames:
# If frame is not from file, continue on to the next file
while os.path.normcase(frame.f_code.co_filename) != filename:
filename = next(filenames, None)
if filename is None:
break
else:
# It's from the given file, go up a frame
continue
# Finished iterating over all files
break
# No frames left
else:
return None
info = traceback.format_stack(frame)
info.insert(0, 'Stack (most recent call last):\n')
# Remove last newline
info[-1] = info[-1].rstrip()
return "".join(info)
def filter(self, record):
if record.levelno in self.levels:
sinfo = self.get_stack()
if sinfo is not None:
record.stack_info = sinfo
return True
Этот фильтр имеет множество преимуществ:
- Удаляет кадры стека из локального файла и файла журнала.
- Оставляет кадры стека на случай, если мы вернемся к локальному файлу после прохождения регистрации. Важно, если мы хотим использовать тот же модуль для других вещей.
- Вы можете прикрепить его к любому обработчику или регистратору, не привязывая вас к StreamHandler или любому другому обработчику.
- Вы можете воздействовать на несколько обработчиков, используя один и тот же фильтр или один обработчик по вашему выбору.
- Уровни задаются в виде переменной
__init__
, что позволяет добавлять дополнительные уровни по мере необходимости.
- Позволяет добавлять трассировку стека в журнал, а не просто печатать.
- Хорошо играет с модулем регистрации, помещая стек в правильное место, ничего неожиданного.
Использование:
>>> import stackfilter
>>> import logging
>>> sfilter = stackfilter.AddStackFilter(levels={logging.WARNING})
>>> logging.basicConfig()
>>> logging.getLogger().addFilter(sfilter)
>>> def testy():
... logging.warning("asdasd")
...
>>> testy()
WARNING:root:asdasd
Stack (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in testy