25

Django error reporting obsługuje niezatłoczone wyjątki, wysyłając wiadomość e-mail i (opcjonalnie) pokazuje użytkownikowi ładną stronę błędu 500.Ręczne wywoływanie raportu o błędzie wiadomości e-mail Django

Działa to bardzo dobrze, ale w kilku przypadkach chciałbym umożliwić użytkownikom nieprzerwane kontynuowanie działalności, ale nadal Django wysyła mi raport o błędach e-mail dotyczących wyjątku.

Więc zasadniczo: czy mogę ręcznie wysłać raport o błędach e-mail, nawet jeśli złapię wyjątek?

Oczywiście, chciałbym uniknąć ręcznego generowania wiadomości e-mail z raportem o błędzie.

Odpowiedz

27

można użyć poniższy kod, aby wysłać ręcznie maila o request i wyjątek 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() 
    ) 

można go przetestować w widoku jak ten:

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

Najsłodszy! I chociaż żadna odpowiedź nie wygenerowała dokładnie raportu o błędzie, który jest generowany automatycznie, to podejście dało najwięcej informacji. Jest to podobne do strony błędów Django wyświetlającej się z 'DEBUG = True' – frnhr

+0

Otrzymuję błąd w wierszu 9. Mówi:" Obiekt "wyjątek" nie ma atrybutu "wiadomość". –

+0

dodano edycję, aby działała dla python 3 – maxbellec

3

Tak, możesz ręcznie wysłać raport o błędach e-mail, nawet jeśli zauważysz wyjątek.

Istnieje kilka sposobów na osiągnięcie tego celu.

  1. Można wykorzystać istniejącą domyślną konfigurację rejestratora (oraz związany z nim układ obsługi, udokumentowany here) dla django.request który wysyła wszystkie komunikaty o błędach do obsługi mail_admins, który wysyła niczego zalogowany z log.error z Django. Żądanie, gdy debugowanie jest fałszywe jako wiadomość e-mail przy użyciu adresu AdminEmailHandler, którego obecny punkt połączenia znajduje się pod numerem handle_uncaught_exception.
  2. Możesz dodać dodatkową konfigurację rejestratora, która używa tej samej procedury obsługi, aby wychwycić wyjątek wcześniej niż django.request i wywołać log.error wcześniej.
  3. Możesz podać podklasę django.request, w szczególności handle_uncaught_exception.
  4. Można użyć niestandardowego middleware (for example StandardExceptionMiddleware) lub ExceptionMiddleware
  5. Można ręcznie zadzwonić zawartość EMIT w AdminEmailHandler lub mail.mail_admins bezpośrednio.

Z tych opcji wydaje się, że najpopularniejsze jest rozwiązanie 4.

Na podstawie dodatkowych informacji w komentarzu przykład kodu 2 znajduje się poniżej.

Pierwszy kod, który zostanie dodany do wyświetlenia

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

ten oparty jest o Django documentation for view writing i and introduction to Django logging, ale nie został przetestowany.

Wtedy dodatkowa konfiguracja rejestratora jest dodać do wejścia wywożący drewno (jak za here)

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

Chcę wyzwolić raport o błędach z widoku, a następnie kontynuować pracę w zwykły sposób (tj. Zezwolić na widok, aby zwrócił HttpResponse), więc nie sądzę, że zrobi to oprogramowanie pośrednie. Czy też brakuje mi czegoś, komentarz @Bandon również wskazuje na oprogramowanie pośrednie? Opcje 1 i 2 wydają się być odpowiedzią. Chcesz dodać przykład kodu? – frnhr

6

Wystarczy prosty setup obsługi dziennika w ustawieniach.

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, 
     }, 
    } 
} 

a następnie w widoku można zrobić coś

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 

Jeśli chcesz szczegółowy raport o błędzie, można spróbować something like this.

Musisz również zająć się sensitive information.

1

Najczęściej ten schemat ze standardowym raportowaniem błędów.

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 

To spowoduje wbudowanego raportowania błędów i logger.exception złapie ramkę stosu. https://docs.djangoproject.com/en/1.8/topics/logging/#making-logging-calls

edit:

zauważyłem kilka informacji brakowało w wiadomości e-mail i uzyskać dokładną traceback jak zbudowany w następstwie może być stosowany zamiast:

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

Więcej informacji znaleźć tutaj: How to send django exception log manually?

Powiązane problemy