logging: use dummy handler when CLI logging is disabled instead of None
This makes the code cleaner by removing conditionals and making the CLI and file logging completely analogous. Doesn't affect performance.
This commit is contained in:
parent
bd657bab3f
commit
43c465c9bf
|
@ -11,6 +11,7 @@ from typing import Generator
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Mapping
|
from typing import Mapping
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest import nodes
|
from _pytest import nodes
|
||||||
|
@ -529,11 +530,24 @@ class LoggingPlugin:
|
||||||
self.log_file_handler.setFormatter(log_file_formatter)
|
self.log_file_handler.setFormatter(log_file_formatter)
|
||||||
|
|
||||||
# CLI/live logging.
|
# CLI/live logging.
|
||||||
|
self.log_cli_level = get_log_level_for_setting(
|
||||||
|
config, "log_cli_level", "log_level"
|
||||||
|
)
|
||||||
if self._log_cli_enabled():
|
if self._log_cli_enabled():
|
||||||
self._setup_cli_logging()
|
terminal_reporter = config.pluginmanager.get_plugin("terminalreporter")
|
||||||
|
capture_manager = config.pluginmanager.get_plugin("capturemanager")
|
||||||
|
# if capturemanager plugin is disabled, live logging still works.
|
||||||
|
self.log_cli_handler = _LiveLoggingStreamHandler(
|
||||||
|
terminal_reporter, capture_manager
|
||||||
|
) # type: Union[_LiveLoggingStreamHandler, _LiveLoggingNullHandler]
|
||||||
else:
|
else:
|
||||||
self.log_cli_handler = None
|
self.log_cli_handler = _LiveLoggingNullHandler()
|
||||||
self.live_logs_context = nullcontext
|
log_cli_formatter = self._create_formatter(
|
||||||
|
get_option_ini(config, "log_cli_format", "log_format"),
|
||||||
|
get_option_ini(config, "log_cli_date_format", "log_date_format"),
|
||||||
|
get_option_ini(config, "log_auto_indent"),
|
||||||
|
)
|
||||||
|
self.log_cli_handler.setFormatter(log_cli_formatter)
|
||||||
|
|
||||||
def _create_formatter(self, log_format, log_date_format, auto_indent):
|
def _create_formatter(self, log_format, log_date_format, auto_indent):
|
||||||
# color option doesn't exist if terminal plugin is disabled
|
# color option doesn't exist if terminal plugin is disabled
|
||||||
|
@ -553,30 +567,6 @@ class LoggingPlugin:
|
||||||
|
|
||||||
return formatter
|
return formatter
|
||||||
|
|
||||||
def _setup_cli_logging(self):
|
|
||||||
config = self._config
|
|
||||||
terminal_reporter = config.pluginmanager.get_plugin("terminalreporter")
|
|
||||||
if terminal_reporter is None:
|
|
||||||
# terminal reporter is disabled e.g. by pytest-xdist.
|
|
||||||
return
|
|
||||||
|
|
||||||
capture_manager = config.pluginmanager.get_plugin("capturemanager")
|
|
||||||
# if capturemanager plugin is disabled, live logging still works.
|
|
||||||
log_cli_handler = _LiveLoggingStreamHandler(terminal_reporter, capture_manager)
|
|
||||||
|
|
||||||
log_cli_formatter = self._create_formatter(
|
|
||||||
get_option_ini(config, "log_cli_format", "log_format"),
|
|
||||||
get_option_ini(config, "log_cli_date_format", "log_date_format"),
|
|
||||||
get_option_ini(config, "log_auto_indent"),
|
|
||||||
)
|
|
||||||
log_cli_handler.setFormatter(log_cli_formatter)
|
|
||||||
|
|
||||||
log_cli_level = get_log_level_for_setting(config, "log_cli_level", "log_level")
|
|
||||||
self.log_cli_handler = log_cli_handler
|
|
||||||
self.live_logs_context = lambda: catching_logs(
|
|
||||||
log_cli_handler, level=log_cli_level
|
|
||||||
)
|
|
||||||
|
|
||||||
def set_log_path(self, fname):
|
def set_log_path(self, fname):
|
||||||
"""Public method, which can set filename parameter for
|
"""Public method, which can set filename parameter for
|
||||||
Logging.FileHandler(). Also creates parent directory if
|
Logging.FileHandler(). Also creates parent directory if
|
||||||
|
@ -608,19 +598,25 @@ class LoggingPlugin:
|
||||||
old_stream.close()
|
old_stream.close()
|
||||||
|
|
||||||
def _log_cli_enabled(self):
|
def _log_cli_enabled(self):
|
||||||
"""Return True if log_cli should be considered enabled, either explicitly
|
"""Return whether live logging is enabled."""
|
||||||
or because --log-cli-level was given in the command-line.
|
enabled = self._config.getoption(
|
||||||
"""
|
|
||||||
return self._config.getoption(
|
|
||||||
"--log-cli-level"
|
"--log-cli-level"
|
||||||
) is not None or self._config.getini("log_cli")
|
) is not None or self._config.getini("log_cli")
|
||||||
|
if not enabled:
|
||||||
|
return False
|
||||||
|
|
||||||
|
terminal_reporter = self._config.pluginmanager.get_plugin("terminalreporter")
|
||||||
|
if terminal_reporter is None:
|
||||||
|
# terminal reporter is disabled e.g. by pytest-xdist.
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||||
def pytest_collection(self) -> Generator[None, None, None]:
|
def pytest_collection(self) -> Generator[None, None, None]:
|
||||||
if self.log_cli_handler is not None:
|
self.log_cli_handler.set_when("collection")
|
||||||
self.log_cli_handler.set_when("collection")
|
|
||||||
|
|
||||||
with self.live_logs_context():
|
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
@ -641,8 +637,7 @@ class LoggingPlugin:
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
def pytest_runtest_setup(self, item):
|
def pytest_runtest_setup(self, item):
|
||||||
if self.log_cli_handler is not None:
|
self.log_cli_handler.set_when("setup")
|
||||||
self.log_cli_handler.set_when("setup")
|
|
||||||
|
|
||||||
empty = {} # type: Dict[str, LogCaptureHandler]
|
empty = {} # type: Dict[str, LogCaptureHandler]
|
||||||
item._store[catch_log_handlers_key] = empty
|
item._store[catch_log_handlers_key] = empty
|
||||||
|
@ -650,15 +645,13 @@ class LoggingPlugin:
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
def pytest_runtest_call(self, item):
|
def pytest_runtest_call(self, item):
|
||||||
if self.log_cli_handler is not None:
|
self.log_cli_handler.set_when("call")
|
||||||
self.log_cli_handler.set_when("call")
|
|
||||||
|
|
||||||
yield from self._runtest_for(item, "call")
|
yield from self._runtest_for(item, "call")
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True)
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
def pytest_runtest_teardown(self, item):
|
def pytest_runtest_teardown(self, item):
|
||||||
if self.log_cli_handler is not None:
|
self.log_cli_handler.set_when("teardown")
|
||||||
self.log_cli_handler.set_when("teardown")
|
|
||||||
|
|
||||||
yield from self._runtest_for(item, "teardown")
|
yield from self._runtest_for(item, "teardown")
|
||||||
del item._store[catch_log_handlers_key]
|
del item._store[catch_log_handlers_key]
|
||||||
|
@ -666,40 +659,34 @@ class LoggingPlugin:
|
||||||
|
|
||||||
@pytest.hookimpl
|
@pytest.hookimpl
|
||||||
def pytest_runtest_logstart(self):
|
def pytest_runtest_logstart(self):
|
||||||
if self.log_cli_handler is not None:
|
self.log_cli_handler.reset()
|
||||||
self.log_cli_handler.reset()
|
self.log_cli_handler.set_when("start")
|
||||||
self.log_cli_handler.set_when("start")
|
|
||||||
|
|
||||||
@pytest.hookimpl
|
@pytest.hookimpl
|
||||||
def pytest_runtest_logfinish(self):
|
def pytest_runtest_logfinish(self):
|
||||||
if self.log_cli_handler is not None:
|
self.log_cli_handler.set_when("finish")
|
||||||
self.log_cli_handler.set_when("finish")
|
|
||||||
|
|
||||||
@pytest.hookimpl
|
@pytest.hookimpl
|
||||||
def pytest_runtest_logreport(self):
|
def pytest_runtest_logreport(self):
|
||||||
if self.log_cli_handler is not None:
|
self.log_cli_handler.set_when("logreport")
|
||||||
self.log_cli_handler.set_when("logreport")
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||||
def pytest_sessionfinish(self):
|
def pytest_sessionfinish(self):
|
||||||
if self.log_cli_handler is not None:
|
self.log_cli_handler.set_when("sessionfinish")
|
||||||
self.log_cli_handler.set_when("sessionfinish")
|
|
||||||
|
|
||||||
with self.live_logs_context():
|
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||||
try:
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
yield
|
||||||
yield
|
|
||||||
finally:
|
# Close the FileHandler explicitly.
|
||||||
# Close the FileHandler explicitly.
|
# (logging.shutdown might have lost the weakref?!)
|
||||||
# (logging.shutdown might have lost the weakref?!)
|
self.log_file_handler.close()
|
||||||
self.log_file_handler.close()
|
|
||||||
|
|
||||||
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||||
def pytest_sessionstart(self):
|
def pytest_sessionstart(self):
|
||||||
if self.log_cli_handler is not None:
|
self.log_cli_handler.set_when("sessionstart")
|
||||||
self.log_cli_handler.set_when("sessionstart")
|
|
||||||
|
|
||||||
with self.live_logs_context():
|
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
yield
|
yield
|
||||||
|
|
||||||
|
@ -715,7 +702,7 @@ class LoggingPlugin:
|
||||||
# setting verbose flag is needed to avoid messy test progress output
|
# setting verbose flag is needed to avoid messy test progress output
|
||||||
self._config.option.verbose = 1
|
self._config.option.verbose = 1
|
||||||
|
|
||||||
with self.live_logs_context():
|
with catching_logs(self.log_cli_handler, level=self.log_cli_level):
|
||||||
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
yield # run all the tests
|
yield # run all the tests
|
||||||
|
|
||||||
|
@ -768,4 +755,14 @@ class _LiveLoggingStreamHandler(logging.StreamHandler):
|
||||||
if not self._section_name_shown and self._when:
|
if not self._section_name_shown and self._when:
|
||||||
self.stream.section("live log " + self._when, sep="-", bold=True)
|
self.stream.section("live log " + self._when, sep="-", bold=True)
|
||||||
self._section_name_shown = True
|
self._section_name_shown = True
|
||||||
logging.StreamHandler.emit(self, record)
|
super().emit(record)
|
||||||
|
|
||||||
|
|
||||||
|
class _LiveLoggingNullHandler(logging.NullHandler):
|
||||||
|
"""A handler used when live logging is disabled."""
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def set_when(self, when):
|
||||||
|
pass
|
||||||
|
|
Loading…
Reference in New Issue