1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
import datetime
import logging
try:
import threading
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 LogCollector(object):
def __init__(self):
if threading is None:
raise NotImplementedError("threading module is not available, \
the logging panel cannot be used without it")
self.records = {} # a dictionary that maps threads to log records
def add_record(self, record, thread=None):
# Avoid logging SQL queries since they are already in the SQL panel
# TODO: Make this check whether SQL panel is enabled
if record.get('channel', '') == 'django.db.backends':
return
self.get_records(thread).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]
class ThreadTrackingHandler(logging.Handler):
def __init__(self, collector):
logging.Handler.__init__(self)
self.collector = collector
def emit(self, record):
record = {
'message': record.getMessage(),
'time': datetime.datetime.fromtimestamp(record.created),
'level': record.levelname,
'file': record.pathname,
'line': record.lineno,
'channel': record.name,
}
self.collector.add_record(record)
collector = LogCollector()
logging_handler = ThreadTrackingHandler(collector)
logging.root.setLevel(logging.NOTSET)
logging.root.addHandler(logging_handler) # register with logging
try:
import logbook
logbook_supported = True
except ImportError:
# logbook support is optional, so fail silently
logbook_supported = False
if logbook_supported:
class LogbookThreadTrackingHandler(logbook.handlers.Handler):
def __init__(self, collector):
logbook.handlers.Handler.__init__(self, bubble=True)
self.collector = collector
def emit(self, record):
record = {
'message': record.message,
'time': record.time,
'level': record.level_name,
'file': record.filename,
'line': record.lineno,
'channel': record.channel,
}
self.collector.add_record(record)
logbook_handler = LogbookThreadTrackingHandler(collector)
logbook_handler.push_application() # register with logbook
class LoggingPanel(DebugPanel):
name = 'Logging'
has_content = True
def process_request(self, request):
collector.clear_records()
def get_and_delete(self):
records = collector.get_records()
collector.clear_records()
return records
def nav_title(self):
return _("Logging")
def nav_subtitle(self):
# FIXME l10n: use ngettext
return "%s message%s" % (len(collector.get_records()), (len(collector.get_records()) == 1) and '' or 's')
def title(self):
return _('Log Messages')
def url(self):
return ''
def content(self):
records = self.get_and_delete()
context = self.context.copy()
context.update({'records': records})
return render_to_string('debug_toolbar/panels/logger.html', context)
|