Merge branch 'messages' of https://github.com/rcorre/qutebrowser into rcorre-messages

This commit is contained in:
Florian Bruhin 2016-05-15 11:20:06 +02:00
commit e21039094d
5 changed files with 101 additions and 9 deletions

View File

@ -1339,6 +1339,27 @@ class CommandDispatcher:
url = QUrl('qute://help/{}'.format(path)) url = QUrl('qute://help/{}'.format(path))
self._open(url, tab, bg, window) self._open(url, tab, bg, window)
@cmdutils.register(instance='command-dispatcher', scope='window')
def messages(self, level='error', plain=False, tab=False, bg=False,
window=False):
"""Show a log of past messages.
Args:
level: Include messages with `level` or higher severity.
Valid values: vdebug, debug, info, warning, error, critical.
plain: Whether to show plaintext (as opposed to html).
tab: Open in a new tab.
bg: Open in a background tab.
window: Open in a new window.
"""
if level.upper() not in log.LOG_LEVELS:
raise cmdexc.CommandError("Invalid log level {}!".format(level))
if plain:
url = QUrl('qute://plainlog?level={}'.format(level))
else:
url = QUrl('qute://log?level={}'.format(level))
self._open(url, tab, bg, window)
@cmdutils.register(instance='command-dispatcher', @cmdutils.register(instance='command-dispatcher',
modes=[KeyMode.insert], hide=True, scope='window') modes=[KeyMode.insert], hide=True, scope='window')
def open_editor(self): def open_editor(self):

View File

@ -26,6 +26,7 @@ Module attributes:
import functools import functools
import configparser import configparser
import mimetypes import mimetypes
import urllib.parse
from PyQt5.QtCore import pyqtSlot, QObject from PyQt5.QtCore import pyqtSlot, QObject
from PyQt5.QtNetwork import QNetworkReply from PyQt5.QtNetwork import QNetworkReply
@ -158,23 +159,36 @@ def qute_version(_win_id, _request):
@add_handler('plainlog') @add_handler('plainlog')
def qute_plainlog(_win_id, _request): def qute_plainlog(_win_id, request):
"""Handler for qute:plainlog. Return HTML content as bytes.""" """Handler for qute:plainlog. Return HTML content as bytes.
An optional query parameter specifies the minimum log level to print.
For example, qute://log?level=warning prints warnings and errors.
Level can be one of: vdebug, debug, info, warning, error, critical.
"""
if log.ram_handler is None: if log.ram_handler is None:
text = "Log output was disabled." text = "Log output was disabled."
else: else:
text = log.ram_handler.dump_log() level = urllib.parse.parse_qs(request.url().query()).get('level')[0]
text = log.ram_handler.dump_log(html=False, level=level)
html = jinja.render('pre.html', title='log', content=text) html = jinja.render('pre.html', title='log', content=text)
return html.encode('UTF-8', errors='xmlcharrefreplace') return html.encode('UTF-8', errors='xmlcharrefreplace')
@add_handler('log') @add_handler('log')
def qute_log(_win_id, _request): def qute_log(_win_id, request):
"""Handler for qute:log. Return HTML content as bytes.""" """Handler for qute:log. Return HTML content as bytes.
An optional query parameter specifies the minimum log level to print.
For example, qute://log?level=warning prints warnings and errors.
Level can be one of: vdebug, debug, info, warning, error, critical.
"""
if log.ram_handler is None: if log.ram_handler is None:
html_log = None html_log = None
else: else:
html_log = log.ram_handler.dump_log(html=True) level = urllib.parse.parse_qs(request.url().query()).get('level')[0]
html_log = log.ram_handler.dump_log(html=True, level=level)
html = jinja.render('log.html', title='log', content=html_log) html = jinja.render('log.html', title='log', content=html_log)
return html.encode('UTF-8', errors='xmlcharrefreplace') return html.encode('UTF-8', errors='xmlcharrefreplace')

View File

@ -64,13 +64,21 @@ LOG_COLORS = {
'CRITICAL': 'red', 'CRITICAL': 'red',
} }
# We first monkey-patch logging to support our VDEBUG level before getting the # We first monkey-patch logging to support our VDEBUG level before getting the
# loggers. Based on http://stackoverflow.com/a/13638084 # loggers. Based on http://stackoverflow.com/a/13638084
VDEBUG_LEVEL = 9 VDEBUG_LEVEL = 9
logging.addLevelName(VDEBUG_LEVEL, 'VDEBUG') logging.addLevelName(VDEBUG_LEVEL, 'VDEBUG')
logging.VDEBUG = VDEBUG_LEVEL logging.VDEBUG = VDEBUG_LEVEL
LOG_LEVELS = {
'VDEBUG': logging.VDEBUG,
'DEBUG': logging.DEBUG,
'INFO': logging.INFO,
'WARNING': logging.WARNING,
'ERROR': logging.ERROR,
'CRITICAL': logging.CRITICAL,
}
def vdebug(self, msg, *args, **kwargs): def vdebug(self, msg, *args, **kwargs):
"""Log with a VDEBUG level. """Log with a VDEBUG level.
@ -430,13 +438,14 @@ class RAMHandler(logging.Handler):
# We don't log VDEBUG to RAM. # We don't log VDEBUG to RAM.
self._data.append(record) self._data.append(record)
def dump_log(self, html=False): def dump_log(self, html=False, level='vdebug'):
"""Dump the complete formatted log data as as string. """Dump the complete formatted log data as as string.
FIXME: We should do all the HTML formatter via jinja2. FIXME: We should do all the HTML formatter via jinja2.
(probably obsolete when moving to a widget for logging, (probably obsolete when moving to a widget for logging,
https://github.com/The-Compiler/qutebrowser/issues/34 https://github.com/The-Compiler/qutebrowser/issues/34
""" """
minlevel = LOG_LEVELS.get(level.upper(), VDEBUG_LEVEL)
lines = [] lines = []
fmt = self.html_formatter.format if html else self.format fmt = self.html_formatter.format if html else self.format
self.acquire() self.acquire()
@ -445,6 +454,7 @@ class RAMHandler(logging.Handler):
finally: finally:
self.release() self.release()
for record in records: for record in records:
if record.levelno >= minlevel:
lines.append(fmt(record)) lines.append(fmt(record))
return '\n'.join(lines) return '\n'.join(lines)

View File

@ -366,6 +366,14 @@ def check_contents_plain(quteproc, text):
assert text in content assert text in content
@bdd.then(bdd.parsers.parse('the page should not contain the plaintext '
'"{text}"'))
def check_not_contents_plain(quteproc, text):
"""Check the current page's content based on a substring."""
content = quteproc.get_content().strip()
assert text not in content
@bdd.then(bdd.parsers.parse('the json on the page should be:\n{text}')) @bdd.then(bdd.parsers.parse('the json on the page should be:\n{text}'))
def check_contents_json(quteproc, text): def check_contents_json(quteproc, text):
"""Check the current page's content as json.""" """Check the current page's content as json."""

View File

@ -379,3 +379,42 @@ Feature: Various utility commands.
When I set network -> custom-headers to {"X-Qute-Test": "testvalue"} When I set network -> custom-headers to {"X-Qute-Test": "testvalue"}
And I open headers And I open headers
Then the header X-Qute-Test should be set to testvalue Then the header X-Qute-Test should be set to testvalue
## :messages
Scenario: Showing error messages
When I run :message-error the-error-message
And I run :message-warning the-warning-message
And I run :message-info the-info-message
And I run :messages
Then the error "the-error-message" should be shown
And the warning "the-warning-message" should be shown
And the page should contain the plaintext "the-error-message"
And the page should not contain the plaintext "the-warning-message"
And the page should not contain the plaintext "the-info-message"
Scenario: Showing messages of type 'warning' or greater
When I run :message-error the-error-message
And I run :message-warning the-warning-message
And I run :message-info the-info-message
And I run :messages warning
Then the error "the-error-message" should be shown
And the warning "the-warning-message" should be shown
And the page should contain the plaintext "the-error-message"
And the page should contain the plaintext "the-warning-message"
And the page should not contain the plaintext "the-info-message"
Scenario: Showing messages of type 'info' or greater
When I run :message-error the-error-message
And I run :message-warning the-warning-message
And I run :message-info the-info-message
And I run :messages info
Then the error "the-error-message" should be shown
And the warning "the-warning-message" should be shown
And the page should contain the plaintext "the-error-message"
And the page should contain the plaintext "the-warning-message"
And the page should contain the plaintext "the-info-message"
Scenario: Showing messages of an invalid level
When I run :messages cataclysmic
Then the error "Invalid log level cataclysmic!" should be shown