Skip to content

Commit 1d90d8e

Browse files
nvierobhudson
authored andcommitted
Added support for LogBook. Thanks to Vincent Driessen for the idea and
patch. Signed-off-by: Rob Hudson <rob@cogit8.org>
1 parent 6578f0b commit 1d90d8e

File tree

3 files changed

+61
-21
lines changed

3 files changed

+61
-21
lines changed

README.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Currently, the following panels have been written and are working:
1616
- Templates and context used, and their template paths
1717
- SQL queries including time to execute and links to EXPLAIN each query
1818
- List of signals, their args and receivers
19-
- Logging output via Python's built-in logging module
19+
- Logging output via Python's built-in logging, or via the `logbook <http://logbook.pocoo.org>`_ module
2020

2121
There is also one Django management command currently:
2222

debug_toolbar/panels/logger.py

+58-20
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@
88
from django.utils.translation import ugettext_lazy as _
99
from debug_toolbar.panels import DebugPanel
1010

11-
class ThreadTrackingHandler(logging.Handler):
11+
12+
class LogCollector(object):
1213
def __init__(self):
1314
if threading is None:
1415
raise NotImplementedError("threading module is not available, \
1516
the logging panel cannot be used without it")
16-
logging.Handler.__init__(self)
1717
self.records = {} # a dictionary that maps threads to log records
1818

19-
def emit(self, record):
20-
self.get_records().append(record)
19+
def add_record(self, record, thread=None):
20+
self.get_records(thread).append(record)
2121

2222
def get_records(self, thread=None):
2323
"""
@@ -36,28 +36,75 @@ def clear_records(self, thread=None):
3636
if thread in self.records:
3737
del self.records[thread]
3838

39-
handler = ThreadTrackingHandler()
39+
40+
class ThreadTrackingHandler(logging.Handler):
41+
def __init__(self, collector):
42+
logging.Handler.__init__(self)
43+
self.collector = collector
44+
45+
def emit(self, record):
46+
record = {
47+
'message': record.getMessage(),
48+
'time': datetime.datetime.fromtimestamp(record.created),
49+
'level': record.levelname,
50+
'file': record.pathname,
51+
'line': record.lineno,
52+
'channel': record.name,
53+
}
54+
self.collector.add_record(record)
55+
56+
57+
collector = LogCollector()
58+
logging_handler = ThreadTrackingHandler(collector)
4059
logging.root.setLevel(logging.NOTSET)
41-
logging.root.addHandler(handler)
60+
logging.root.addHandler(logging_handler) # register with logging
61+
62+
try:
63+
import logbook
64+
logbook_supported = True
65+
except ImportError:
66+
# logbook support is optional, so fail silently
67+
logbook_supported = False
68+
69+
if logbook_supported:
70+
class LogbookThreadTrackingHandler(logbook.handlers.Handler):
71+
def __init__(self, collector):
72+
logbook.handlers.Handler.__init__(self, bubble=True)
73+
self.collector = collector
74+
75+
def emit(self, record):
76+
record = {
77+
'message': record.message,
78+
'time': record.time,
79+
'level': record.level_name,
80+
'file': record.filename,
81+
'line': record.lineno,
82+
'channel': record.channel,
83+
}
84+
self.collector.add_record(record)
85+
86+
87+
logbook_handler = LogbookThreadTrackingHandler(collector)
88+
logbook_handler.push_application() # register with logbook
4289

4390
class LoggingPanel(DebugPanel):
4491
name = 'Logging'
4592
has_content = True
4693

4794
def process_request(self, request):
48-
handler.clear_records()
95+
collector.clear_records()
4996

5097
def get_and_delete(self):
51-
records = handler.get_records()
52-
handler.clear_records()
98+
records = collector.get_records()
99+
collector.clear_records()
53100
return records
54101

55102
def nav_title(self):
56103
return _("Logging")
57104

58105
def nav_subtitle(self):
59106
# FIXME l10n: use ngettext
60-
return "%s message%s" % (len(handler.get_records()), (len(handler.get_records()) == 1) and '' or 's')
107+
return "%s message%s" % (len(collector.get_records()), (len(collector.get_records()) == 1) and '' or 's')
61108

62109
def title(self):
63110
return _('Log Messages')
@@ -66,16 +113,7 @@ def url(self):
66113
return ''
67114

68115
def content(self):
69-
records = []
70-
for record in self.get_and_delete():
71-
records.append({
72-
'message': record.getMessage(),
73-
'time': datetime.datetime.fromtimestamp(record.created),
74-
'level': record.levelname,
75-
'file': record.pathname,
76-
'line': record.lineno,
77-
})
78-
116+
records = self.get_and_delete()
79117
context = self.context.copy()
80118
context.update({'records': records})
81119

debug_toolbar/templates/debug_toolbar/panels/logger.html

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<tr>
66
<th>{% trans "Level" %}</th>
77
<th>{% trans "Time" %}</th>
8+
<th>{% trans "Channel" %}</th>
89
<th>{% trans "Message" %}</th>
910
<th>{% trans "Location" %}</th>
1011
</tr>
@@ -14,6 +15,7 @@
1415
<tr class="{% cycle 'djDebugOdd' 'djDebugEven' %}">
1516
<td>{{ record.level }}</td>
1617
<td>{{ record.time|date:"h:i:s m/d/Y" }}</td>
18+
<td>{{ record.channel|default:"-" }}</td>
1719
<td>{{ record.message }}</td>
1820
<td>{{ record.file }}:{{ record.line }}</td>
1921
</tr>

0 commit comments

Comments
 (0)