Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 930f33bfe9
Fetching contributors…

Cannot retrieve contributors at this time

file 125 lines (100 sloc) 3.851 kb
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
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)
Something went wrong with that request. Please try again.