LoggingPlugin: Expose setting log_file_handler
- This patch allows to set log_file (path) from hook Signed-off-by: Thomas Hisch Signed-off-by: Andras Mitzki <andras.mitzki@balabit.com>
This commit is contained in:
parent
a131cd6c3b
commit
e3824d23bc
1
AUTHORS
1
AUTHORS
|
@ -16,6 +16,7 @@ Allan Feldman
|
||||||
Aly Sivji
|
Aly Sivji
|
||||||
Anatoly Bubenkoff
|
Anatoly Bubenkoff
|
||||||
Anders Hovmöller
|
Anders Hovmöller
|
||||||
|
Andras Mitzki
|
||||||
Andras Tim
|
Andras Tim
|
||||||
Andrea Cimatoribus
|
Andrea Cimatoribus
|
||||||
Andreas Zeidler
|
Andreas Zeidler
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
With the help of new ``set_log_path()`` method there is a way to set ``log_file`` paths from hooks.
|
|
@ -198,6 +198,9 @@ option names are:
|
||||||
* ``log_file_format``
|
* ``log_file_format``
|
||||||
* ``log_file_date_format``
|
* ``log_file_date_format``
|
||||||
|
|
||||||
|
You can call ``set_log_path()`` to customize the log_file path dynamically. This functionality
|
||||||
|
is considered **experimental**.
|
||||||
|
|
||||||
.. _log_release_notes:
|
.. _log_release_notes:
|
||||||
|
|
||||||
Release notes
|
Release notes
|
||||||
|
|
|
@ -13,6 +13,7 @@ import six
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.compat import dummy_context_manager
|
from _pytest.compat import dummy_context_manager
|
||||||
from _pytest.config import create_terminal_writer
|
from _pytest.config import create_terminal_writer
|
||||||
|
from _pytest.pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_LOG_FORMAT = "%(filename)-25s %(lineno)4d %(levelname)-8s %(message)s"
|
DEFAULT_LOG_FORMAT = "%(filename)-25s %(lineno)4d %(levelname)-8s %(message)s"
|
||||||
|
@ -399,22 +400,21 @@ class LoggingPlugin(object):
|
||||||
)
|
)
|
||||||
self.log_level = get_actual_log_level(config, "log_level")
|
self.log_level = get_actual_log_level(config, "log_level")
|
||||||
|
|
||||||
|
self.log_file_level = get_actual_log_level(config, "log_file_level")
|
||||||
|
self.log_file_format = get_option_ini(config, "log_file_format", "log_format")
|
||||||
|
self.log_file_date_format = get_option_ini(
|
||||||
|
config, "log_file_date_format", "log_date_format"
|
||||||
|
)
|
||||||
|
self.log_file_formatter = logging.Formatter(
|
||||||
|
self.log_file_format, datefmt=self.log_file_date_format
|
||||||
|
)
|
||||||
|
|
||||||
log_file = get_option_ini(config, "log_file")
|
log_file = get_option_ini(config, "log_file")
|
||||||
if log_file:
|
if log_file:
|
||||||
self.log_file_level = get_actual_log_level(config, "log_file_level")
|
|
||||||
|
|
||||||
log_file_format = get_option_ini(config, "log_file_format", "log_format")
|
|
||||||
log_file_date_format = get_option_ini(
|
|
||||||
config, "log_file_date_format", "log_date_format"
|
|
||||||
)
|
|
||||||
# Each pytest runtests session will write to a clean logfile
|
|
||||||
self.log_file_handler = logging.FileHandler(
|
self.log_file_handler = logging.FileHandler(
|
||||||
log_file, mode="w", encoding="UTF-8"
|
log_file, mode="w", encoding="UTF-8"
|
||||||
)
|
)
|
||||||
log_file_formatter = logging.Formatter(
|
self.log_file_handler.setFormatter(self.log_file_formatter)
|
||||||
log_file_format, datefmt=log_file_date_format
|
|
||||||
)
|
|
||||||
self.log_file_handler.setFormatter(log_file_formatter)
|
|
||||||
else:
|
else:
|
||||||
self.log_file_handler = None
|
self.log_file_handler = None
|
||||||
|
|
||||||
|
@ -468,6 +468,27 @@ class LoggingPlugin(object):
|
||||||
log_cli_handler, formatter=log_cli_formatter, level=log_cli_level
|
log_cli_handler, formatter=log_cli_formatter, level=log_cli_level
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def set_log_path(self, fname):
|
||||||
|
"""Public method, which can set filename parameter for
|
||||||
|
Logging.FileHandler(). Also creates parent directory if
|
||||||
|
it does not exist.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
Please considered as an experimental API.
|
||||||
|
"""
|
||||||
|
fname = Path(fname)
|
||||||
|
|
||||||
|
if not fname.is_absolute():
|
||||||
|
fname = Path(self._config.rootdir, fname)
|
||||||
|
|
||||||
|
if not fname.parent.exists():
|
||||||
|
fname.parent.mkdir(exist_ok=True, parents=True)
|
||||||
|
|
||||||
|
self.log_file_handler = logging.FileHandler(
|
||||||
|
str(fname), mode="w", encoding="UTF-8"
|
||||||
|
)
|
||||||
|
self.log_file_handler.setFormatter(self.log_file_formatter)
|
||||||
|
|
||||||
def _log_cli_enabled(self):
|
def _log_cli_enabled(self):
|
||||||
"""Return True if log_cli should be considered enabled, either explicitly
|
"""Return True if log_cli should be considered enabled, either explicitly
|
||||||
or because --log-cli-level was given in the command-line.
|
or because --log-cli-level was given in the command-line.
|
||||||
|
@ -490,6 +511,15 @@ class LoggingPlugin(object):
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def _runtest_for(self, item, when):
|
def _runtest_for(self, item, when):
|
||||||
|
with self._runtest_for_main(item, when):
|
||||||
|
if self.log_file_handler is not None:
|
||||||
|
with catching_logs(self.log_file_handler, level=self.log_file_level):
|
||||||
|
yield
|
||||||
|
else:
|
||||||
|
yield
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def _runtest_for_main(self, item, when):
|
||||||
"""Implements the internals of pytest_runtest_xxx() hook."""
|
"""Implements the internals of pytest_runtest_xxx() hook."""
|
||||||
with catching_logs(
|
with catching_logs(
|
||||||
LogCaptureHandler(), formatter=self.formatter, level=self.log_level
|
LogCaptureHandler(), formatter=self.formatter, level=self.log_level
|
||||||
|
|
|
@ -1002,3 +1002,51 @@ def test_log_in_hooks(testdir):
|
||||||
assert "sessionstart" in contents
|
assert "sessionstart" in contents
|
||||||
assert "runtestloop" in contents
|
assert "runtestloop" in contents
|
||||||
assert "sessionfinish" in contents
|
assert "sessionfinish" in contents
|
||||||
|
|
||||||
|
|
||||||
|
def test_log_set_path(testdir):
|
||||||
|
report_dir_base = testdir.tmpdir.strpath
|
||||||
|
|
||||||
|
testdir.makeini(
|
||||||
|
"""
|
||||||
|
[pytest]
|
||||||
|
log_file_level = DEBUG
|
||||||
|
log_cli=true
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
testdir.makeconftest(
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
|
||||||
|
def pytest_runtest_setup(item):
|
||||||
|
config = item.config
|
||||||
|
logging_plugin = config.pluginmanager.get_plugin("logging-plugin")
|
||||||
|
report_file = os.path.join({}, item._request.node.name)
|
||||||
|
logging_plugin.set_log_path(report_file)
|
||||||
|
yield
|
||||||
|
""".format(
|
||||||
|
repr(report_dir_base)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger("testcase-logger")
|
||||||
|
def test_first():
|
||||||
|
logger.info("message from test 1")
|
||||||
|
assert True
|
||||||
|
|
||||||
|
def test_second():
|
||||||
|
logger.debug("message from test 2")
|
||||||
|
assert True
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
testdir.runpytest()
|
||||||
|
with open(os.path.join(report_dir_base, "test_first"), "r") as rfh:
|
||||||
|
content = rfh.read()
|
||||||
|
assert "message from test 1" in content
|
||||||
|
|
||||||
|
with open(os.path.join(report_dir_base, "test_second"), "r") as rfh:
|
||||||
|
content = rfh.read()
|
||||||
|
assert "message from test 2" in content
|
||||||
|
|
Loading…
Reference in New Issue