When you are developing Django, you likely want the most verbose debugging output possible. Django uses the logging levels defined by Python logging module, and defines the logging style in a Python dictionary in settings.py. Read more about Django logging.
Example Logging Configuration
My favorite logging configuration is to dump the most verbose output possible to myproject/django.log when DEBUG = True
. This logging output is very verbose. It dumps all HTTP requests, error messaging, SQL queries, and silenced templating errors.
We can also direct Django to dump less verbose output when DEBUG = False
. Python makes this easy.
# Place in your settings.py file, near the bottom LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'my_log_handler': { 'level': 'DEBUG' if DEBUG else 'INFO', 'class': 'logging.FileHandler', 'filename': os.path.join(BASE_DIR, 'django.log'), }, }, 'loggers': { 'django': { 'handlers': ['my_log_handler'], 'level': 'DEBUG' if DEBUG else 'INFO', 'propagate': True, }, }, }
You can also read more about Python logging levels.
Logging Explanation
You will see tons of different logging messages in Django when the logging level is set to DEBUG
. We will explain a few common ones.
Template Level Errors
The Django template renderer uses Python under the hood, but fails silently when Python errors occur. For example, these messages will show up all the time if your template silently fails to look up attributes on users that aren’t logged in.
Traceback (most recent call last): File ".../site-packages/django/template/base.py", line 843, in _resolve_lookup current = getattr(current, bit) File ".../site-packages/django/utils/functional.py", line 216, in inner return func(self._wrapped, *args) AttributeError: 'AnonymousUser' object has no attribute 'username'
SQL Queries
Django will log every single SQL query made (both explicitly and under-the-hood) when the logging level is set to DEBUG
. This is good for debugging, but can slow some complex views down to a crawl. In my experience, 1,000 distinct SQL queries can take about 8-10 seconds to log, but only fractions of a second to run. So, developers be warned. The SQL queries will show the time taken to make the query in milliseconds, followed by the query.
(0.001) SELECT "axes_accessattempt"."id", "axes_accessattempt"."user_agent", "axes_accessattempt"."ip_address", "axes_accessattempt"."username", "axes_accessattempt"."trusted", "axes_accessattempt"."http_accept", "axes_accessattempt"."path_info", "axes_accessattempt"."attempt_time", "axes_accessattempt"."get_data", "axes_accessattempt"."post_data", "axes_accessattempt"."failures_since_start" FROM "axes_accessattempt" WHERE ("axes_accessattempt"."ip_address" = '127.0.0.1' AND "axes_accessattempt"."trusted" = 0) ORDER BY "axes_accessattempt"."attempt_time" DESC; args=('127.0.0.1', False)
Failed HTTP Requests
This output level will also log HTTP requests quite plainly. When the logging level is DEBUG
, it will both failed and successful HTTP requests.
GET /accounts/login/?next=/ HTTP/1.1" 200 2999
Incorrect HOST Headers
If your server has the IP address 123.123.123.123
, and your allowed hosts file doesn’t include it, someone that tries to access your server through that IP address will cause the following error to be logged.
NOTE You should only allow access to your production servers through its domain name. Read more about allowed_hosts.
Invalid HTTP_HOST header: '123.123.123.123'. You may need to add '123.123.123.123' to ALLOWED_HOSTS.
Page Not Found Errors
This error will come up when you or your users request a page that isn’t found and Django returns a 400 error.
Not Found: /some_garbage_url_path_that_doesnt_exist
Summary
Most important errors can be seen in the terminal during development, but it is wise to activate verbose logging for resolving advanced issues and fine-tuning site performance.
Leave a Reply