Скрученная необработанная ошибка

Когда скрученный реактор работает и в отложенном случае возникает исключение, которое не было перехвачено, на терминал выводится «Необработанная ошибка» вместе с трассировкой и исключением. Можно ли обработать/перехватить эти исключения (например, установить обратный вызов или переопределить метод)?

РЕДАКТИРОВАТЬ: я знаю, что могу поймать сбой, добавив errback в deferrerd. Я хочу знать, есть ли способ перехватить необработанный сбой/исключение, которое прошло по цепочке к реактору.

РЕДАКТИРОВАТЬ: По сути, мне интересно, есть ли у скрученного реактора глобальный обработчик ошибок или что-то, к чему можно получить доступ. Интересно, потому что он печатает трассировку и ошибку из-за сбоя.

Пример:

Unhandled Error
Traceback (most recent call last):
  File "/var/projects/python/server.py", line 359, in run_server
    return server.run()
  File "/var/projects/python/server.py", line 881, in run
    reactor.run()
  File "/usr/local/lib/python2.6/dist-packages/Twisted-11.0.0-py2.6-linux-x86_64.egg/twisted/internet/base.py", line 1162, in run
    self.mainLoop()
  File "/usr/local/lib/python2.6/dist-packages/Twisted-11.0.0-py2.6-linux-x86_64.egg/twisted/internet/base.py", line 1171, in mainLoop
    self.runUntilCurrent()
--- <exception caught here> ---
  File "/usr/local/lib/python2.6/dist-packages/Twisted-11.0.0-py2.6-linux-x86_64.egg/twisted/internet/base.py", line 793, in runUntilCurrent
    call.func(*call.args, **call.kw)
  File "/var/projects/python/server.py", line 524, in monitor
    elapsed = time.time() - info.last
exceptions.NameError: global name 'info' is not defined

person All Workers Are Essential    schedule 05.08.2011    source источник
comment
Возможно, фрагмент кода будет полезнее, чем общая трассировка.   -  person GaretJax    schedule 06.08.2011
comment
По сути, мне интересно, есть ли у скрученного реактора глобальный обработчик ошибок или что-то, к чему можно получить доступ. Интересно, потому что он печатает трассировку и ошибку из-за сбоя.   -  person All Workers Are Essential    schedule 06.08.2011
comment
ЭТО более четкий вопрос! Я так не думаю, но позвольте мне взглянуть... ;-)   -  person GaretJax    schedule 06.08.2011


Ответы (3)


Поскольку эти обратные трассировки записываются с использованием вызова twisted.python.log.deferr() (по крайней мере, в Twisted 10.2), их можно перенаправить с помощью наблюдателя журнала. Это наиболее распространенная вещь, которую нужно делать с этими трассировками стека. Я не могу найти базовый класс для наблюдателей за журналом (на удивление), но есть пара встроенных:

twisted.python.log.PythonLoggingObserver — все, что регистрируется, отправляется в стандартный модуль Python logging. (Я использую это в своем приложении.)

twisted.python.log.FileLogObserver — все, что регистрируется, сохраняется в файле.

Оба они будут перехватывать трассировки стека, о которых сообщает реактор. Все, что вам нужно сделать, это создать наблюдатель журнала (без аргументов), а затем вызвать метод объекта start().

(Примечание: есть также класс StdioOnnaStick, который вы можете создать и назначьте sys.stdout или sys.stderr, если хотите. Тогда все, что вы print, попадете в журнал Twisted.)

Чтобы по-настоящему перехватывать эти вызовы, чтобы трассировка стека вообще никогда не регистрировалась, вы можете:

  • Подкласс twisted.internet.SelectReactor и переопределить его метод runUntilCurrent(). Это то, что регистрирует трассировку стека. Прежде чем сделать это, вам нужно будет изучить источник twisted.internet.base.ReactorBase.
  • После того, как вы выполнили все импорты twisted.*, установите twisted.python.log.deferr функцию по вашему выбору, которая совместима с прототипом def err(_stuff=None, _why=None, **kw).
person wberry    schedule 05.08.2011
comment
Все хорошо, за исключением того, что вы действительно никогда не должны рекомендовать подкласс реактора. Написание собственного реактора отрезает вас от огромного количества функций Twisted; все, что связано с графическим интерфейсом или оптимизированным мультиплексором для вашей платформы (epoll, kqueue, IOCP), и это редко необходимо. Кроме того, обезьянье исправление deferr слишком радикально. Правильно будет принять ваше предложение по поводу наблюдателя за логами. Вы можете просто написать свой собственный и обернуть вокруг существующего наблюдателя, вам не нужно создавать подкласс одного из именованных классов. - person Glyph; 06.08.2011
comment
Да, это зависит от того, что он имел в виду под перехватом. Если он имел в виду полную тишину, то, надеюсь, перспектива возиться с внутренностями Twisted для достижения этого лишает его стимула. Я также рекомендую использовать один из классов наблюдателя журнала. - person wberry; 06.08.2011
comment
Спасибо. Наблюдатель за логированием должен работать. Создание подкласса реактора может быть излишним, но полезно знать. - person All Workers Are Essential; 08.08.2011

Вы можете добавить errback к отложенному; необработанные исключения автоматически преобразуются в twisted.python.failure.Failure.

person GaretJax    schedule 05.08.2011
comment
сбои, означающие экземпляры twisted.python.failure.Failure - person wberry; 06.08.2011
comment
Я знаю, что могу поймать сбой, добавив errback к deferrerd. Я хочу знать, есть ли способ перехватить необработанный сбой/исключение, которое прошло по цепочке к реактору. - person All Workers Are Essential; 06.08.2011
comment
@C.P.Burns: Поскольку исключение преобразуется в сбой, если вы добавите errback к отложенному, вы можете его перехватить. Я что-то упускаю? - person GaretJax; 06.08.2011
comment
@GaretJax: К.П. кажется, хочет знать, как сделать это для всех зарегистрированных исключений (независимо от того, исходят ли они от Deferred или нет), не зная, из какого Deferred они могут исходить. - person Glyph; 06.08.2011
comment
@Glyph: мне кажется, что это связано исключительно с отложенным: исключение возникает внутри отложенного; во всяком случае, я написал этот ответ до КП. прокомментировал и отредактировал свой вопрос. ;-) - person GaretJax; 06.08.2011

Отвечая на ваш комментарий:

По сути, мне интересно, есть ли у скрученного реактора глобальный обработчик ошибок или что-то, к чему можно получить доступ. Интересно, потому что он печатает трассировку и ошибку из-за сбоя.

Ответ "не в надлежащем виде".

Во-первых, реактор не имеет никакого отношения к deferred’ам, вообще-то весь deferred-модуль должен быть помещен в пакет twisted.python, но этого пока нельзя сделать из-за некоторых зависимостей. Вернемся к вашему вопросу...

Копаемся в скрученном коде (точнее, в модуле twisted.internet.defer) можно наметить следующий поток событий:

  1. Когда метод callback вызывается с результатом, отложенный экземпляр начинает выполнять свои обратные вызовы через ссылку _runCallbacks;
  2. Если один из обратных вызовов вызывает исключение, он превращается в ошибку (строка 542);
  3. Если цепочка обратных вызовов исчерпана и последним результатом был сбой, текущий результат присваивается свойству failResult файла DebugInfo экземпляр (строка 575);
  4. Если отложенный экземпляр и, следовательно, его DebugInfo экземпляр являются сборщиком мусора, в результате все равно возникает активный сбой, DebugInfo.__del__ и распечатывается трассировка.

Учитывая эти предпосылки, одним из самых простых решений было бы исправить класс DebugInfo обезьяной:

from twisted.internet.defer import DebugInfo
del DebugInfo.__del__  # Hides all errors
person GaretJax    schedule 05.08.2011
comment
Это неправильно — есть несколько способов перехватывать ошибки, добавляя наблюдатели логов, которые будут захватывать Failure объекты и обрабатывать их различными способами. В других ответах обсуждаются некоторые из них. Не буду понижать голос, потому что это интересное исследование кода, но, пожалуйста, не принимайте это предложение. - person Glyph; 06.08.2011
comment
Не буду с тобой спорить... не было бы шансов. ;-) Но что, если у вас есть несколько обозревателей логов и вы хотите скрыть это от всех? Если я хорошо помню, они называются итеративно, не так ли? - person GaretJax; 06.08.2011
comment
Это не очень полезно хотеть. Не выдавайте ошибку, если вы не хотите, чтобы наблюдатели ее видели (что равнозначно добавлению правильного errback в данном конкретном случае). - person Jean-Paul Calderone; 07.08.2011
comment
Я согласен с вами (поэтому я ответил другим ответом в первую очередь), но, возможно, вместо того, чтобы скрывать ошибки, вы хотели бы вызвать какое-то другое действие (но не регистрировать их)… код исправления обезьяны в ответе был только один из возможных примеров. Заметьте, я не утверждаю, что мой ответ правильный, мне просто было любопытно. - person GaretJax; 08.08.2011
comment
Спасибо за разъяснение между реактором и отсроченным. - person All Workers Are Essential; 08.08.2011