2015-04-01 15 views
25

Django error reporting gestisce le eccezioni non rilevate inviando un'e-mail e (facoltativamente) mostra all'utente una bella pagina di errore 500.Attivazione manuale del rapporto errori email Django

Questo funziona molto bene, ma in alcuni casi vorrei consentire agli utenti di continuare la loro attività senza interruzioni, ma ho ancora Django inviarmi il rapporto di errore e-mail sull'eccezione.

Quindi in pratica: posso inviare manualmente un messaggio di errore anche se rilevo l'eccezione?

Ovviamente, vorrei evitare di generare manualmente l'e-mail di segnalazione degli errori.

risposta

27

È possibile utilizzare il seguente codice per inviare manualmente una e-mail di un request e un'eccezione e:

import sys 
import traceback 
from django.core import mail 
from django.views.debug import ExceptionReporter 

def send_manually_exception_email(request, e): 
    exc_info = sys.exc_info() 
    reporter = ExceptionReporter(request, is_email=True, *exc_info) 
    subject = e.message.replace('\n', '\\n').replace('\r', '\\r')[:989] 
    message = "%s\n\n%s" % (
     '\n'.join(traceback.format_exception(*exc_info)), 
     reporter.filter.get_request_repr(request) 
    ) 
    mail.mail_admins(
     subject, message, fail_silently=True, 
     html_message=reporter.get_traceback_html() 
    ) 

potete provarlo in una vista del genere:

def test_view(request): 
    try: 
     raise Exception 
    except Exception as e: 
     send_manually_exception_email(request, e) 
+0

Più dolce! E sebbene nessuna risposta abbia prodotto esattamente il rapporto di errore che viene generato automaticamente, questo approccio ha fornito la maggior parte delle informazioni. È simile alla pagina di errore Django mostra con 'DEBUG = True' – frnhr

+0

Ricevo un errore nella riga n. 9. Dice:" L'oggetto 'Eccezione' non ha attributo 'messaggio' –

+0

aggiunto una modifica per farlo funzionare per python 3 – maxbellec

3

Sì, è possibile inviare manualmente un messaggio di errore anche se si rileva un'eccezione.

Ci sono diversi modi per procedere.

  1. È possibile utilizzare la configurazione predefinita logger esistente (e la sua configurazione gestore associato, documentato here) per django.request che invia tutti i messaggi di errore al gestore mail_admins, che invia il nulla connesso con log.error da Django. richiesta quando il debug è falso come email utilizzando AdminEmailHandler, il cui call point esistente è handle_uncaught_exception.
  2. È possibile aggiungere una configurazione di logger aggiuntiva che utilizza lo stesso gestore per intercettare l'eccezione prima di django.request e richiamare log.error in precedenza.
  3. È possibile sottoclasse django.request, in particolare handle_uncaught_exception.
  4. È possibile utilizzare un middleware personalizzato (for example StandardExceptionMiddleware) o ExceptionMiddleware
  5. È possibile chiamare manualmente i contenuti di Emit in AdminEmailHandler o mail.mail_admins direttamente.

Di queste opzioni, l'opzione 4 sembra essere la più comune.

Sulla base delle informazioni aggiuntive nel commento è riportato un esempio di codice di 2.

Innanzitutto il codice che verrà conteggiato a visualizzare

from django.http import HttpResponse 
import logging 
logger = logging.getLogger(__name__) 

def my_view(request): 

    try: 
     result = do_something() 
     return HttpResponse('<h1>Page was found' + result + '</h1>') 
    except Exception: 
     # Can have whatever status_code and title you like, but I was just matching the existing call. 
     logger.error('Internal Server Error: %s', request.path, 
      exc_info=sys.exc_info(), 
      extra={ 
      'status_code': 500, 
      'request': request 
      } 
     ) 
     return HttpResponse('<h1>Page was found, and exception was mailed to admins.</h1>') 

Questo si basa su Django documentation for view writing e and introduction to Django logging, ma non è stato testato.

Poi la configurazione del logger aggiuntivo è aggiungere alla alla voce forestale (come da here)

'nameofdjangoapplicationgoeshere': { 
      'handlers': ['mail_admins'], 
      'level': 'ERROR', 
      'propagate': False, 
     }, 
+0

Desidero attivare la segnalazione di errore da una vista e quindi continuare con le cose come di consueto (ovvero consentire alla vista di restituire una risposta HTTP), quindi non credo che un middleware lo farà. O mi manca smth, il commento di @Brandon indica anche il middleware? Le opzioni 1 e 2 sembrano essere la risposta. Ti va di aggiungere un esempio di codice? – frnhr

6

Basta installare un semplice gestore di registro nelle impostazioni.

LOGGING = { 
    'version': 1, 
    'disable_existing_loggers': False, 
    'filters': { 
     'require_debug_false': { 
      '()': 'django.utils.log.RequireDebugFalse' 
     } 
    }, 
    'handlers': { 
     'mail_admins': { 
      'level': 'ERROR', 
      'filters': ['require_debug_false'], 
      'class': 'django.utils.log.AdminEmailHandler' 
     }, 
     'app': { 
      'level': 'ERROR', 
      'filters': ['require_debug_false'], 
      'class': 'django.utils.log.AdminEmailHandler' 
     }, 
    }, 
    'loggers': { 
     'django.request': { 
      'handlers': ['mail_admins'], 
      'level': 'ERROR', 
      'propagate': True, 
     }, 
    } 
} 

e quindi a suo avviso, si può fare nulla

import logging 
logger = logging.getLogger('app') 

def some_view(request): 
    try: 
     # something 
     if something_wnet_wrong: 
      logger.error('Something went wrong!') 
     return some_http_response 
    except: 
     #something else 
     logger.error(sys.exc_info(), request)   
     return some_other_response 

Se volete rapporto di errore dettagliato, si può provare something like this.

Inoltre, è necessario occuparsi di sensitive information.

1

Io uso soprattutto questo modello con la segnalazione degli errori standard.

import logging  
logger = logging.getLogger('django.request') 

#code block in view 
try: 
    #code that can raise exception 
except: 
    logger.exception('Information') 
#continue as nothing happend 

Si attiverà il costruito nel segnalazione degli errori e logger.exception prenderà lo stack frame. https://docs.djangoproject.com/en/1.8/topics/logging/#making-logging-calls

edit:

ho notato alcune informazioni mancava nella e-mail e per ottenere un traceback esattamente come il costruito nel seguente può essere utilizzato al posto:

logger.exception('Internal Server Error: %s', request.path, 
       extra={'status_code': 500, 'request': request}) 

Maggiori informazioni trovate qui: How to send django exception log manually?