Files
flask-debugtoolbar/flask_debugtoolbar/panels/logger.py
T
Matt Good 3bea63dc8a Fix werkzeug request logging with the log panel
Werkzeug will disable its default logging setup if another log handler
is already configured.  At some point the initialization order changed
and the logging panel's handler is getting added first now, so
werkzeug's request log will not be printed to the console by default. By
explicitly calling werkzeug's logger we now make sure it's initialized
before the logging panel's handler.

Fixes #33
2013-02-21 10:53:16 -08:00

116 lines
3.2 KiB
Python

from __future__ import with_statement
import datetime
import logging
try:
import threading
except ImportError:
threading = None
from flask_debugtoolbar.panels import DebugPanel
from flask_debugtoolbar.utils import format_fname
_ = lambda x: x
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 = None
_init_lock = threading.Lock()
def _init_once():
global handler
if handler is not None:
return
with _init_lock:
if handler is not None:
return
# Call werkzeug's internal logging to make sure it gets configured
# before we add our handler. Otherwise werkzeug will see our handler
# and not configure console logging for the request log.
# Werkzeug's default log level is INFO so this message probably won't be
# seen.
try:
from werkzeug._internal import _log
except ImportError:
pass
else:
_log('debug', 'Initializing Flask-DebugToolbar log handler')
handler = ThreadTrackingHandler()
logging.root.addHandler(handler)
class LoggingPanel(DebugPanel):
name = 'Logging'
has_content = True
def process_request(self, request):
_init_once()
handler.clear_records()
def get_and_delete(self):
records = handler.get_records()
handler.clear_records()
return records
def nav_title(self):
return _("Logging")
def nav_subtitle(self):
# FIXME l10n: use ngettext
return "%s message%s" % (len(handler.get_records()), (len(handler.get_records()) == 1) and '' or 's')
def title(self):
return _('Log Messages')
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': format_fname(record.pathname),
'file_long': record.pathname,
'line': record.lineno,
})
context = self.context.copy()
context.update({'records': records})
return self.render('panels/logger.html', context)