21

I did some searching, but I'm wondering if anyone has a snippet of a logging configuration to get Django to just output a stack trace to stdout (so I can see it in the Terminal window) when it encounters an error during a request. This is specifically for local development/debugging and mainly for when I do AJAX post requests and I have to look at the HTML in Firebug to figure out what line the error occurred on.

Bialecki
  • 30,061
  • 36
  • 87
  • 109
  • "Terminal Window"? You're running `django-admin.py runserver`? – S.Lott May 04 '11 at 15:56
  • 1
    Yes, `manage.py runserver` locally, but this would be helpful for production as well, although there I get emails, so less of an issue. – Bialecki May 04 '11 at 16:05
  • the "production" approach depends on how you're integrated with Apache, so you'll need to provide yet more details on that configuration to be sure we understand. – S.Lott May 04 '11 at 16:08
  • @SLott Good point, for now I'll edit the question to be specifically about local development. Thanks for pointing that out. – Bialecki May 04 '11 at 17:28

6 Answers6

37

Another method is with LOGGING. Specifically you get a stacktrace when running ./manage.py runserver by adding the following to the settings.py file:

LOGGING = {
    'version': 1,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.request': {
            'handlers':['console'],
            'propagate': True,
            'level':'DEBUG',
        }
    },
}

This syntax comes from the Django documentation Configuring Logging and can be further modified to increase or decrease the amount of console-logging.

Also the 5XX responses are raised as ERROR messages and 4XX responses are raised as WARNING messages.

Note that this question & answer has a 2013 duplicate here.

Community
  • 1
  • 1
Mike Biglan MS
  • 1,822
  • 1
  • 20
  • 20
28

It's strange nobody mentioned the DEBUG_PROPAGATE_EXCEPTIONS setting. It's not for production, but very easy to use for at test/debugging environment. Simply add to settings.py:

DEBUG_PROPAGATE_EXCEPTIONS = True
Tonechas
  • 13,398
  • 16
  • 46
  • 80
Ilia Barahovsky
  • 10,158
  • 8
  • 41
  • 52
  • 2
    Exactly this seems the most appropriate answer :) – sudhanshu Feb 28 '16 at 11:23
  • 1
    +1 for what is worth, after a couple of hours debugging a DRF issue and with no more tests/options to try, you literally saved my day... – jliendo Apr 03 '16 at 15:19
  • 1
    This should definitely be the accepted answer, thank you so much! – Eli Rose Jun 07 '16 at 17:29
  • What's the difference between this and using the LOGGING json item in the other answer? – Jay May 10 '21 at 11:34
  • 1
    @Jay with LOGGING you might turn on a lot of log messages from various spots in application. In production setting, this is apparently the most correct approach. But for quick and dirty debugging having only exceptions printed to a console should do. – Ilia Barahovsky May 10 '21 at 16:44
25

You can create a piece of middleware to do this. Here's a modified snippet I'm using for a project:

class ExceptionLoggingMiddleware(object):
    def process_exception(self, request, exception):
        import traceback
        print traceback.format_exc()

Place this handler in your middleware part of the Django settings.

Dan Breen
  • 12,626
  • 4
  • 38
  • 49
  • The format for these exceptions have changed since this answer (understandably!). The updated format can be seen at: https://stackoverflow.com/a/42233213/366529 – dKen Aug 07 '22 at 07:56
2

I had a similar problem, but the middleware option didn't help me. The reason is that I'm using django-jsonview 0.4.3 which provides a decorator that converts a dictionary into a valid json http response, even when the decorated function fails, so process_exception middleware method is never called. I checked the code of this decorator and it seems that it tries to log the error doing this:

...
except Exception as e:
    logger = logging.getLogger('django.request')
    logger.exception(unicode(e))

However, I don't know why, this is not working and nothing is logged in my bash console. I should find out why this in happening. Meanwhile, I'm using an extra decorator:

def log_errors(func):
    if not settings.DEBUG:
        return func

    def wrapper(request, *args, **kwargs):
        try:
            return func(request, *args, **kwargs)
        except:
            print traceback.format_exc()
    return wrapper

Then, in all my json views:

@json_view
@log_errors
def my_view(request):
    ....
matiascelasco
  • 1,145
  • 2
  • 13
  • 18
2

I usually use this:

    except Exception,e:
        # Get line
        trace=traceback.extract_tb(sys.exc_info()[2])
        # Add the event to the log
        output ="Error in the server: %s.\n" % (e)
        output+="\tTraceback is:\n"
        for (file,linenumber,affected,line)  in trace:
            output+="\t> Error at function %s\n" % (affected)
            output+="\t  At: %s:%s\n" % (file,linenumber)
            output+="\t  Source: %s\n" % (line)
        output+="\t> Exception: %s\n" % (e)

Then I use "output" for whatever I need: print to stdout, send an email, etc...

Juanmi Taboada
  • 539
  • 10
  • 25
  • I think there are better answers here, but it's also worth pointing out that you might as well just call `import traceback; traceback.print_exc()` instead of these many lines. – Christopher Armstrong Feb 13 '19 at 23:27
  • 1
    In your way you are not able to do anything with the the exception, so I still prefer mine because is more flexible and is an example of working with: filename, line number and line of code which produced the Exception. – Juanmi Taboada Feb 14 '19 at 06:09
0

Subclass WSGI handler, do whatever you want with traceback in your defined handle_uncaught_exception, and use your WSGIHandler instead of the one provided by django when deploying.

import traceback
from django.core.handlers.wsgi import WSGIHandler

class MyWSGIHandler(WSGIHandler):
    """WSGI Handler which prints traceback to stderr"""
    def handle_uncaught_exception(self, request, resolver, exc_info):
        traceback.print_tb(exc_info[2], file=sys.stderr)
        return super(WSGIHandler, self).handle_uncaught_exception(request, resolver, exc_info)

Used with Apache/mod_wsgi, this should write traceback in Apache's error log

Imran
  • 87,203
  • 23
  • 98
  • 131