20

With DEBUG=True, Django exceptions dump to stderr, which is typically sent to a rotating log file by the web server.

With DEBUG=False, Django instead emails the exception to the the ADMINS=.

How can I retain the DEBUG=True behavior with DEBUG=False?

I've read How do you log server errors on django sites and How can I see error logs of Django views and How do you log server errors on django sites. The answer seems to involve some middleware. Is there a code snippet available, or are these batteries included?

Community
  • 1
  • 1
Bryce
  • 8,313
  • 6
  • 55
  • 73

4 Answers4

22

Here is a full working logging configuration. Critical errors are logged to sentry, warnings are sent to admins by emails, normal notice errors are logged to syslog, and debug messages are prompted on the standard output.

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'formatters': {
        'verbose': {
            'format': '[contactor] %(levelname)s %(asctime)s %(message)s'
        },
    },
    'handlers': {
        # Send all messages to console
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        },
        # Send info messages to syslog
        'syslog':{
            'level':'INFO',
            'class': 'logging.handlers.SysLogHandler',
            'facility': SysLogHandler.LOG_LOCAL2,
            'address': '/dev/log',
            'formatter': 'verbose',
        },
        # Warning messages are sent to admin emails
        'mail_admins': {
            'level': 'WARNING',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler',
        },
        # critical errors are logged to sentry
        'sentry': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'raven.contrib.django.handlers.SentryHandler',
        },
    },
    'loggers': {
        # This is the "catch all" logger
        '': {
            'handlers': ['console', 'syslog', 'mail_admins', 'sentry'],
            'level': 'DEBUG',
            'propagate': False,
        },
    }
}
Thibault J
  • 4,336
  • 33
  • 44
  • 1
    Is there a stderr logger option in there somewhere? – Bryce Oct 11 '13 at 06:25
  • 1
    The [logging.StreamHandler class](http://docs.python.org/2/library/logging.handlers.html#streamhandler) default output is stderr. – Thibault J Oct 11 '13 at 08:31
  • So if I checked propagate to True, I'd get the DEBUG=True behavior of logging via Apache? – Bryce Oct 11 '13 at 14:49
  • You might want to check the [DEBUG entry in the doc](https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-DEBUG). It has few to do with logging. The [logging doc](https://docs.djangoproject.com/en/dev/topics/logging/) is also very helpful. – Thibault J Oct 14 '13 at 07:08
  • @ThibaultJ "are prompted on the standard output." where is this standard output you referring to ? :) I am using DigitalOceam, Gunicorn and nginx – PolarBear10 May 11 '19 at 03:27
  • @Matthew I don't know. Better check the specific doc of DigitalOcean. – Thibault J May 13 '19 at 10:00
19

Django uses a logging filter to decide wither the console handler is used or not by default. See also django.utils.log on Github.

To keep the same behavior without filtering messages to console, just disable filtering in your settings.py like this:

from django.utils.log import DEFAULT_LOGGING

DEFAULT_LOGGING['handlers']['console']['filters'] = []
Cani
  • 1,129
  • 10
  • 14
  • where can I find the log files after adding this into the settings.py ? – PolarBear10 May 11 '19 at 03:25
  • Adding this to `settings.py` causes Django to send errors to stderr/stdout. Where this is logged depends on your webserver. – Cani Jul 15 '19 at 08:45
  • Amazing solution! – Ron Sep 05 '19 at 12:07
  • excellent solution, though monkey-patching's django might be frowned upon by some. One could use the following instead LOGGING = deepcopy(DEFAULT_LOGGING) DEFAULT_LOGGING['handlers']['console']['filters'] = [] – Klaas van Schelven Jan 15 '21 at 13:22
5

Here's another way of doing it with complexity half-way between the other answers, logs both to console and file

# settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
       'file': {
           'level': 'DEBUG',
           'class': 'logging.FileHandler',
           'filename': 'log.django',
       },
    },
    'loggers': {
        'django': {
            'handlers': ['console','file'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'),
        },
    },
}
citynorman
  • 4,918
  • 3
  • 38
  • 39
3

Here is the minimal valid Django LOGGING configuration snippet required to log exception tracebacks to stderr.

Put this at the end of your settings.py:

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
        },
    },
    "loggers": {
        "django": {"handlers": ["console"], "level": "INFO"},
    },
}
Chris McCormick
  • 4,356
  • 1
  • 21
  • 19