From f97ff555a4d8f22dae83bcfd0c2dcf6e846962c9 Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Fri, 28 Aug 2009 09:21:39 -0700 Subject: Refactored SQL panel to use datetime objects and added a visual display of both duration and sequence to the SQL template. --- debug_toolbar/panels/sql.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'debug_toolbar/panels/sql.py') diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index f12939e..62c0e58 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -1,6 +1,6 @@ import os import SocketServer -import time +from datetime import datetime import traceback import django from django.conf import settings @@ -16,6 +16,10 @@ from debug_toolbar.panels import DebugPanel django_path = os.path.realpath(os.path.dirname(django.__file__)) socketserver_path = os.path.realpath(os.path.dirname(SocketServer.__file__)) +# TODO:This should be set in the toolbar loader as a default and panels should +# get a copy of the toolbar object with access to its config dictionary +SQL_WARNING_THRESHOLD = getattr(settings, 'DEBUG_TOOLBAR_CONFIG', {}).get('SQL_WARNING_THRESHOLD', 500) + def tidy_stacktrace(strace): """ Clean up stacktrace and remove all entries that: @@ -39,11 +43,12 @@ class DatabaseStatTracker(util.CursorDebugWrapper): in `connection.queries`. """ def execute(self, sql, params=()): - start = time.time() + start = datetime.now() try: return self.cursor.execute(sql, params) finally: - stop = time.time() + stop = datetime.now() + duration = ms_from_timedelta(stop - start) stacktrace = tidy_stacktrace(traceback.extract_stack()) _params = '' try: @@ -53,11 +58,14 @@ class DatabaseStatTracker(util.CursorDebugWrapper): # We keep `sql` to maintain backwards compatibility self.db.queries.append({ 'sql': self.db.ops.last_executed_query(self.cursor, sql, params), - 'time': (stop - start) * 1000, # convert to ms + 'duration': duration, 'raw_sql': sql, 'params': _params, 'hash': sha_constructor(settings.SECRET_KEY + sql + _params).hexdigest(), 'stacktrace': stacktrace, + 'start_time': start, + 'stop_time': stop, + 'is_slow': (duration > SQL_WARNING_THRESHOLD) }) util.CursorDebugWrapper = DatabaseStatTracker @@ -77,14 +85,14 @@ class SQLDebugPanel(DebugPanel): return 'SQL' def nav_subtitle(self): - self._sql_time = sum(map(lambda q: float(q['time']), connection.queries)) + self._sql_time = sum([q['duration'] for q in connection.queries[self._offset:]]) num_queries = len(connection.queries) - self._offset return "%d %s in %.2fms" % ( num_queries, (num_queries == 1) and 'query' or 'queries', self._sql_time ) - + def title(self): return 'SQL Queries' @@ -93,8 +101,15 @@ class SQLDebugPanel(DebugPanel): def content(self): sql_queries = connection.queries[self._offset:] + width_ratio_tally = 0 for query in sql_queries: query['sql'] = reformat_sql(query['sql']) + try: + query['width_ratio'] = (query['duration'] / self._sql_time) * 100 + except ZeroDivisionError: + query['width_ratio'] = 0 + query['start_offset'] = width_ratio_tally + width_ratio_tally += query['width_ratio'] context = { 'queries': sql_queries, @@ -103,6 +118,12 @@ class SQLDebugPanel(DebugPanel): } return render_to_string('debug_toolbar/panels/sql.html', context) +def ms_from_timedelta(td): + """ + Given a timedelta object, returns a float representing milliseconds + """ + return (td.seconds * 1000) + (td.microseconds / 1000.0) + def reformat_sql(sql): sql = sql.replace(',', ', ') sql = sql.replace('SELECT ', 'SELECT\n\t') -- cgit v1.2.3