aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--debug_toolbar/media/toolbar.css2
-rw-r--r--debug_toolbar/panels/logger.py73
-rw-r--r--debug_toolbar/templates/debug_toolbar/panels/logger.html26
-rw-r--r--debug_toolbar/toolbar/loader.py1
4 files changed, 101 insertions, 1 deletions
diff --git a/debug_toolbar/media/toolbar.css b/debug_toolbar/media/toolbar.css
index 43ac588..bad28c5 100644
--- a/debug_toolbar/media/toolbar.css
+++ b/debug_toolbar/media/toolbar.css
@@ -22,7 +22,7 @@
margin: 0;
padding: 0;
line-height: 30px;
- padding: 8px 10px 9px;
+ padding: 8px 9px 9px;
position: relative;
width: auto;
}
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})
diff --git a/debug_toolbar/templates/debug_toolbar/panels/logger.html b/debug_toolbar/templates/debug_toolbar/panels/logger.html
new file mode 100644
index 0000000..93443be
--- /dev/null
+++ b/debug_toolbar/templates/debug_toolbar/panels/logger.html
@@ -0,0 +1,26 @@
+<h3>Log Messages</h3>
+{% if records %}
+ <table>
+ <thead>
+ <tr>
+ <th>Level</th>
+ <th>Time</th>
+ <th>Message</th>
+ <th>Location</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for record in records %}
+ <tr class="{% cycle 'row1' 'row2' %}">
+ <td>{{ record.level }}</td>
+ <td>{{ record.time|date:"h:i:s m/d/Y" }}</td>
+ <td>{{ record.message }}</td>
+ <td>{{ record.file }}:{{ record.line }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+{% else %}
+ <p>No messages logged.</p>
+{% endif %}
+
diff --git a/debug_toolbar/toolbar/loader.py b/debug_toolbar/toolbar/loader.py
index 0ac9096..e2c9793 100644
--- a/debug_toolbar/toolbar/loader.py
+++ b/debug_toolbar/toolbar/loader.py
@@ -17,6 +17,7 @@ class DebugToolbar(object):
'debug_toolbar.panels.sql.SQLDebugPanel',
'debug_toolbar.panels.cache.CacheDebugPanel',
'debug_toolbar.panels.template.TemplateDebugPanel',
+ 'debug_toolbar.panels.logger.LoggingPanel',
)
self.load_panels()