Cuando el reactor retorcido está en funcionamiento y se produce una excepción dentro de un aplazamiento que no se detecta, se imprime "Error no controlado" en el terminal junto con un rastreo y la excepción. ¿Es posible manejar / interceptar estas excepciones (por ejemplo, establecer una devolución de llamada o anular un método)?

EDITAR: Soy consciente de que puedo detectar un error al agregar un error a un diferido. Lo que quiero saber es si hay una manera de interceptar una falla / excepción no manejada que ha atravesado la cadena hasta el reactor.

EDITAR: Básicamente, me pregunto si el reactor retorcido tiene un controlador de errores global o algo a lo que se pueda acceder. Me pregunto porque imprime el rastreo y el error de la falla.

Ejemplo:

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
9
user369450 6 ago. 2011 a las 01:16

3 respuestas

La mejor respuesta

Debido a que estos rastreos se escriben usando una llamada a twisted.python.log.deferr() (en Twisted 10.2 de todos modos), es posible redirigirlos utilizando un observador de registros. Esto es lo más común que se puede hacer con estos rastros de pila. No puedo encontrar ninguna clase base para observadores de registro (sorprendentemente) pero hay un par incorporado:

twisted.python.log.PythonLoggingObserver - Todo lo que se registra va al Python estándar { {X1}} módulo. (Lo uso en mi aplicación).

twisted.python.log.FileLogObserver: todo lo que se registra va a un archivo.

Ambos captarán trazas de pila reportadas por el reactor. Todo lo que tiene que hacer es construir el observador de registro (sin argumentos) y luego llamar al método start() del objeto.

(Nota al margen: también hay una StdioOnnaStick clase que puede construir y asignar a sys.stdout o sys.stderr si lo desea. Luego, cualquier cosa que print vaya al registro Twisted).

Para realmente, realmente interceptar estas llamadas, para que los rastros de la pila nunca se registren, usted podría:

  • Subclase twisted.internet.SelectReactor y anular su método runUntilCurrent(). Eso es lo que registra los rastros de la pila. Tendría que estudiar la fuente de twisted.internet.base.ReactorBase antes de hacer esto.
  • Después de que haya realizado todas las importaciones twisted.*, configure twisted.python.log.deferr en una función de su elección, que sea compatible con el prototipo def err(_stuff=None, _why=None, **kw).
6
wberry 5 ago. 2011 a las 22:14

Respondiendo a tu comentario:

Esencialmente, me pregunto si el reactor retorcido tiene un controlador de error global o algo a lo que se pueda acceder. Me pregunto porque imprime el rastreo y el error del error.

La respuesta es "no de manera adecuada".

Primero, el reactor no tiene nada que ver con los diferidos, en realidad, todo el módulo diferido debe colocarse en el paquete twisted.python, pero esto aún no se puede hacer debido a algunas dependencias. Volviendo a tu pregunta ...

Excavando en el código retorcido (más precisamente, el twisted.internet.defer módulo) puede delinear el siguiente flujo de eventos:

  1. Cuando se llama al método callback con un resultado, la instancia diferida comienza a ejecutar sus devoluciones de llamada a través de método _runCallbacks;
  2. Si una de las devoluciones de llamada arroja una excepción, se envuelve en Falla (línea 542);
  3. Si la cadena de devolución de llamada se agota y el último resultado fue un error, el resultado actual se asigna a la propiedad failResult de un DebugInfo instancia (línea 575);
  4. Si la instancia diferida, y por lo tanto su instancia DebugInfo, es basura recolectada y todavía hay una falla activa como resultado, el Se llama al método DebugInfo.__del__ y se imprime el rastreo.

Dadas estas premisas, una de las soluciones más simples sería parchear la clase DebugInfo:

from twisted.internet.defer import DebugInfo
del DebugInfo.__del__  # Hides all errors
1
GaretJax 5 ago. 2011 a las 22:19

Puede agregar un error al diferido; las excepciones no controladas se convierten automáticamente a twisted.python.failure.Failure.

3
GaretJax 5 ago. 2011 a las 21:37