diff options
Diffstat (limited to 'debug_toolbar/panels')
| -rw-r--r-- | debug_toolbar/panels/__init__.py | 9 | ||||
| -rw-r--r-- | debug_toolbar/panels/cache.py | 5 | ||||
| -rw-r--r-- | debug_toolbar/panels/headers.py | 3 | ||||
| -rw-r--r-- | debug_toolbar/panels/logger.py | 9 | ||||
| -rw-r--r-- | debug_toolbar/panels/request_vars.py | 5 | ||||
| -rw-r--r-- | debug_toolbar/panels/settings_vars.py | 7 | ||||
| -rw-r--r-- | debug_toolbar/panels/signals.py | 4 | ||||
| -rw-r--r-- | debug_toolbar/panels/sql.py | 81 | ||||
| -rw-r--r-- | debug_toolbar/panels/template.py | 4 | ||||
| -rw-r--r-- | debug_toolbar/panels/timer.py | 14 | ||||
| -rw-r--r-- | debug_toolbar/panels/version.py | 10 |
11 files changed, 112 insertions, 39 deletions
diff --git a/debug_toolbar/panels/__init__.py b/debug_toolbar/panels/__init__.py index 54b3318..cf65aa8 100644 --- a/debug_toolbar/panels/__init__.py +++ b/debug_toolbar/panels/__init__.py @@ -14,7 +14,16 @@ class DebugPanel(object): def dom_id(self): return 'djDebug%sPanel' % (self.name.replace(' ', '')) + def nav_title(self): + """Title showing in toolbar""" + raise NotImplementedError + + def nav_subtitle(self): + """Subtitle showing until title in toolbar""" + return '' + def title(self): + """Title showing in panel""" raise NotImplementedError def url(self): diff --git a/debug_toolbar/panels/cache.py b/debug_toolbar/panels/cache.py index 613d4d9..a05d3cc 100644 --- a/debug_toolbar/panels/cache.py +++ b/debug_toolbar/panels/cache.py @@ -87,9 +87,12 @@ class CacheDebugPanel(DebugPanel): self.cache = CacheStatTracker(cache.cache) cache.cache = self.cache - def title(self): + def nav_title(self): return 'Cache: %.2fms' % self.cache.total_time + def title(self): + return 'Cache Usage' + def url(self): return '' diff --git a/debug_toolbar/panels/headers.py b/debug_toolbar/panels/headers.py index 213198a..06858ef 100644 --- a/debug_toolbar/panels/headers.py +++ b/debug_toolbar/panels/headers.py @@ -31,6 +31,9 @@ class HeaderDebugPanel(DebugPanel): 'SERVER_SOFTWARE', ) + def nav_title(self): + return 'HTTP Headers' + def title(self): return 'HTTP Headers' diff --git a/debug_toolbar/panels/logger.py b/debug_toolbar/panels/logger.py index cb88148..a16b933 100644 --- a/debug_toolbar/panels/logger.py +++ b/debug_toolbar/panels/logger.py @@ -5,6 +5,7 @@ try: except ImportError: threading = None from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ from debug_toolbar.panels import DebugPanel class ThreadTrackingHandler(logging.Handler): @@ -51,8 +52,14 @@ class LoggingPanel(DebugPanel): handler.clear_records() return records + def nav_title(self): + return _("Logging") + + def nav_subtitle(self): + return "%s message%s" % (len(handler.get_records()), (len(handler.get_records()) == 1) and '' or 's') + def title(self): - return "Logging (%s message%s)" % (len(handler.get_records()), (len(handler.get_records()) == 1) and '' or 's') + return 'Log Messages' def url(self): return '' diff --git a/debug_toolbar/panels/request_vars.py b/debug_toolbar/panels/request_vars.py index 88a7204..d0a8c19 100644 --- a/debug_toolbar/panels/request_vars.py +++ b/debug_toolbar/panels/request_vars.py @@ -8,9 +8,12 @@ class RequestVarsDebugPanel(DebugPanel): name = 'RequestVars' has_content = True + def nav_title(self): + return 'Request Vars' + def title(self): return 'Request Vars' - + def url(self): return '' diff --git a/debug_toolbar/panels/settings_vars.py b/debug_toolbar/panels/settings_vars.py index e090718..f30f601 100644 --- a/debug_toolbar/panels/settings_vars.py +++ b/debug_toolbar/panels/settings_vars.py @@ -1,8 +1,10 @@ from django.conf import settings from django.template.loader import render_to_string from django.views.debug import get_safe_settings +from django.utils.translation import ugettext_lazy as _ from debug_toolbar.panels import DebugPanel + class SettingsVarsDebugPanel(DebugPanel): """ A panel to display all variables in django.conf.settings @@ -10,8 +12,11 @@ class SettingsVarsDebugPanel(DebugPanel): name = 'SettingsVars' has_content = True + def nav_title(self): + return _('Settings') + def title(self): - return 'Settings' + return 'Settings from <code>%s</code>' % settings.SETTINGS_MODULE def url(self): return '' diff --git a/debug_toolbar/panels/signals.py b/debug_toolbar/panels/signals.py index 7fe382e..56fbfd4 100644 --- a/debug_toolbar/panels/signals.py +++ b/debug_toolbar/panels/signals.py @@ -7,6 +7,7 @@ from django.db.models.signals import class_prepared, pre_init, post_init, \ pre_save, post_save, pre_delete, post_delete, post_syncdb from django.dispatch.dispatcher import WEAKREF_TYPES from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ try: from django.db.backends.signals import connection_created @@ -34,6 +35,9 @@ class SignalDebugPanel(DebugPanel): 'post_syncdb': post_syncdb, } + def nav_title(self): + return _("Signals") + def title(self): return "Signals" 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 + diff --git a/debug_toolbar/panels/template.py b/debug_toolbar/panels/template.py index e99b9c5..f090c78 100644 --- a/debug_toolbar/panels/template.py +++ b/debug_toolbar/panels/template.py @@ -7,6 +7,7 @@ from django.dispatch import Signal from django.template.context import get_standard_processors from django.template.loader import render_to_string from django.test.signals import template_rendered +from django.utils.translation import ugettext_lazy as _ from debug_toolbar.panels import DebugPanel # Code taken and adapted from Simon Willison and Django Snippets: @@ -41,6 +42,9 @@ class TemplateDebugPanel(DebugPanel): def _store_template_info(self, sender, **kwargs): self.templates.append(kwargs) + def nav_title(self): + return _('Templates') + def title(self): num_templates = len([t for t in self.templates if not t['template'].name.startswith('debug_toolbar/')]) diff --git a/debug_toolbar/panels/timer.py b/debug_toolbar/panels/timer.py index 352bf55..4e390f6 100644 --- a/debug_toolbar/panels/timer.py +++ b/debug_toolbar/panels/timer.py @@ -4,9 +4,9 @@ except ImportError: pass # Will fail on Win32 systems import time from django.template.loader import render_to_string +from django.utils.translation import ugettext_lazy as _ from debug_toolbar.panels import DebugPanel - class TimerDebugPanel(DebugPanel): """ Panel that displays the time a response took in milliseconds. @@ -31,13 +31,19 @@ class TimerDebugPanel(DebugPanel): if self.has_resource: self._end_rusage = resource.getrusage(resource.RUSAGE_SELF) - def title(self): + def nav_title(self): + return _('Time') + + def nav_subtitle(self): if self.has_resource: utime = self._end_rusage.ru_utime - self._start_rusage.ru_utime stime = self._end_rusage.ru_stime - self._start_rusage.ru_stime - return 'Time: %0.2fms, %0.2fms CPU' % (self.total_time, (utime + stime) * 1000.0) + return 'CPU: %0.2fms (%0.2fms)' % ((utime + stime) * 1000.0, self.total_time) else: - return 'Time: %0.2fms' % (self.total_time) + return 'TOTAL: %0.2fms' % (self.total_time) + + def title(self): + return 'Resource Usage' def url(self): return '' diff --git a/debug_toolbar/panels/version.py b/debug_toolbar/panels/version.py index 7ea6543..3d82dd0 100644 --- a/debug_toolbar/panels/version.py +++ b/debug_toolbar/panels/version.py @@ -1,4 +1,5 @@ import django +from django.utils.translation import ugettext_lazy as _ from debug_toolbar.panels import DebugPanel class VersionDebugPanel(DebugPanel): @@ -6,9 +7,12 @@ class VersionDebugPanel(DebugPanel): Panel that displays the Django version. """ name = 'Version' - - def title(self): - return 'Version: %s' % (django.get_version()) + + def nav_title(self): + return _('Django Version') + + def nav_subtitle(self): + return django.get_version() def url(self): return '' |
