python - Correct logging for exception in coroutine Python3 + Tornado4.3 + native logging module -
in tornado, exception encapsulated within future , caller async function must yield future unpack exception. how log message correctly print out function name , line exception happens if have long calling chain of async functions ?
for example, in code below:
format = '%(asctime)s - %(levelname)s - %(filename)s : %(lineno)s'\ ' - %(funcname)20s() - %(message)s\n' logging.basicconfig(format=format) ... @gen.coroutine def layer_2(): return(yield async_func()) @gen.coroutine def layer_1(): return(yield layer_2()) @gen.coroutine def main(): try: yield layer_1() except exception e: logging.warning('error: {}'.format(str(e))
if there exception raised in async_func()
, log message lineno
, funcname
of main()
, not of async_func()
.
is there solution short of try
, catch
every yield
statement ? thanks!
edit 1: realized answer question might have nothing tornado, i'm including here because it's case.
i see you're using python 3, , in python 3, exceptions futures have traceback available automatically. use logging.exception
print it:
@gen.coroutine def main(): try: yield layer_1() except exception e: logging.exception(e)
there's nothing mysterious going on in logging
. can print traceback yourself:
@gen.coroutine def main(): try: yield layer_1() except exception e: import traceback traceback.print_exc()
compared traceback regular function call stack, traceback has stuff in it: calls gen.runner.run, part of tornado's coroutine implementation. serves purpose: can see main
@ top of stack , async_func
@ bottom.
this works in python 3 because every exception has traceback attached it, , tornado correctly attaches coroutine's traceback exception unwinds stack during exception handling. for history, see docs on future.
and finally, if replace gen.coroutine
async def
you'll nice clean tracebacks implemented python 3.5 interpreter itself.
Comments
Post a Comment