From 4ef51f1c912d49c7650126398c4ac38fef0f795c Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Thu, 11 Sep 2008 23:18:14 -0700 Subject: Moving reformat sql so we can pull this in elsewhere. --- debug_toolbar/panels/sql.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index f23e317..8edfce9 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -36,13 +36,6 @@ class SQLDebugPanel(DebugPanel): self._offset = len(connection.queries) self._sql_time = 0 - def _reformat_sql(self, sql): - sql = sql.replace('`,`', '`, `') - sql = sql.replace('` FROM `', '` \n FROM `') - sql = sql.replace('` WHERE ', '` \n WHERE ') - sql = sql.replace(' ORDER BY ', ' \n ORDER BY ') - return sql - def title(self): self._sql_time = sum(map(lambda q: float(q['time']) * 1000, connection.queries)) return '%d SQL Queries (%.2fms)' % (len(connection.queries), self._sql_time) @@ -53,10 +46,19 @@ class SQLDebugPanel(DebugPanel): def content(self): sql_queries = connection.queries[self._offset:] for query in sql_queries: - query['sql'] = self._reformat_sql(query['sql']) + query['sql'] = reformat_sql(query['sql']) context = { 'queries': sql_queries, 'sql_time': self._sql_time, } return render_to_string('debug_toolbar/panels/sql.html', context) + +def reformat_sql(sql): + sql = sql.replace('`,`', '`, `') + sql = sql.replace('` FROM `', '` \n FROM `') + sql = sql.replace('` WHERE ', '` \n WHERE ') + sql = sql.replace('` INNER JOIN ', '` \n INNER JOIN ') + sql = sql.replace('` OUTER JOIN ', '` \n OUTER JOIN ') + sql = sql.replace(' ORDER BY ', ' \n ORDER BY ') + return sql -- cgit v1.2.3 From 8377ea179568c1fbf8f46db1234e85d689daae0a Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Thu, 11 Sep 2008 23:19:27 -0700 Subject: Adding JSON params to pass to view and adding link for explain. --- debug_toolbar/panels/sql.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 8edfce9..757505a 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -1,3 +1,4 @@ +import simplejson import time from debug_toolbar.panels import DebugPanel from django.db import connection @@ -20,7 +21,7 @@ class DatabaseStatTracker(util.CursorDebugWrapper): 'sql': self.db.ops.last_executed_query(self.cursor, sql, params), 'time': stop - start, 'raw_sql': sql, - 'params': params, + 'params': simplejson.dumps(params), }) util.CursorDebugWrapper = DatabaseStatTracker -- cgit v1.2.3 From e40b2c0fbdbd932be5f9d0550a16b6652de0d38d Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Thu, 18 Sep 2008 13:43:13 -0700 Subject: I noticed the template_rendered signal from the test suite also passed context, so I'm including the context with each template in the Template panel. This should make the designers happy. --- debug_toolbar/panels/template.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/template.py b/debug_toolbar/panels/template.py index f1cf65b..f02b673 100644 --- a/debug_toolbar/panels/template.py +++ b/debug_toolbar/panels/template.py @@ -32,11 +32,11 @@ class TemplateDebugPanel(DebugPanel): def __init__(self, request): super(TemplateDebugPanel, self).__init__(request) - self.templates_used = [] - template_rendered.connect(self._storeRenderedTemplates) + self.templates = [] + template_rendered.connect(self._storeTemplateInfo) - def _storeRenderedTemplates(self, sender, **kwargs): - self.templates_used.append(kwargs['template']) + def _storeTemplateInfo(self, sender, **kwargs): + self.templates.append(kwargs) def title(self): return 'Templates' @@ -45,12 +45,22 @@ class TemplateDebugPanel(DebugPanel): return '' def content(self): - templates = [ - (t.name, t.origin and t.origin.name or 'No origin') - for t in self.templates_used - ] + template_context = [] + for i, d in enumerate(self.templates): + info = {} + # Clean up some info about templates + t = d.get('template', None) + if t.origin and t.origin.name: + t.origin_name = t.origin.name + else: + t.origin_name = 'No origin' + info['template'] = t + # Clean up context for better readability + c = d.get('context', None) + info['context'] = '\n'.join([_d.__repr__() for _d in c.dicts]) + template_context.append(info) context = { - 'templates': templates, + 'templates': template_context, 'template_dirs': settings.TEMPLATE_DIRS, } return render_to_string('debug_toolbar/panels/templates.html', context) -- cgit v1.2.3 From 43bb25c874f765800076285e76b2b0ba1460a597 Mon Sep 17 00:00:00 2001 From: Nowell Strite Date: Fri, 19 Sep 2008 01:17:16 -0400 Subject: Fixed template panel to skip over debug_toolbar templates. Fixed a bug in template context output where rendering would hang while trying to autoescape the context variable output. --- debug_toolbar/panels/template.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/template.py b/debug_toolbar/panels/template.py index f02b673..bda6630 100644 --- a/debug_toolbar/panels/template.py +++ b/debug_toolbar/panels/template.py @@ -50,6 +50,9 @@ class TemplateDebugPanel(DebugPanel): info = {} # Clean up some info about templates t = d.get('template', None) + # Skip templates that we are generating through the debug toolbar. + if t.name.startswith('debug_toolbar/'): + continue if t.origin and t.origin.name: t.origin_name = t.origin.name else: -- cgit v1.2.3 From 8e124b0a129ab351ec6cae30d8358709d4c1430b Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sat, 20 Sep 2008 20:30:45 +0100 Subject: Use pformat for template contexts, which makes it more readable --- debug_toolbar/panels/template.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/template.py b/debug_toolbar/panels/template.py index bda6630..e08f220 100644 --- a/debug_toolbar/panels/template.py +++ b/debug_toolbar/panels/template.py @@ -5,6 +5,8 @@ from django.template.loader import render_to_string from django.test.signals import template_rendered from debug_toolbar.panels import DebugPanel +from pprint import pformat + # Code taken and adapted from Simon Willison and Django Snippets: # http://www.djangosnippets.org/snippets/766/ @@ -60,7 +62,7 @@ class TemplateDebugPanel(DebugPanel): info['template'] = t # Clean up context for better readability c = d.get('context', None) - info['context'] = '\n'.join([_d.__repr__() for _d in c.dicts]) + info['context'] = '\n'.join([pformat(_d) for _d in c.dicts]) template_context.append(info) context = { 'templates': template_context, -- cgit v1.2.3 From 251a7f4eb5efaf6339edd57021e5ce3d53a679b3 Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Sat, 20 Sep 2008 13:46:44 -0700 Subject: Import simplejson from django rather than an external dependency. --- debug_toolbar/panels/sql.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 757505a..cdcbd1b 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -1,9 +1,9 @@ -import simplejson import time from debug_toolbar.panels import DebugPanel from django.db import connection from django.db.backends import util from django.template.loader import render_to_string +from django.utils import simplejson class DatabaseStatTracker(util.CursorDebugWrapper): """ -- cgit v1.2.3 From f40ad85645f27fc4b80683acdbefd01a1da51afd Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Sat, 20 Sep 2008 17:00:19 -0700 Subject: Updating SQL panel to use Pygments for SQL highlighting if it's available, moving the EXPLAIN link to the left to avoid scrolling. I have a feeling that the SQL panel could use a serious security review since we're passing SQL in via GET which is, I'm sure, a big no-no. --- debug_toolbar/panels/sql.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index cdcbd1b..4b059ac 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -57,9 +57,18 @@ class SQLDebugPanel(DebugPanel): def reformat_sql(sql): sql = sql.replace('`,`', '`, `') - sql = sql.replace('` FROM `', '` \n FROM `') - sql = sql.replace('` WHERE ', '` \n WHERE ') - sql = sql.replace('` INNER JOIN ', '` \n INNER JOIN ') - sql = sql.replace('` OUTER JOIN ', '` \n OUTER JOIN ') - sql = sql.replace(' ORDER BY ', ' \n ORDER BY ') + 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 ', '`\nINNER JOIN\n\t') + sql = sql.replace('` OUTER JOIN ', '`\nOUTER JOIN\n\t') + sql = sql.replace(' ORDER BY ', '\nORDER 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(noclasses=True)) + except ImportError: + pass return sql -- cgit v1.2.3 From ee75a75f7e379b492af927b261726bc5d40fdb50 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sat, 20 Sep 2008 23:31:45 +0100 Subject: Show 1 SQL query v.s. 3 SQL queries --- debug_toolbar/panels/sql.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 4b059ac..81834b4 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -39,7 +39,11 @@ class SQLDebugPanel(DebugPanel): def title(self): self._sql_time = sum(map(lambda q: float(q['time']) * 1000, connection.queries)) - return '%d SQL Queries (%.2fms)' % (len(connection.queries), self._sql_time) + return '%d SQL %s (%.2fms)' % ( + len(connection.queries), + (len(connection.queries) == 1) and 'query' or 'queries', + self._sql_time + ) def url(self): return '' -- cgit v1.2.3 From ee810109f7dfb8c70278b5c447b4604bccc987a0 Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Sun, 21 Sep 2008 22:35:15 -0700 Subject: Refactoring middleware and panels so panels have more explicit middleware-like methods to be more clear when panel processing happens. --- debug_toolbar/panels/__init__.py | 20 +++++++++++++++----- debug_toolbar/panels/cache.py | 3 +-- debug_toolbar/panels/headers.py | 7 ++++++- debug_toolbar/panels/request_vars.py | 3 +++ debug_toolbar/panels/sql.py | 6 +++--- debug_toolbar/panels/template.py | 6 ++---- debug_toolbar/panels/timer.py | 10 ++++++---- 7 files changed, 36 insertions(+), 19 deletions(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/__init__.py b/debug_toolbar/panels/__init__.py index 29cec02..54b3318 100644 --- a/debug_toolbar/panels/__init__.py +++ b/debug_toolbar/panels/__init__.py @@ -6,9 +6,10 @@ class DebugPanel(object): """ # name = Base has_content = False # If content returns something, set to true in subclass - - def __init__(self, request): - self.request = request + + # Panel methods + def __init__(self): + pass def dom_id(self): return 'djDebug%sPanel' % (self.name.replace(' ', '')) @@ -20,6 +21,15 @@ class DebugPanel(object): raise NotImplementedError def content(self): - # TODO: This is a bit flaky in that panel.content() returns a string - # that gets inserted into the toolbar HTML template. raise NotImplementedError + + # Standard middleware methods + def process_request(self, request): + pass + + def process_view(self, request, view_func, view_args, view_kwargs): + pass + + def process_response(self, request, response): + pass + diff --git a/debug_toolbar/panels/cache.py b/debug_toolbar/panels/cache.py index 263b62b..613d4d9 100644 --- a/debug_toolbar/panels/cache.py +++ b/debug_toolbar/panels/cache.py @@ -78,7 +78,7 @@ class CacheDebugPanel(DebugPanel): name = 'Cache' has_content = True - def __init__(self, request): + def __init__(self): # This is hackish but to prevent threading issues is somewhat needed if isinstance(cache.cache, CacheStatTracker): cache.cache.reset() @@ -86,7 +86,6 @@ class CacheDebugPanel(DebugPanel): else: self.cache = CacheStatTracker(cache.cache) cache.cache = self.cache - super(CacheDebugPanel, self).__init__(request) def title(self): return 'Cache: %.2fms' % self.cache.total_time diff --git a/debug_toolbar/panels/headers.py b/debug_toolbar/panels/headers.py index 3ab4a95..213198a 100644 --- a/debug_toolbar/panels/headers.py +++ b/debug_toolbar/panels/headers.py @@ -37,8 +37,13 @@ class HeaderDebugPanel(DebugPanel): def url(self): return '' + def process_request(self, request): + self.headers = dict( + [(k, request.META[k]) for k in self.header_filter if k in request.META] + ) + def content(self): context = { - 'headers': dict([(k, self.request.META[k]) for k in self.header_filter if k in self.request.META]), + 'headers': self.headers } return render_to_string('debug_toolbar/panels/headers.html', context) \ No newline at end of file diff --git a/debug_toolbar/panels/request_vars.py b/debug_toolbar/panels/request_vars.py index a137393..88a7204 100644 --- a/debug_toolbar/panels/request_vars.py +++ b/debug_toolbar/panels/request_vars.py @@ -14,6 +14,9 @@ class RequestVarsDebugPanel(DebugPanel): def url(self): return '' + def process_request(self, request): + self.request = request + def content(self): context = { 'get': [(k, self.request.GET.getlist(k)) for k in self.request.GET.iterkeys()], diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 81834b4..b99709f 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -27,13 +27,13 @@ util.CursorDebugWrapper = DatabaseStatTracker class SQLDebugPanel(DebugPanel): """ - Panel that displays information about the SQL queries run while processing the request. + Panel that displays information about the SQL queries run while processing + the request. """ name = 'SQL' has_content = True - def __init__(self, request): - super(SQLDebugPanel, self).__init__(request) + def __init__(self): self._offset = len(connection.queries) self._sql_time = 0 diff --git a/debug_toolbar/panels/template.py b/debug_toolbar/panels/template.py index e08f220..eb20079 100644 --- a/debug_toolbar/panels/template.py +++ b/debug_toolbar/panels/template.py @@ -1,3 +1,4 @@ +from pprint import pformat from django.conf import settings from django.core.signals import request_started from django.dispatch import Signal @@ -5,8 +6,6 @@ from django.template.loader import render_to_string from django.test.signals import template_rendered from debug_toolbar.panels import DebugPanel -from pprint import pformat - # Code taken and adapted from Simon Willison and Django Snippets: # http://www.djangosnippets.org/snippets/766/ @@ -32,8 +31,7 @@ class TemplateDebugPanel(DebugPanel): name = 'Template' has_content = True - def __init__(self, request): - super(TemplateDebugPanel, self).__init__(request) + def __init__(self): self.templates = [] template_rendered.connect(self._storeTemplateInfo) diff --git a/debug_toolbar/panels/timer.py b/debug_toolbar/panels/timer.py index d520191..ea8ed4a 100644 --- a/debug_toolbar/panels/timer.py +++ b/debug_toolbar/panels/timer.py @@ -3,16 +3,18 @@ from debug_toolbar.panels import DebugPanel class TimerDebugPanel(DebugPanel): """ - Panel that displays the time a response took. + Panel that displays the time a response took in milliseconds. """ name = 'Timer' - def __init__(self, request): - super(TimerDebugPanel, self).__init__(request) + def process_request(self, request): self._start_time = time.time() + def process_response(self, request, response): + self.total_time = (time.time() - self._start_time) * 1000 + def title(self): - return 'Time: %0.2fms' % ((time.time() - self._start_time) * 1000) + return 'Time: %0.2fms' % (self.total_time) def url(self): return '' -- cgit v1.2.3 From 7ea7e780b775680be3050a8d6eb71f63b5a1fd34 Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Tue, 23 Sep 2008 19:55:18 -0700 Subject: Updating pygments styles to better match new toolbar styles. --- debug_toolbar/panels/sql.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index b99709f..e4e3c02 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -72,7 +72,7 @@ def reformat_sql(sql): from pygments import highlight from pygments.lexers import SqlLexer from pygments.formatters import HtmlFormatter - sql = highlight(sql, SqlLexer(), HtmlFormatter(noclasses=True)) + sql = highlight(sql, SqlLexer(), HtmlFormatter()) except ImportError: pass return sql -- cgit v1.2.3 From 159e690ff3d07c8821332942ae722bdf0bdf5208 Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Tue, 23 Sep 2008 21:06:39 -0700 Subject: Add catch for non JSON serializable objects and don't show the EXPLAIN link for these. --- debug_toolbar/panels/sql.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index e4e3c02..9223cb7 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -16,12 +16,17 @@ class DatabaseStatTracker(util.CursorDebugWrapper): return self.cursor.execute(sql, params) finally: stop = time.time() + _params = None + try: + _params = simplejson.dumps(params) + except TypeError: + pass # object not JSON serializable # 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, 'raw_sql': sql, - 'params': simplejson.dumps(params), + 'params': _params }) util.CursorDebugWrapper = DatabaseStatTracker -- cgit v1.2.3 From d74431411b5c390379bcac89a60628a26365d8c9 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Wed, 24 Sep 2008 12:40:02 +0200 Subject: Added context processors to TemplateDebugPanel --- debug_toolbar/panels/template.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/template.py b/debug_toolbar/panels/template.py index eb20079..9cab618 100644 --- a/debug_toolbar/panels/template.py +++ b/debug_toolbar/panels/template.py @@ -4,6 +4,7 @@ from django.core.signals import request_started from django.dispatch import Signal from django.template.loader import render_to_string from django.test.signals import template_rendered +from django.template.context import get_standard_processors from debug_toolbar.panels import DebugPanel # Code taken and adapted from Simon Willison and Django Snippets: @@ -44,6 +45,11 @@ class TemplateDebugPanel(DebugPanel): def url(self): return '' + def process_request(self, request): + self.context_processors = dict( + [("%s.%s" % (k.__module__, k.__name__), pformat(k(request))) for k in get_standard_processors()] + ) + def content(self): template_context = [] for i, d in enumerate(self.templates): @@ -65,5 +71,6 @@ class TemplateDebugPanel(DebugPanel): context = { 'templates': template_context, 'template_dirs': settings.TEMPLATE_DIRS, + 'context_processors': self.context_processors, } return render_to_string('debug_toolbar/panels/templates.html', context) -- cgit v1.2.3 From 85d879803c88aa036934d36977a10b5d28b70aaa Mon Sep 17 00:00:00 2001 From: Rob Hudson Date: Wed, 24 Sep 2008 16:23:01 -0700 Subject: Adding a SHA-1 hash to the parameters passed to get the EXPLAIN query to avoid any sort of tampering of the SQL or parameters. --- debug_toolbar/panels/sql.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/sql.py b/debug_toolbar/panels/sql.py index 9223cb7..22d65a7 100644 --- a/debug_toolbar/panels/sql.py +++ b/debug_toolbar/panels/sql.py @@ -1,9 +1,11 @@ import time from debug_toolbar.panels import DebugPanel +from django.conf import settings from django.db import connection from django.db.backends import util from django.template.loader import render_to_string from django.utils import simplejson +from django.utils.hashcompat import sha_constructor class DatabaseStatTracker(util.CursorDebugWrapper): """ @@ -26,7 +28,8 @@ class DatabaseStatTracker(util.CursorDebugWrapper): 'sql': self.db.ops.last_executed_query(self.cursor, sql, params), 'time': stop - start, 'raw_sql': sql, - 'params': _params + 'params': _params, + 'hash': sha_constructor(settings.SECRET_KEY + sql + _params).hexdigest(), }) util.CursorDebugWrapper = DatabaseStatTracker @@ -37,7 +40,7 @@ class SQLDebugPanel(DebugPanel): """ name = 'SQL' has_content = True - + def __init__(self): self._offset = len(connection.queries) self._sql_time = 0 -- cgit v1.2.3 From c70df302e1564a7f7fe7883d3e042419ece1d9e6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 27 Sep 2008 15:50:47 -0400 Subject: added logger panel --- debug_toolbar/panels/logger.py | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 debug_toolbar/panels/logger.py (limited to 'debug_toolbar/panels') diff --git a/debug_toolbar/panels/logger.py b/debug_toolbar/panels/logger.py new file mode 100644 index 0000000..e3fd21e --- /dev/null +++ b/debug_toolbar/panels/logger.py @@ -0,0 +1,73 @@ +import datetime +import logging + +try: + import threading +except ImportError: + threading = None + +from django.template.loader import render_to_string + +from debug_toolbar.panels import DebugPanel + +class ThreadTrackingHandler(logging.Handler): + def __init__(self): + if threading is None: + raise NotImplementedError("threading module is not available, \ + the logging panel cannot be used without it") + logging.Handler.__init__(self) + self.records = {} # a dictionary that maps threads to log records + + def emit(self, record): + self.get_records().append(record) + + def get_records(self, thread=None): + """ + Returns a list of records for the provided thread, of if none is provided, + returns a list for the current thread. + """ + if thread is None: + thread = threading.currentThread() + if thread not in self.records: + self.records[thread] = [] + return self.records[thread] + + def clear_records(self, thread=None): + if thread is None: + thread = threading.currentThread() + if thread in self.records: + del self.records[thread] + +handler = ThreadTrackingHandler() +logging.root.setLevel(logging.NOTSET) +logging.root.addHandler(handler) + +class LoggingPanel(DebugPanel): + name = 'Logging' + has_content = True + + def process_request(self, request): + handler.clear_records() + + def get_and_delete(self): + records = handler.get_records() + handler.clear_records() + return records + + def title(self): + return "Logging (%s message%s)" % (len(handler.get_records()), (len(handler.get_records()) == 1) and '' or 's') + + def url(self): + return '' + + def content(self): + records = [] + for record in self.get_and_delete(): + records.append({ + 'message': record.getMessage(), + 'time': datetime.datetime.fromtimestamp(record.created), + 'level': record.levelname, + 'file': record.pathname, + 'line': record.lineno, + }) + return render_to_string('debug_toolbar/panels/logger.html', {'records': records}) -- cgit v1.2.3