Log to RAM and display log in crash dialog

This commit is contained in:
Florian Bruhin 2014-05-25 18:46:15 +02:00
parent 353a447dd6
commit f87e7b76f4
2 changed files with 57 additions and 9 deletions

View File

@ -19,6 +19,7 @@
import logging import logging
from logging import getLogger from logging import getLogger
from collections import deque
# The different loggers used. # The different loggers used.
@ -38,29 +39,44 @@ hints = getLogger('hints')
keyboard = getLogger('keyboard') keyboard = getLogger('keyboard')
ram_handler = None
def init_log(args): def init_log(args):
"""Init loggers based on the argparse namespace passed.""" """Init loggers based on the argparse namespace passed."""
global ram_handler
logfilter = LogFilter(None if args.logfilter is None logfilter = LogFilter(None if args.logfilter is None
else args.logfilter.split(',')) else args.logfilter.split(','))
level = 'DEBUG' if args.debug else args.loglevel.upper() level = 'DEBUG' if args.debug else args.loglevel.upper()
try: try:
# pylint: disable=protected-access
numeric_level = logging._nameToLevel[level] numeric_level = logging._nameToLevel[level]
except KeyError: except KeyError:
raise ValueError("Invalid log level: {}".format(args.loglevel)) raise ValueError("Invalid log level: {}".format(args.loglevel))
extended_fmt = ('{asctime} [{levelname}] [{name}|{module}:{funcName}:'
'{lineno}] {message}')
extended_datefmt = '%H:%M:%S'
simple_fmt = '{levelname}: {message}'
simple_datefmt = None
if numeric_level <= logging.DEBUG: if numeric_level <= logging.DEBUG:
fmt = ('{asctime} [{levelname}] [{name}|{module}:{funcName}:{lineno}] ' console_formatter = logging.Formatter(extended_fmt, extended_datefmt,
'{message}') '{')
datefmt = '%Y-%m-%d %H:%M:%S'
else: else:
fmt = '{levelname}: {message}' console_formatter = logging.Formatter(simple_fmt, simple_datefmt, '{')
datefmt = None
formatter = logging.Formatter(fmt, datefmt, '{')
console_handler = logging.StreamHandler() console_handler = logging.StreamHandler()
console_handler.addFilter(logfilter) console_handler.addFilter(logfilter)
console_handler.setLevel(level) console_handler.setLevel(level)
console_handler.setFormatter(formatter) console_handler.setFormatter(console_formatter)
ram_formatter = logging.Formatter(extended_fmt, extended_datefmt, '{')
ram_handler = RAMHandler(capacity=200)
ram_handler.setLevel(logging.NOTSET)
ram_handler.setFormatter(ram_formatter)
root = getLogger() root = getLogger()
root.addHandler(console_handler) root.addHandler(console_handler)
root.addHandler(ram_handler)
root.setLevel(logging.NOTSET) root.setLevel(logging.NOTSET)
@ -91,3 +107,29 @@ class LogFilter(logging.Filter):
elif record.name[len(name)] == '.': elif record.name[len(name)] == '.':
return True return True
return False return False
class RAMHandler(logging.Handler):
"""Logging handler which keeps the messages in a deque in RAM.
Loosly based on logging.BufferingHandler which is unsuitable because it
uses a simple list rather than a deque.
Attributes:
data: A deque containing the logging records.
"""
def __init__(self, capacity):
super().__init__()
self.data = deque(maxlen=capacity)
def emit(self, record):
self.data.append(record)
def dump_log(self):
"""Dump the complete formatted log data as as string."""
lines = []
for record in self.data:
lines.append(self.format(record))
return '\n'.join(lines)

View File

@ -21,13 +21,14 @@ import sys
import traceback import traceback
from urllib.error import URLError from urllib.error import URLError
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QClipboard from PyQt5.QtGui import QClipboard
from PyQt5.QtWidgets import (QDialog, QLabel, QTextEdit, QPushButton, from PyQt5.QtWidgets import (QDialog, QLabel, QTextEdit, QPushButton,
QVBoxLayout, QHBoxLayout, QApplication) QVBoxLayout, QHBoxLayout, QApplication)
import qutebrowser.config.config as config import qutebrowser.config.config as config
import qutebrowser.utils.misc as utils import qutebrowser.utils.misc as utils
import qutebrowser.utils.log as logutils
from qutebrowser.utils.version import version from qutebrowser.utils.version import version
@ -52,8 +53,8 @@ class _CrashDialog(QDialog):
self._hbox = None self._hbox = None
self._lbl = None self._lbl = None
self._gather_crash_info() self._gather_crash_info()
self.setFixedSize(500, 350)
self.setWindowTitle("Whoops!") self.setWindowTitle("Whoops!")
self.resize(QSize(800, 600))
self._vbox = QVBoxLayout(self) self._vbox = QVBoxLayout(self)
self._init_text() self._init_text()
self._txt = QTextEdit() self._txt = QTextEdit()
@ -110,6 +111,11 @@ class _CrashDialog(QDialog):
config.instance().dump_userconfig())) config.instance().dump_userconfig()))
except AttributeError: except AttributeError:
pass pass
try:
self._crash_info.append(("Debug log",
logutils.ram_handler.dump_log()))
except AttributeError:
pass
def _format_crash_info(self): def _format_crash_info(self):
"""Format the gathered crash info to be displayed. """Format the gathered crash info to be displayed.