Merge branch 'knaggita-issue52'

This commit is contained in:
Florian Bruhin 2016-08-19 15:28:18 +02:00
commit 60001ec8b1
7 changed files with 106 additions and 6 deletions

View File

@ -39,6 +39,8 @@ Added
to focus the previous/next category in the completion (bound to `<Ctrl-Tab>` to focus the previous/next category in the completion (bound to `<Ctrl-Tab>`
and `<Ctrl-Shift-Tab>` by default). and `<Ctrl-Shift-Tab>` by default).
- New `:click-element` command to fake a click on a element. - New `:click-element` command to fake a click on a element.
- New `:debug-log-filter` command to change console log filtering on-the-fly.
- New `:debug-log-level` command to change the console loglevel on-the-fly.
Changed Changed
~~~~~~~ ~~~~~~~

View File

@ -199,6 +199,7 @@ Contributors, sorted by the number of commits in descending order:
* Brian Jackson * Brian Jackson
* sbinix * sbinix
* neeasade * neeasade
* knaggita
* jnphilipp * jnphilipp
* Tobias Patzl * Tobias Patzl
* Stefan Tatschner * Stefan Tatschner
@ -224,7 +225,6 @@ Contributors, sorted by the number of commits in descending order:
* zwarag * zwarag
* xd1le * xd1le
* oniondreams * oniondreams
* knaggita
* issue * issue
* haxwithaxe * haxwithaxe
* evan * evan

View File

@ -1449,6 +1449,8 @@ These commands are mainly intended for debugging. They are hidden if qutebrowser
|<<debug-crash,debug-crash>>|Crash for debugging purposes. |<<debug-crash,debug-crash>>|Crash for debugging purposes.
|<<debug-dump-page,debug-dump-page>>|Dump the current page's content to a file. |<<debug-dump-page,debug-dump-page>>|Dump the current page's content to a file.
|<<debug-log-capacity,debug-log-capacity>>|Change the number of log lines to be stored in RAM. |<<debug-log-capacity,debug-log-capacity>>|Change the number of log lines to be stored in RAM.
|<<debug-log-filter,debug-log-filter>>|Change the log filter for console logging.
|<<debug-log-level,debug-log-level>>|Change the log level for console logging.
|<<debug-pyeval,debug-pyeval>>|Evaluate a python string and display the results as a web page. |<<debug-pyeval,debug-pyeval>>|Evaluate a python string and display the results as a web page.
|<<debug-set-fake-clipboard,debug-set-fake-clipboard>>|Put data into the fake clipboard and enable logging, used for tests. |<<debug-set-fake-clipboard,debug-set-fake-clipboard>>|Put data into the fake clipboard and enable logging, used for tests.
|<<debug-trace,debug-trace>>|Trace executed code via hunter. |<<debug-trace,debug-trace>>|Trace executed code via hunter.
@ -1500,6 +1502,24 @@ Change the number of log lines to be stored in RAM.
==== positional arguments ==== positional arguments
* +'capacity'+: Number of lines for the log. * +'capacity'+: Number of lines for the log.
[[debug-log-filter]]
=== debug-log-filter
Syntax: +:debug-log-filter 'filters'+
Change the log filter for console logging.
==== positional arguments
* +'filters'+: A comma separated list of logger names.
[[debug-log-level]]
=== debug-log-level
Syntax: +:debug-log-level 'level'+
Change the log level for console logging.
==== positional arguments
* +'level'+: The log level to set.
[[debug-pyeval]] [[debug-pyeval]]
=== debug-pyeval === debug-pyeval
Syntax: +:debug-pyeval [*--quiet*] 's'+ Syntax: +:debug-pyeval [*--quiet*] 's'+

View File

@ -22,6 +22,7 @@
import functools import functools
import types import types
import traceback import traceback
import logging
try: try:
import hunter import hunter
@ -249,6 +250,34 @@ def log_capacity(capacity: int):
log.ram_handler.change_log_capacity(capacity) log.ram_handler.change_log_capacity(capacity)
@cmdutils.register(debug=True)
@cmdutils.argument('level', choices=sorted(
(level.lower() for level in log.LOG_LEVELS),
key=lambda e: log.LOG_LEVELS[e.upper()]))
def debug_log_level(level: str):
"""Change the log level for console logging.
Args:
level: The log level to set.
"""
log.console_handler.setLevel(log.LOG_LEVELS[level.upper()])
@cmdutils.register(debug=True)
def debug_log_filter(filters: str):
"""Change the log filter for console logging.
Args:
filters: A comma separated list of logger names.
"""
if set(filters.split(',')).issubset(log.LOGGER_NAMES):
log.console_filter.names = filters.split(',')
else:
raise cmdexc.CommandError("filters: Invalid value {} - expected one "
"of: {}".format(filters,
', '.join(log.LOGGER_NAMES)))
@cmdutils.register() @cmdutils.register()
@cmdutils.argument('current_win_id', win_id=True) @cmdutils.argument('current_win_id', win_id=True)
def window_only(current_win_id): def window_only(current_win_id):

View File

@ -87,6 +87,15 @@ LOG_LEVELS = {
'CRITICAL': logging.CRITICAL, 'CRITICAL': logging.CRITICAL,
} }
LOGGER_NAMES = [
'statusbar', 'completion', 'init', 'url',
'destroy', 'modes', 'webview', 'misc',
'mouse', 'procs', 'hints', 'keyboard',
'commands', 'signals', 'downloads',
'js', 'qt', 'rfc6266', 'ipc', 'shlexer',
'save', 'message', 'config', 'sessions'
]
def vdebug(self, msg, *args, **kwargs): def vdebug(self, msg, *args, **kwargs):
"""Log with a VDEBUG level. """Log with a VDEBUG level.
@ -131,6 +140,8 @@ sessions = logging.getLogger('sessions')
ram_handler = None ram_handler = None
console_handler = None
console_filter = None
def stub(suffix=''): def stub(suffix=''):
@ -149,6 +160,7 @@ class CriticalQtWarning(Exception):
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 console
level = args.loglevel.upper() level = args.loglevel.upper()
try: try:
numeric_level = getattr(logging, level) numeric_level = getattr(logging, level)
@ -161,9 +173,11 @@ def init_log(args):
console, ram = _init_handlers(numeric_level, args.color, args.force_color, console, ram = _init_handlers(numeric_level, args.color, args.force_color,
args.json_logging, args.loglines) args.json_logging, args.loglines)
root = logging.getLogger() root = logging.getLogger()
global console_filter
if console is not None: if console is not None:
if args.logfilter is not None: if args.logfilter is not None:
console.addFilter(LogFilter(args.logfilter.split(','))) console_filter = LogFilter(args.logfilter.split(','))
console.addFilter(console_filter)
root.addHandler(console) root.addHandler(console)
if ram is not None: if ram is not None:
root.addHandler(ram) root.addHandler(ram)
@ -175,6 +189,10 @@ def init_log(args):
_log_inited = True _log_inited = True
def change(filters):
console.addFilter(LogFilter(filters.split(',')))
def _init_py_warnings(): def _init_py_warnings():
"""Initialize Python warning handling.""" """Initialize Python warning handling."""
warnings.simplefilter('default') warnings.simplefilter('default')
@ -210,6 +228,7 @@ def _init_handlers(level, color, force_color, json_logging, ram_capacity):
json_logging: Output log lines in JSON (this disables all colors). json_logging: Output log lines in JSON (this disables all colors).
""" """
global ram_handler global ram_handler
global console_handler
console_fmt, ram_fmt, html_fmt, use_colorama = _init_formatters( console_fmt, ram_fmt, html_fmt, use_colorama = _init_formatters(
level, color, force_color, json_logging) level, color, force_color, json_logging)
@ -448,16 +467,16 @@ class LogFilter(logging.Filter):
def __init__(self, names): def __init__(self, names):
super().__init__() super().__init__()
self._names = names self.names = names
def filter(self, record): def filter(self, record):
"""Determine if the specified record is to be logged.""" """Determine if the specified record is to be logged."""
if self._names is None: if self.names is None:
return True return True
if record.levelno > logging.DEBUG: if record.levelno > logging.DEBUG:
# More important than DEBUG, so we won't filter at all # More important than DEBUG, so we won't filter at all
return True return True
for name in self._names: for name in self.names:
if record.name == name: if record.name == name:
return True return True
elif not record.name.startswith(name): elif not record.name.startswith(name):

View File

@ -471,10 +471,26 @@ Feature: Various utility commands.
Then the page should contain the plaintext "newstuff" Then the page should contain the plaintext "newstuff"
And the page should not contain the plaintext "oldstuff" And the page should not contain the plaintext "oldstuff"
Scenario: Using :debug-log-capacity with negative capacity
When I run :debug-log-capacity -1
Then the error "Can't set a negative log capacity!" should be shown
# :debug-log-level / :debug-log-filter
# Other :debug-log-{level,filter} features are tested in
# unit/utils/test_log.py as using them would break end2end tests.
Scenario: Using debug-log-level with invalid level
When I run :debug-log-level hello
Then the error "level: Invalid value hello - expected one of: vdebug, debug, info, warning, error, critical" should be shown
Scenario: Using debug-log-filter with invalid filter
When I run :debug-log-filter blah
Then the error "filters: Invalid value blah - expected one of: statusbar, *" should be shown
## https://github.com/The-Compiler/qutebrowser/issues/1523 ## https://github.com/The-Compiler/qutebrowser/issues/1523
Scenario: Completing a single option argument Scenario: Completing a single option argument
When I run :set-cmd-text -s :-- When I run :set-cmd-text -s :--
Then no crash should happen Then no crash should happen
## https://github.com/The-Compiler/qutebrowser/issues/1386 ## https://github.com/The-Compiler/qutebrowser/issues/1386

View File

@ -29,6 +29,7 @@ import pytest
import pytest_catchlog import pytest_catchlog
from qutebrowser.utils import log from qutebrowser.utils import log
from qutebrowser.misc import utilcmds
@pytest.yield_fixture(autouse=True) @pytest.yield_fixture(autouse=True)
@ -167,6 +168,19 @@ class TestLogFilter:
record = self._make_record(logger, "bacon", level=logging.INFO) record = self._make_record(logger, "bacon", level=logging.INFO)
assert logfilter.filter(record) assert logfilter.filter(record)
@pytest.mark.parametrize('category, logged_before, logged_after', [
('init', True, False), ('url', False, True), ('js', False, True)])
def test_debug_log_filter_cmd(self, monkeypatch, logger, category,
logged_before, logged_after):
logfilter = log.LogFilter(["init"])
monkeypatch.setattr(log, 'console_filter', logfilter)
record = self._make_record(logger, category)
assert logfilter.filter(record) == logged_before
utilcmds.debug_log_filter('url,js')
assert logfilter.filter(record) == logged_after
class TestRAMHandler: class TestRAMHandler: