2017-08-11 3 views
0

J'utilise tornado scheduler de apscheduler. Chaque fois qu'une tâche est appelée, je dois enregistrer ses exceptions. Pour gérer les exceptions, j'ai créé un décorateur qui obtiendra le futur objet et prendra les mesures appropriées. Cela fonctionne bien, mais il ne se connecte pas à la fonction de rappel du futur. J'ai fait Pdb à l'intérieur du callback, et les propriétés de l'instance de logger sont comme prévu, mais il ne se connecte pas du tout. Le code est,La journalisation ne fonctionne pas dans le rappel de tornado.concurrent.Future

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. J'utilise python2.7

Répondre

1

Le retour du futur manque au wrapper - sans cela, ioloop ne continuera pas s'il y a un appel asynchrone. Ajoutons appel async

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

Comme vous pouvez le remarquer, je l'ai enlevé () de décorateur pour le simplifier. Il ne doit pas nécessairement être imbriqué. Ainsi, le décorateur pourrait ressembler à:

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 

Ensuite, le rappel du gestionnaire appelle Future.result() qui va immédiatement re-raise exception. Il est donc préférable de vérifier s'il y a une exception en premier lieu:

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

mettre tout ceci dans l'exemple simple:

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)) 

Puisque la question ne fournit pas d'informations sur l'enregistrement par lui-même, je J'ai utilisé la norme avec un niveau modifié. La sortie de code:

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 

S'il y a une autre question, je présume qu'il est lié à la configuration de l'enregistrement/configuration.

+0

J'ai cependant eu recours à 'yield' (in caller) en conjonction avec' gen.Return' (in callee). Et je suis capable de gérer les exceptions dans le bloc 'try except'. Est-ce que ce sera aussi bon qu'une exécution 'sync' normale? pour référence -> https://gist.github.com/pranav93/3c34d6cfc2b5d8956625e4cd66bdfa34 – pnv