Comment consignez-vous les erreurs de serveur sur les sites Django

175

Ainsi, lorsque je joue avec le développement, je peux simplement définir settings.DEBUGsur Trueet si une erreur se produit, je peux le voir bien formaté, avec une bonne trace de pile et des informations de demande.

Mais sur le type de site de production, je préfère utiliser DEBUG=Falseet montrer aux visiteurs une page d'erreur standard 500 avec des informations sur lesquelles je travaille sur la correction de ce bogue en ce moment;)
En même temps, j'aimerais avoir un moyen de tout consigner ces informations (trace de la pile et demande d'informations) dans un fichier sur mon serveur - pour que je puisse simplement les afficher sur ma console et regarder les erreurs défiler, m'envoyer le journal toutes les heures ou quelque chose comme ça.

Quelles solutions de journalisation recommanderiez-vous pour un site django, qui répondrait à ces exigences simples? J'ai l'application en cours d'exécution en tant que fcgiserveur et j'utilise le serveur Web Apache comme frontend (bien que je pense à aller sur lighttpd).

kender
la source
quelque chose du champ
Cherian
2
Sentry pour afficher les journaux: readthedocs.org/docs/sentry/en/latest/index.html
Cherian
Le lien partagé par Cherian est désormais mort. Si vous essayez de rechercher Sentry, vous trouverez probablement du matériel pour leur instance officielle payante, mais voici le lien pour configurer une instance auto-hébergée: docs.sentry.io/server Aussi, voici le repo actuellement maintenu: github .com / getsentry / sentry
lehiester

Réponses:

103

Eh bien, quand DEBUG = FalseDjango enverra automatiquement un suivi complet de toute erreur à chaque personne répertoriée dans le ADMINSparamètre, ce qui vous permettra d' obtenir des notifications pratiquement gratuitement. Si vous souhaitez un contrôle plus fin, vous pouvez écrire et ajouter à vos paramètres une classe middleware qui définit une méthode nommée process_exception(), qui aura accès à l'exception qui a été levée:

http://docs.djangoproject.com/en/dev/topics/http/middleware/#process-exception

Votre process_exception()méthode peut alors effectuer n'importe quel type de journalisation que vous souhaitez: écrire sur la console, écrire dans un fichier, etc., etc.

Edit: bien que ce soit un peu moins utile, vous pouvez également écouter le got_request_exceptionsignal, qui sera envoyé chaque fois qu'une exception est rencontrée lors du traitement de la requête:

http://docs.djangoproject.com/en/dev/ref/signals/#got-request-exception

Cela ne pas cependant, vous accédez à donner à l'objet d'exception, la méthode middleware est beaucoup plus facile de travailler avec.

James Bennett
la source
7
Notez que l'utilisation logging.exception('Some message')avec le module de journalisation standard de python fonctionne très bien dans un gestionnaire sginal pour got_request_exception, si tout ce que vous cherchez à faire est de déconnecter les traces de pile. En d'autres termes, la traceback est toujours disponible dans got_request_exception.
TM.
l'exception passée dans process_exception ne semble pas avoir la trace de la pile, y a-t-il un moyen de l'obtenir?
Nick BL
79

Django Sentry est une bonne façon de procéder, comme déjà mentionné, mais il y a un peu de travail à faire pour le configurer correctement (en tant que site Web séparé). Si vous souhaitez simplement tout consigner dans un simple fichier texte, voici la configuration de journalisation à mettre dans votresettings.py

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        # Include the default Django email handler for errors
        # This is what you'd get without configuring logging at all.
        'mail_admins': {
            'class': 'django.utils.log.AdminEmailHandler',
            'level': 'ERROR',
             # But the emails are plain text by default - HTML is nicer
            'include_html': True,
        },
        # Log to a text file that can be rotated by logrotate
        'logfile': {
            'class': 'logging.handlers.WatchedFileHandler',
            'filename': '/var/log/django/myapp.log'
        },
    },
    'loggers': {
        # Again, default Django configuration to email unhandled exceptions
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        # Might as well log any errors anywhere else in Django
        'django': {
            'handlers': ['logfile'],
            'level': 'ERROR',
            'propagate': False,
        },
        # Your own app - this assumes all your logger names start with "myapp."
        'myapp': {
            'handlers': ['logfile'],
            'level': 'WARNING', # Or maybe INFO or DEBUG
            'propagate': False
        },
    },
}
EMP
la source
Je suis d'accord, j'adore Sentry! Je veux en avoir un port .Net (je travaille sur des projets .Net dernièrement).
Gromer
1
Une petite faute de frappe au cas où quelqu'un couper et coller: "propager" au lieu de "propager" à la fin.
user1228295
3
'include_html': Truene rend PAS simplement les e-mails «plus agréables»! Il comprend un suivi complet, y compris les valeurs des paramètres et des variables locales. Selon la documentation, il s'agit d'un problème de sécurité: docs.djangoproject.com/en/1.8/topics/logging/…
Thomas
1
Je suis curieux de savoir si le gestionnaire mail_admins (et l'enregistreur django.request) est nécessaire puisque vous avez «disable_existing_loggers»: False et répliquez simplement la journalisation django par défaut avec ce gestionnaire (et enregistreur). Je mettrai à jour quand j'aurai testé.
DylanYoung
Veuillez mettre à jour cette réponse. Depuis django1.9 change-log: la configuration de journalisation par défaut de Django ne définit plus les enregistreurs «django.request» et «django.security».
narendra-choudhary
30

Évidemment, James a raison, mais si vous vouliez enregistrer des exceptions dans une banque de données, il existe déjà quelques solutions open source:

1) CrashLog est un bon choix: http://code.google.com/p/django-crashlog/

2) Db-Log est également un bon choix: http://code.google.com/p/django-db-log/

Quelle est la différence entre les deux? Presque rien que je puisse voir, donc l'un ou l'autre suffira.

J'ai utilisé les deux et ils fonctionnent bien.

montylounge
la source
15

Un certain temps s'est écoulé depuis la soumission de code la plus utile d'EMP. Je viens de l'implémenter, et tout en me débattant avec une option manage.py, pour essayer de chasser un bogue, j'ai reçu un avertissement d'obsolescence à l'effet qu'avec ma version actuelle de Django (1.5.?) Un filtre require_debug_false est maintenant nécessaire pour le gestionnaire mail_admins.

Voici le code révisé:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
         'require_debug_false': {
             '()': 'django.utils.log.RequireDebugFalse'
         }
     },
    'handlers': {
        # Include the default Django email handler for errors
        # This is what you'd get without configuring logging at all.
        'mail_admins': {
            'class': 'django.utils.log.AdminEmailHandler',
            'level': 'ERROR',
            'filters': ['require_debug_false'],
             # But the emails are plain text by default - HTML is nicer
            'include_html': True,
        },
        # Log to a text file that can be rotated by logrotate
        'logfile': {
            'class': 'logging.handlers.WatchedFileHandler',
            'filename': '/home/username/public_html/djangoprojectname/logfilename.log'
        },
    },
    'loggers': {
        # Again, default Django configuration to email unhandled exceptions
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        # Might as well log any errors anywhere else in Django
        'django': {
            'handlers': ['logfile'],
            'level': 'ERROR',
            'propagate': False,
        },
        # Your own app - this assumes all your logger names start with "myapp."
        'myapp': {
            'handlers': ['logfile'],
            'level': 'DEBUG', # Or maybe INFO or WARNING
            'propagate': False
        },
    },
}
Mike O'Connor
la source
Je suis curieux de savoir si le gestionnaire mail_admins (et l'enregistreur django.request) est nécessaire puisque vous avez «disable_existing_loggers»: False et répliquez simplement la journalisation django par défaut avec ce gestionnaire (et enregistreur). Je mettrai à jour quand j'aurai testé.
DylanYoung
1

J'ai juste eu un problème ennuyeux avec mon fcgiscript. Cela s'est produit avant même que Django ne commence. Le manque de journalisation est tellement douloureux. Quoi qu'il en soit, rediriger stderr vers un fichier comme la toute première chose a beaucoup aidé:

#!/home/user/env/bin/python
sys.stderr = open('/home/user/fcgi_errors', 'a')
jozxyqk
la source