Twisted unhandled error
When the twisted reactor is running and an exception occurs within a deferred that isn't caught, "Unhandled Error" is printed to the terminal along with a traceback and the exception. Is it possible to handle/intercept these exceptions (e.g., set a callback or override a method)?
EDIT: I'm aware that I can catch a failure by adding an errback to a deferrerd. What I want to know is if there is a way to intercept an unhandled failure/exception that has traversed its way up the chain to the reactor.
EDIT: Essentially, I'm wondering if the twisted reactor has a global error handler or something that can be accessed. I wonder because it prints the traceback and error from the failure.
Example:
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
Because these tracebacks are written using a call to twisted.python.log.deferr()
(in Twisted 10.2 anyway), it is possible to redirect them using a log observer. This is the most common thing to do with these stack traces. I can't find any base class for log observers (surprisingly) but there are a couple built in:
twisted.python.log.PythonLoggingObserver
- Anything logged goes to the standard Python logging
module. (I use this in my application.)
twisted.python.log.FileLogObserver
- Anything logged goes to a file.
Both of these will catch stack traces reported by the reactor. All you have to do is construct the log observer (no arguments) and then call the object's start()
method.
(Side note: there's also a StdioOnnaStick
class that you can construct and assign to sys.stdout
or sys.stderr
if you want. Then anything you print
goes to the Twisted log.)
To really, truly intercept these calls, so the stack traces never get logged at all, you could either:
- Subclass
twisted.internet.SelectReactor
and override itsrunUntilCurrent()
method. That is what logs the stack traces. You would need to study the source oftwisted.internet.base.ReactorBase
before doing this. - After you have done all
twisted.*
imports, settwisted.python.log.deferr
to a function of your choosing, that is compatible with the prototypedef err(_stuff=None, _why=None, **kw)
.
You can add an errback to the deferred; unhandled exceptions are automatically converted to twisted.python.failure.Failure
.
Answering to your comment:
Essentially, I'm wondering if the twisted reactor has a global error handler or something that can be accessed. I wonder because it prints the traceback and error from the failure.
The response is "not in a proper way".
First, the reactor has nothing to do with deferreds, actually, the whole deferred module should be placed in the twisted.python
package, but this cannot be done yet because of some dependencies. Back to your question...
Digging into the twisted code (more precisel, the twisted.internet.defer
module) you can outline the following event flow:
- When the
callback
method is called with a result, the deferred instance begins to run its callbacks through the_runCallbacks
method; - If one of the callbacks throws an exception, it is wrapped into Failure (line 542);
- If the callback chain is exhausted and the last result was a failure, the current result is assigned to the failResult property of a
DebugInfo
instance (line 575); - If the deferred instance, and thus its
DebugInfo
instance, are garbage collected ad there still is an active failure as a result, theDebugInfo.__del__
method is called and the traceback printed out.
Given these premises, one of the simplest solutions would be to monkey patch the DebugInfo
class:
from twisted.internet.defer import DebugInfo
del DebugInfo.__del__ # Hides all errors
精彩评论