From time to time the pager goes off, and I need to find the source of a given query hitting MySQL. It might be poorly performing, or flooding MySQL in high volume. In any case, I'd love some instrumentation that could point me at a lead in my Django site that's more specific than a given user or IP address. I'm considering adding a comment to the query that includes some part of the call stack, possibly based on Ned Batchelder's "global request" code[1]. Is there a community maintained solution to similar problems already in the wild? Or failing that, an approach that the community would like to include in Django?----
You received this message because you are subscribed to the Google Groups "Django developers" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-developers/-/PAcaIZ8CvlUJ.
To post to this group, send email to django-d...@googlegroups.com.
To unsubscribe from this group, send email to django-develop...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
Matt
You are modifying the settings on runtime , that practise is not recommended by django and personally i have had bad experience with that...
So the straw man solution we've implemented for now looks like this. (Background: we have a settings.THREADLOCALS construct which serves in a capacity similar to Ned's global requests; also, our monkeypatch_method decorator does what you probably think it does.) First, we've a tiny bit of middleware:from django.conf import settingsclass RequestURIMiddleware:"""Set the request URI in THREADLOCALS so that it can be used to commentSQL queries with what triggered them."""def process_request(self, request):settings.THREADLOCALS.request_uri = request.build_absolute_uri()And then we've monkeypatched the cursor method on BaseDatabaseWrapper like so:
from django.conf import settingsfrom django.db.backends import BaseDatabaseWrapper, utilfrom patchers import monkeypatch_methodimport tracebackclass CommentingCursorWrapper(util.CursorDebugWrapper):def execute(self, sql, *args, **kwargs):"""Before sending to the DB, this adds a comment to the SQL with notes about the query's origin"""try:if getattr(settings, 'SQL_COMMENTS_ALWAYS_TRACEBACK', False):raise AttributeError# THREADLOCALS.request_uri is (usually) populated by RequestURIMiddlewareorigin_comment = ' /* Originated from request to {0}'.format(settings.THREADLOCALS.request_uri)except AttributeError:# If no URI available (e.g., Celery task), report the first non-Django point in the call stack:tb = reversed(traceback.format_stack()[:-1]) # walk it bottom-up, excluding this framefor frame in tb:if 'django' not in frame:origin_comment = ' /* Originated at{0}'.format(frame.split('\n')[0])breakorigin_comment = origin_comment.replace('%', '%%')origin_comment = origin_comment.replace('*/', '\*\/')sql += origin_comment + ' */'return self.cursor.execute(sql, *args, **kwargs)@monkeypatch_method(django.db.backends.BaseDatabaseWrapper)
def cursor(self, *args, **kwargs):return CommentingCursorWrapper(cursor._original_cursor_function(self, *args, **kwargs), self)So in short, we comment the SQL with the URI when it's available, and fall back to the (presumably more expensive to gather) traceback information when it's not.This is just the monkeypatch we're throwing in to solve our immediate problem, but it'd be easy enough to convert into a patch. Before we do, any thoughts/criticisms of this approach?Best,Marty
On Monday, October 22, 2012 11:23:47 PM UTC-5, Matt McClure wrote:Thanks, Russell. That's similar to the approach we were thinking of implementing. Hopefully we'll have a straw man to share shortly.Matt
--
You received this message because you are subscribed to the Google Groups "Django developers" group.
To view this discussion on the web visit https://groups.google.com/d/msg/django-developers/-/-X0AFXuzDv8J.