@@ -73,6 +73,16 @@ def get_excepthook_client():
7373 return client
7474
7575
76+ def get_loop_excepthook_client (loop = None ):
77+ import asyncio
78+
79+ loop = loop or asyncio .get_event_loop ()
80+ hook = loop .get_exception_handler ()
81+ client = getattr (hook , 'raven_client' , None )
82+ if client is not None :
83+ return client
84+
85+
7686class ModuleProxyCache (dict ):
7787 def __missing__ (self , key ):
7888 module , class_name = key .rsplit ('.' , 1 )
@@ -283,6 +293,55 @@ def install_logging_hook(self):
283293 from raven .breadcrumbs import install_logging_hook
284294 install_logging_hook ()
285295
296+ def install_asyncio_hook (self , loop = None ):
297+ import asyncio
298+
299+ loop = loop or asyncio .get_event_loop ()
300+
301+ try :
302+ loop_except_handler = loop .get_exception_handler () or type (loop ).default_exception_handler
303+ except AttributeError :
304+ # No get_exception_handler before Python 3.5.2
305+ loop_except_handler = getattr (loop , '_exception_handler' , None ) or type (loop ).default_exception_handler
306+
307+ def handle_exception (loop , context ):
308+ if 'exception' in context :
309+ exception = context ['exception' ]
310+ exc_info = type (exception ), exception , exception .__traceback__
311+ self .captureException (exc_info = exc_info , level = 'exception' ) # asyncio exceptions are non-fatal
312+ else :
313+ if 'source_traceback' in context :
314+ tb = context ['source_traceback' ]
315+ elif 'handle' in context and getattr (context ['handle' ], '_source_traceback' , None ):
316+ tb = context ['handle' ]._source_traceback
317+ elif 'future' in context and getattr (context ['future' ], '_source_traceback' , None ):
318+ tb = context ['future' ]._source_traceback
319+ else :
320+ tb = None
321+
322+ if tb :
323+ frames = []
324+
325+ for file_name , lineno , function_name , text in tb :
326+ frames .append ({
327+ 'filename' : file_name ,
328+ 'lineno' : lineno ,
329+ 'function' : function_name ,
330+ })
331+
332+ if frames :
333+ data = {'stacktrace' : {'frames' : frames }}
334+ else :
335+ data = None
336+
337+ message = context .get ('message' , 'Unhandled exception in event loop' )
338+ self .captureMessage (message , data = data , level = 'exception' )
339+
340+ loop_except_handler (loop , context )
341+
342+ handle_exception .raven_client = self
343+ loop .set_exception_handler (handle_exception )
344+
286345 def hook_libraries (self , libraries ):
287346 from raven .breadcrumbs import hook_libraries
288347 hook_libraries (libraries )
0 commit comments