8 ответов:
использовать
logging.exceptionСexcept:обработчик для регистрации текущего исключения, с добавлением сообщения.import logging LOG_FILENAME = '/tmp/logging_example.out' logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG) logging.debug('This message should go to the log file') try: run_my_stuff() except: logging.exception('Got exception on main handler') raiseтеперь, глядя на лог-файл,
/tmp/logging_example.out:DEBUG:root:This message should go to the log file ERROR:root:Got exception on main handler Traceback (most recent call last): File "/tmp/teste.py", line 9, in <module> run_my_stuff() NameError: name 'run_my_stuff' is not defined
использовать параметры exc_info может быть лучше, остается предупреждение или название ошибки:
try: # coode in here except Exception as e: logging.error(e, exc_info=True)
моя работа недавно поручила мне регистрировать все трассировки / исключения из нашего приложения. Я попробовал множество методов, которые другие разместили в интернете, например, выше, но остановился на другом подходе. Переопределение
traceback.print_exception.у меня есть запись в http://www.bbarrows.com/ это было бы намного легче читать, но я также вставлю его сюда.
когда поставлена задача регистрации всех исключений, которые наше программное обеспечение может столкнуться в wild я попробовал несколько различных методов для регистрации наших трассировок исключений python. Сначала я подумал, что Python system exception hook, sys.excepthook будет идеальным местом для вставки кода регистрации. Я пытался что-то подобное:
import traceback import StringIO import logging import os, sys def my_excepthook(excType, excValue, traceback, logger=logger): logger.error("Logging an uncaught exception", exc_info=(excType, excValue, traceback)) sys.excepthook = my_excepthookэто работало для основного потока, но вскоре я обнаружил, что мой sys.excepthook не будет существовать в каких-либо новых потоках, которые запустил мой процесс. Это огромная проблема, потому что большинство всего происходит в потоках в этом проект.
после поиска в интернете и чтения большого количества документации самая полезная информация, которую я нашел, была из трекера проблем Python.
первый пост в потоке показывает рабочий пример
sys.excepthookне сохраняется в потоках (как показано ниже). Видимо, это ожидаемое поведение.import sys, threading def log_exception(*args): print 'got exception %s' % (args,) sys.excepthook = log_exception def foo(): a = 1 / 0 threading.Thread(target=foo).start()сообщения в этом потоке проблемы Python действительно приводят к 2 предложенным взломам. Либо подкласс
Threadи обернуть метод запуска в нашей собственной попытке кроме блока для того, чтобы ловить и регистрировать исключения или патч обезьяныthreading.Thread.runчтобы запустить свою собственную попытку, кроме блокировки и регистрации исключений.первый метод подклассов
Threadмне кажется, что в вашем коде меньше элегантности, так как вам придется импортировать и использовать свой пользовательскийThreadкласс везде, где вы хотели иметь поток ведения журнала. Это оказалось хлопот, потому что мне пришлось искать всю нашу базу кода и заменить все нормальныеThreadsС этим обычаемThread. Однако было понятно, что этоThreadделал и было бы легче для кого-то диагностировать и отлаживать, если что-то пошло не так с пользовательским кодом регистрации. Поток ведения журнала custome может выглядеть следующим образом:class TracebackLoggingThread(threading.Thread): def run(self): try: super(TracebackLoggingThread, self).run() except (KeyboardInterrupt, SystemExit): raise except Exception, e: logger = logging.getLogger('') logger.exception("Logging an uncaught exception")второй способ исправления обезьян
threading.Thread.runприятно, потому что я мог бы просто запустить его сразу после__main__и измерьте мой код регистрации во всех исключениях. Обезьяна исправление может быть раздражающим для отладки, хотя, как это изменяет ожидаемую функциональность чего-то. Этот предлагаемый патч из трекера проблем Python был:def installThreadExcepthook(): """ Workaround for sys.excepthook thread bug From http://spyced.blogspot.com/2007/06/workaround-for-sysexcepthook-bug.html (https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1230540&group_id=5470). Call once from __main__ before creating any threads. If using psyco, call psyco.cannotcompile(threading.Thread.run) since this replaces a new-style class method. """ init_old = threading.Thread.__init__ def init(self, *args, **kwargs): init_old(self, *args, **kwargs) run_old = self.run def run_with_except_hook(*args, **kw): try: run_old(*args, **kw) except (KeyboardInterrupt, SystemExit): raise except: sys.excepthook(*sys.exc_info()) self.run = run_with_except_hook threading.Thread.__init__ = initэто было не до тех пор, пока я не начал тестировать мое исключение регистрации я понял, что я шел об этом все неправильно.
для проверки я поставил
raise Exception("Test")где-то в моем коде. Однако обертывание метода A, который вызвал этот метод, было блоком try except, который распечатал трассировку и проглотил исключение. Это было очень неприятно, потому что я видел, как traceback печатается в STDOUT, но не регистрируется. Именно тогда я решил, что гораздо более простой способ регистрации tracebacks-это просто обезьяна патч метод, который использует весь код python для печати самих tracebacks, traceback.print_exception. Я закончил с чем-то похожим на следующее:
def add_custom_print_exception(): old_print_exception = traceback.print_exception def custom_print_exception(etype, value, tb, limit=None, file=None): tb_output = StringIO.StringIO() traceback.print_tb(tb, limit, tb_output) logger = logging.getLogger('customLogger') logger.error(tb_output.getvalue()) tb_output.close() old_print_exception(etype, value, tb, limit=None, file=None) traceback.print_exception = custom_print_exceptionэтот код записывает трассировку в строковый буфер и записывает ее в журнал ошибок. У меня есть пользовательский обработчик журналов, настроенный на регистратор "customLogger", который принимает журналы уровня ошибок и отправляет их домой анализ.
вы можете регистрировать все неперехваченные исключения в главном потоке, назначив обработчик
sys.excepthook, возможно, с помощьюexc_infoпараметр функций ведения журнала Python:import sys import logging logging.basicConfig(filename='/tmp/foobar.log') def exception_hook(exc_type, exc_value, exc_traceback): logging.error( "Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback) ) sys.excepthook = exception_hook raise Exception('Boom')если ваша программа использует потоки, однако, обратите внимание, что потоки, созданные с помощью
threading.Threadбудет не триггерsys.excepthookкогда неперехваченное исключение происходит внутри них, как отмечено в вопрос 1230540 по вопросу Python трекер. Некоторые хаки были предложены там, чтобы обойти это ограничение, как обезьяна-исправлениеThread.__init__заменитьself.runальтернативаrunметод, который обертывает оригинал вtryблокировать и звонкиsys.excepthookвнутриexceptблок. Кроме того, вы можете просто вручную обернуть точку входа для каждого из ваших потоков вtry/exceptсебя.
Неперехваченные сообщения об исключениях отправляются в STDERR, поэтому вместо реализации вашего входа в Python вы можете отправить STDERR в файл, используя любую оболочку, которую вы используете для запуска вашего скрипта Python. В скрипте Bash вы можете сделать это с перенаправлением вывода, Как описано в руководстве BASH.
примеры
добавить ошибки в файл, другой вывод на терминал:
./test.py 2>> mylog.logперезаписать файл с чередованием STDOUT и STDERR вывод:
./test.py &> mylog.log
может быть, не так стильно, но проще:
#!/bin/bash log="/var/log/yourlog" /path/to/your/script.py 2>&1 | (while read; do echo "$REPLY" >> $log; done)
то, что я искала:
import sys import traceback exc_type, exc_value, exc_traceback = sys.exc_info() traceback_in_var = traceback.format_tb(exc_traceback)посмотреть:
вот простой пример, взятый из документация python 2.6:
import logging LOG_FILENAME = '/tmp/logging_example.out' logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG,) logging.debug('This message should go to the log file')
Comments