aboutsummaryrefslogtreecommitdiffstats
path: root/debug_toolbar/panels/sql.py
diff options
context:
space:
mode:
authorAlex Gaynor2009-09-10 11:14:27 -0700
committerAlex Gaynor2009-09-10 11:14:27 -0700
commitd6190014abd950f032755fde33ce32c30fc0e754 (patch)
treef070f1275da92ea9efc545ef049c798499286412 /debug_toolbar/panels/sql.py
parent89a0b38316e1822bf22a4f013a6bb12f9db585b8 (diff)
parent608e3ce3e79e3c2d073cf72d1071b71b324485ee (diff)
downloaddjango-debug-toolbar-d6190014abd950f032755fde33ce32c30fc0e754.tar.bz2
handle merge conflicts
Diffstat (limited to 'debug_toolbar/panels/sql.py')
-rw-r--r--debug_toolbar/panels/sql.py81
1 files changed, 53 insertions, 28 deletions
diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py
index c8d50d9..3903b54 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
@@ -18,6 +18,21 @@ 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)
+
+SQL_KEYWORDS = (
+ 'SELECT',
+ 'FROM',
+ 'WHERE',
+ 'INNER JOIN',
+ 'LEFT OUTER JOIN',
+ 'ORDER BY',
+ 'HAVING',
+ 'GROUP BY',
+)
+
def tidy_stacktrace(strace):
"""
Clean up stacktrace and remove all entries that:
@@ -41,11 +56,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:
@@ -55,11 +71,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
@@ -74,47 +93,53 @@ class SQLDebugPanel(DebugPanel):
def __init__(self):
self._offset = len(connection.queries)
self._sql_time = 0
+ self._queries = []
- def title(self):
- self._sql_time = sum(map(lambda q: float(q['time']), connection.queries))
- num_queries = len(connection.queries) - self._offset
- return '%d SQL %s (%.2fms)' % (
+ def nav_title(self):
+ return 'SQL'
+
+ def nav_subtitle(self):
+ self._queries = connection.queries[self._offset:]
+ self._sql_time = sum([q['duration'] for q in self._queries])
+ num_queries = len(self._queries)
+ return "%d %s in %.2fms" % (
num_queries,
(num_queries == 1) and 'query' or 'queries',
self._sql_time
)
+ def title(self):
+ return 'SQL Queries'
+
def url(self):
return ''
def content(self):
- sql_queries = connection.queries[self._offset:]
- for query in sql_queries:
+ width_ratio_tally = 0
+ for query in self._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,
+ 'queries': self._queries,
'sql_time': self._sql_time,
'is_mysql': settings.DATABASE_ENGINE == 'mysql',
}
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')
- sql = sql.replace(' FROM ', '\nFROM\n\t')
- sql = sql.replace(' WHERE ', '\nWHERE\n\t')
- sql = sql.replace(' INNER JOIN', '\n\tINNER JOIN')
- sql = sql.replace(' LEFT OUTER JOIN' , '\n\tLEFT OUTER JOIN')
- sql = sql.replace(' ORDER BY ', '\nORDER BY\n\t')
- sql = sql.replace(' HAVING ', '\nHAVING\n\t')
- sql = sql.replace(' GROUP BY ', '\nGROUP BY\n\t')
- # Use Pygments to highlight SQL if it's available
- try:
- from pygments import highlight
- from pygments.lexers import SqlLexer
- from pygments.formatters import HtmlFormatter
- sql = highlight(sql, SqlLexer(), HtmlFormatter())
- except ImportError:
- pass
+ for kwd in SQL_KEYWORDS:
+ sql = sql.replace(kwd, '<strong>%s</strong>' % (kwd,))
return sql
+