diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 865990693..c6c6a85ef 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -1339,6 +1339,22 @@ class CommandDispatcher: url = QUrl('qute://help/{}'.format(path)) 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). + """ + 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', modes=[KeyMode.insert], hide=True, scope='window') def open_editor(self): diff --git a/qutebrowser/browser/network/qutescheme.py b/qutebrowser/browser/network/qutescheme.py index a608dd304..f3fe0b799 100644 --- a/qutebrowser/browser/network/qutescheme.py +++ b/qutebrowser/browser/network/qutescheme.py @@ -27,7 +27,7 @@ import functools import configparser import mimetypes -from PyQt5.QtCore import pyqtSlot, QObject +from PyQt5.QtCore import pyqtSlot, QObject, QUrlQuery from PyQt5.QtNetwork import QNetworkReply import qutebrowser @@ -159,22 +159,37 @@ def qute_version(_win_id, _request): @add_handler('plainlog') 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 min 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: text = "Log output was disabled." else: - text = log.ram_handler.dump_log() + query = QUrlQuery(_request.url().query()) + level = query.queryItemValue('level') + text = log.ram_handler.dump_log(html=False, level=level) html = jinja.render('pre.html', title='log', content=text) return html.encode('UTF-8', errors='xmlcharrefreplace') @add_handler('log') 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 min 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: html_log = None else: - html_log = log.ram_handler.dump_log(html=True) + query = QUrlQuery(_request.url().query()) + level = query.queryItemValue('level') + html_log = log.ram_handler.dump_log(html=True, level=level) + html = jinja.render('log.html', title='log', content=html_log) return html.encode('UTF-8', errors='xmlcharrefreplace') diff --git a/qutebrowser/utils/log.py b/qutebrowser/utils/log.py index 577383e1b..0bce09030 100644 --- a/qutebrowser/utils/log.py +++ b/qutebrowser/utils/log.py @@ -429,13 +429,15 @@ class RAMHandler(logging.Handler): # We don't log VDEBUG to RAM. 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. FIXME: We should do all the HTML formatter via jinja2. (probably obsolete when moving to a widget for logging, https://github.com/The-Compiler/qutebrowser/issues/34 """ + # pylint: disable=protected-access + minlevel = logging._nameToLevel.get(level.upper(), VDEBUG_LEVEL) lines = [] fmt = self.html_formatter.format if html else self.format self.acquire() @@ -444,7 +446,8 @@ class RAMHandler(logging.Handler): finally: self.release() for record in records: - lines.append(fmt(record)) + if record.levelno >= minlevel: + lines.append(fmt(record)) return '\n'.join(lines) diff --git a/tests/integration/features/misc.feature b/tests/integration/features/misc.feature index 13a3c33c6..7714385b5 100644 --- a/tests/integration/features/misc.feature +++ b/tests/integration/features/misc.feature @@ -342,7 +342,7 @@ Feature: Various utility commands. Scenario: Running :pyeval with --quiet When I run :debug-pyeval --quiet 1+1 Then "pyeval output: 2" should be logged - + ## https://github.com/The-Compiler/qutebrowser/issues/504 Scenario: Focusing download widget via Tab @@ -367,3 +367,35 @@ Feature: Various utility commands. When I set network -> custom-headers to {"X-Qute-Test": "testvalue"} And I open headers 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" + + 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" + + 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"