@@ -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,58 @@ 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 ()
303+ except AttributeError :
304+ # No get_exception_handler before Python 3.5.2
305+ loop_except_handler = getattr (loop , '_exception_handler' , None )
306+
307+ if not loop_except_handler :
308+ loop_except_handler = type (loop ).default_exception_handler
309+
310+ def handle_exception (loop , context ):
311+ if 'exception' in context :
312+ exception = context ['exception' ]
313+ exc_info = type (exception ), exception , exception .__traceback__
314+ self .captureException (exc_info = exc_info , level = 'exception' ) # asyncio exceptions are non-fatal
315+ else :
316+ data = {}
317+
318+ if 'source_traceback' in context :
319+ tb = context ['source_traceback' ]
320+ elif 'handle' in context and getattr (context ['handle' ], '_source_traceback' , None ):
321+ tb = context ['handle' ]._source_traceback
322+ elif 'future' in context and getattr (context ['future' ], '_source_traceback' , None ):
323+ tb = context ['future' ]._source_traceback
324+ else :
325+ tb = None
326+
327+ if tb :
328+ frames = []
329+
330+ for file_name , lineno , function_name , text in tb :
331+ frames .append ({
332+ 'filename' : file_name ,
333+ 'lineno' : lineno ,
334+ 'function' : function_name ,
335+ })
336+
337+ if frames :
338+ data = {'stacktrace' : {'frames' : frames }}
339+
340+ message = context .get ('message' , 'Unhandled exception in event loop' )
341+ self .captureMessage (message , data = data , level = 'exception' )
342+
343+ loop_except_handler (loop , context )
344+
345+ handle_exception .raven_client = self
346+ loop .set_exception_handler (handle_exception )
347+
286348 def hook_libraries (self , libraries ):
287349 from raven .breadcrumbs import hook_libraries
288350 hook_libraries (libraries )
0 commit comments