2013-05-20 11 views
16

ho istituito il sedano a lavorare con la mia applicazione Django utilizzando le loro istruzioni daemonization (http://docs.celeryproject.org/en/latest/tutorials/daemonizing.html#daemonizing)Come accedere eccezioni che si verificano in un compito Django sedano

Qui è il mio compito di prova

@periodic_task(run_every=timedelta(seconds=10)) 
def debugger(): 
    logger.info("Running debugger") 
    raise Exception('Failed') 

ho bisogno di un modo di sapere che questa attività (debugger) non è riuscita a causa dell'eccezione. Il file di registrazione di Celery stampa il log logger.info ("debugger in esecuzione"), ma non registra l'eccezione. Mi sto perdendo qualcosa, o dovrei trovare compiti falliti in qualche altro modo?

+1

Cosa voglio da sedano? Non potrei crash come app desktop. Potresti usare due semplici modi. 1. Utilizzare il risultato backend e contrassegnare l'attività come fallita. 2. Avvolgi tutto il tuo codice in sedano per provare tranne. – Rustem

+3

@Rustem Mi piacerebbe che Celery rilevi eccezioni e le scriva in un file di registro invece di ingannarle apparentemente ... –

risposta

1

Utilizzare il modulo traceback per acquisire la traccia come stringa e inviarla al registratore.

try: 
    ... 
except: 
    import traceback 
    logger.info(traceback.format_exc()) 
+3

fwif, il logger python può includere la traccia di nuovo su qualsiasi livello. tutto ciò che devi fare è aggiungere exc_info = 1 alla chiamata. per esempio. logger.info ('qualcosa ha fallito b/c dell'altro coso', exc_info = 1) – user2399268

6

Potete guardare Celery User Guide:

from celery.utils.log import get_task_logger 

logger = get_task_logger(__name__) 

@app.task 
def div(): 
    try: 
     1/0 
    except ZeroDivisionError: 
     logger.exception("Task error") 

Dalla documentazione per python logging module:

Logger.exception (msg, * args)

Registra un messaggio con livello ERROR su questo registratore. Gli argomenti sono interpretati come per debug(). Le informazioni sulle eccezioni vengono aggiunte al messaggio di registrazione. Questo metodo deve essere chiamato solo da un gestore di eccezioni.

+1

Aspetta, mi aspetto che ci sia qualcosa registrato nel log del lavoro, per lo meno, per ogni compito che fallisce ... –

3

La domanda:

mi piacerebbe sedano per la cattura di eccezioni e di scrivere in un file di log, invece di apparentemente loro ingoiare ...

La parte superiore corrente la risposta qui è così così per gli scopi di una soluzione professionale. Molti sviluppatori di Python considereranno l'errore di blank catching, caso per caso, di una bandiera rossa. Un ragionevole avversione per questo è stato ben articolato in un commento:

Aspetta, mi aspetto che ci sia qualcosa di registrato nel registro dei lavoratori, per lo meno, per ogni compito che non riesce ...

Celery fa l'eccezione, non sta facendo ciò che l'OP voleva che facesse con esso (lo memorizza nel backend del risultato). Il seguente elenco è il meglio che internet ha da offrire su questo problema. È un po 'datato, ma nota il numero di forchette e stelle.

https://gist.github.com/darklow/c70a8d1147f05be877c3

Il nocciolo sta prendendo il caso fallimento e fare qualcosa di personalizzato con esso. Questo è un superset del problema dell'OP. Ecco come regolare la soluzione nel Gist per registrare l'eccezione.

import logging 

logger = logging.getLogger('your.desired.logger') 


class LogErrorsTask(Task): 
    def on_failure(self, exc, task_id, args, kwargs, einfo): 
     logger.exception('Celery task failure!!!1', exc_info=exc) 
     super(LogErrorsTask, self).on_failure(exc, task_id, args, kwargs, einfo) 

Sarà comunque necessario per assicurarsi che tutte le attività ereditano da questa classe compito, e il nocciolo mostra come fare questo se si sta utilizzando il @task decoratore (con il base=LogErrorsTask kwarg).

Il vantaggio di questa soluzione è di non annidare il codice in altri contesti di prova eccetto. Questo è piggyback sul percorso del codice di errore che il sedano sta già utilizzando.

0

Si può anche ignorare il sedano app, per evitare di aggiungere base kwarg ad ogni @app.task decoratore:

import logging 
from celery import Celery, Task 

logger = logging.getLogger(__name__) 

class LoggingTask(Task): 
    def on_failure(self, exc, task_id, args, kwargs, einfo): 
     logger.exception('Task failed: %s' % exc, exc_info=exc) 
     super(LoggingTask, self).on_failure(exc, task_id, args, kwargs, einfo) 

class LoggingCelery(Celery): 
    def task(self, *args, **kwargs): 
     kwargs.setdefault('base', LoggingTask) 
     return super(LoggingCelery, self).task(*args, **kwargs) 

app = LoggingCelery(__name__) 
Problemi correlati