Quantcast
Viewing all articles
Browse latest Browse all 56

How to log missing template variable, showing location and context in Django?

I am following this tutorial ("With a logging filter that raises exceptions") to catch all invalid variable names in Django templates.

myproject/mysite/logging.py:

import loggingclass MissingVariableError(Exception):"""  A variable was missing from a template. Used as an alternative to  django.template.base.VariableDoesNotExist, because that exception has some  meaning within the template engine."""class MissingVariableErrorFilter(logging.Filter):"""  Take log messages from Django for missing template variables and turn them  into exceptions."""  ignored_prefixes = ("admin/",  )  def filter(self, record):    if record.msg.startswith("Exception while resolving variable "):      variable_name, template_name = record.args      if not template_name.startswith(self.ignored_prefixes):        raise MissingVariableError(          f"{variable_name!r} missing in {template_name!r}"        ) from None    return False

myproject/settings.py:

LOGGING = {"version": 1,"disable_existing_loggers": False,"filters": {"missing_variable_error": {"()": "www.logging.MissingVariableErrorFilter",        },    },"handlers": {"console": {"class": "logging.StreamHandler",        },    },"root": {"handlers": ["console"],"level": "WARNING",    },"loggers": {"django": {"handlers": ["console"],"level": 'INFO',"propagate": False,        },"django.template": {"level": "DEBUG","filters": ["missing_variable_error"],        },    },}

When I load the main page I get this in the log

Traceback (most recent call last):...  File "/install_dir/site/myproject/mysite/logging.py", line 27, in filter     raise MissingVariableError(www.logging.MissingVariableError: 'exception_notes' missing in 'unknown'

Problem 1: exception_notes does not appear in my site (see note below)

Problem 2: this stack trace is very large and noisy.

Also, the site serves an unfriendly error (this is actually what I do want, sometimes, in debug mode):

#> curl localhostA server error occurred.  Please contact the administrator.

(This exeception_notes seems to be from /python3.10/site-packages/django/views/templates/technical_500.html or /lib/python3.10/site-packages/django/views/templates/technical_500.txt rather than my own files, but that's not really the issue -- I can filter using if 'site-packages/django' in record.pathname although that's a bit hacky.)

I can get better results if I change MissingVariableErrorFilter.filter to simply

def filter (self, record):    return True

which according to this

Is the specified record to be logged? Returns zero for no, nonzero for yes. If deemed appropriate, the record may be modified in-place by this method.

sounds like what should be happening anyway, but doesn't. With this, the site loads as normal (with the missing template variables rendering as empty) but there is this in the log

www_1  | Exception while resolving variable 'form' in template 'index.html'.www_1  | Traceback (most recent call last):www_1  |   File "/django-template-venv/lib/python3.10/site-packages/django/template/base.py", line 880, in _resolve_lookupwww_1  |     current = current[bit]www_1  |   File "/django-template-venv/lib/python3.10/site-packages/django/template/context.py", line 83, in __getitem__www_1  |     raise KeyError(key)www_1  | KeyError: 'form'www_1  | www_1  | During handling of the above exception, another exception occurred:www_1  | www_1  | Traceback (most recent call last):www_1  |   File "/django-template-venv/lib/python3.10/site-packages/django/template/base.py", line 886, in _resolve_lookupwww_1  |     if isinstance(current, BaseContext) and getattr(www_1  | AttributeError: type object 'RequestContext' has no attribute 'form'www_1  | www_1  | During handling of the above exception, another exception occurred:www_1  | www_1  | Traceback (most recent call last):www_1  |   File "/django-template-venv/lib/python3.10/site-packages/django/template/base.py", line 896, in _resolve_lookupwww_1  |     current = current[int(bit)]www_1  | ValueError: invalid literal for int() with base 10: 'form'www_1  | www_1  | During handling of the above exception, another exception occurred:www_1  | www_1  | Traceback (most recent call last):www_1  |   File "/django-template-venv/lib/python3.10/site-packages/django/template/base.py", line 903, in _resolve_lookupwww_1  |     raise VariableDoesNotExist(www_1  | django.template.base.VariableDoesNotExist: Failed lookup for key [form] in [{'True': True, 'False': False, 'None': None}, {'csrf_token': <SimpleLazyObject: 'tuuBGDK1DEzWyNikznwXo85aK8gtQqtRE1knF43l2oZQsGk0CLBMvmewePqvEoBq'>, 'request': <WSGIRequest: GET '/'>, 'user': <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7f2cd093e8f0>>, 'perms': PermWrapper(<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7f2cd093e8f0>>), 'messages': <FallbackStorage: request=<WSGIRequest: GET '/'>>, 'DEFAULT_MESSAGE_LEVELS': {'DEBUG': 10, 'INFO': 20, 'SUCCESS': 25, 'WARNING': 30, 'ERROR': 40}, 'debug': True}, {}, {'request': <WSGIRequest: GET '/'>}, {'user': <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7f2cd093e8f0>>}]

Problem 3: this is better, but I only really need the first (Exception while resolving variable 'form' in template 'index.html'.) and last (django.template.base.VariableDoesNotExist: Failed lookup for key [form] in ...) lines.

Having a filter that simply does return True sounds like it should be redundant, but if I remove django.template from LOGGERS

LOGGING = {"version": 1,"disable_existing_loggers": False,"handlers": {"console": {"class": "logging.StreamHandler",        },    },"root": {"handlers": ["console"],"level": "WARNING",    },"loggers": {"django": {"handlers": ["console"],"level": log_level,"propagate": False,        },    },}

Then I get nothing in the log about the missing template variable at all.

How do I set up logging to:

  • print the name and location of missing template variables (e.g. "foo on index.html line 123")
  • also print the context given to the template
  • optionally (e.g. in debug mode) raise an exception which makes the page load obviously fail

?


Viewing all articles
Browse latest Browse all 56

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>