记录在 tornado.concurrent.Future 的回调中不起作用

Logging not working in callback of tornado.concurrent.Future

我正在使用 apscheduler 的 tornado 调度程序。每当调用任务时,我都需要记录它的异常。为了处理异常,我创建了一个装饰器,它将获得未来的对象并采取适当的行动。它工作正常,但它没有记录在未来的回调函数中。我已经在回调内部完成了 Pdb,并且记录器实例属性符合预期,但它仍然根本没有记录文件。 代码是,

logger = logging.getLogger('myLogger')

def handle_callback(result):
    logger.debug(result.result())
    logger.info(result.result())
    logger.error(result.result())
    logger.exception(result.result())
    logger.exception(result.exc_info())


def handle_exceptions():
    def wrapped(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            future = fn(*args, **kwargs)
            future.add_done_callback(handle_callback)
        return wrapper
    return wrapped


@handle_exceptions()
@gen.coroutine
def run_task(job_id):
    logger.info('executing job {}'.format(job_id))
    raise MyException

P.S。我正在使用 python2.7

包装器缺少未来的 return - 没有这个,如果有一些异步调用,ioloop 将不会继续。让我们添加一些异步调用

@handle_exceptions
@gen.coroutine
def run_task(job_id):
    logger.info('executing job {}'.format(job_id))
    yield gen.sleep(1)
    raise Exception('blah')

您可能已经注意到,我已从装饰器中删除 () 以简化它。它不必嵌套。所以装饰器看起来像:

def handle_exceptions(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        future = fn(*args, **kwargs)
        future.add_done_callback(handle_callback)
        return future  # <<< we need this
    return wrapper

接下来,处理程序的回调正在调用 Future.result(),这将立即重新引发异常。所以最好先检查一下是否有异常:

def handle_callback(result):
    exc_info  = result.exc_info()
    if exc_info:
        logger.error('EXCEPTION %s', exc_info)

将其组合成一个简单的例子:

import logging
from functools import wraps, partial
from tornado import gen, ioloop

logger = logging.getLogger()
logger.setLevel(logging.INFO)


def handle_callback(result):
    exc_info  = result.exc_info()
    if exc_info:
        logger.error('EXCEPTION %s', exc_info)


def handle_exceptions(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        future = fn(*args, **kwargs)
        future.add_done_callback(handle_callback)
        return future
    return wrapper


@handle_exceptions
@gen.coroutine
def run_task(job_id):
    logger.info('executing job {}'.format(job_id))
    yield gen.sleep(1)
    raise Exception('blah')


ioloop.IOLoop.instance().run_sync(partial(run_task, 123))

由于问题本身不提供有关日志记录的任何信息,因此我使用了更改级别的标准。 代码输出:

INFO:root:executing job 123
ERROR:root:EXCEPTION (<type 'exceptions.Exception'>, Exception('blah',), <traceback object at 0x7f807df07dd0>)
Traceback (most recent call last):
  File "test.py", line 31, in <module>
    ioloop.IOLoop.instance().run_sync(partial(run_task, 123))
  File "/tmp/so/lib/python2.7/site-packages/tornado/ioloop.py", line 458, in run_sync
    return future_cell[0].result()
  File "/tmp/so/lib/python2.7/site-packages/tornado/concurrent.py", line 238, in result
    raise_exc_info(self._exc_info)
  File "/tmp/so/lib/python2.7/site-packages/tornado/gen.py", line 1069, in run
    yielded = self.gen.send(value)
  File "test.py", line 28, in run_task
    raise Exception('blah')
Exception: blah

如果还有任何其他问题,我认为它与日志记录有关 config/setup。