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 | ||||
| Anatoly Bubenkoff | ||||
| Anders Hovmöller | ||||
| Andras Mitzki | ||||
| Andras Tim | ||||
| Andrea Cimatoribus | ||||
| 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_date_format`` | ||||
| 
 | ||||
| You can call ``set_log_path()`` to customize the log_file path dynamically. This functionality | ||||
| is considered **experimental**. | ||||
| 
 | ||||
| .. _log_release_notes: | ||||
| 
 | ||||
| Release notes | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ import six | |||
| import pytest | ||||
| from _pytest.compat import dummy_context_manager | ||||
| from _pytest.config import create_terminal_writer | ||||
| from _pytest.pathlib import Path | ||||
| 
 | ||||
| 
 | ||||
| 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") | ||||
| 
 | ||||
|         log_file = get_option_ini(config, "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( | ||||
|         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" | ||||
|         ) | ||||
|             # Each pytest runtests session will write to a clean logfile | ||||
|         self.log_file_formatter = logging.Formatter( | ||||
|             self.log_file_format, datefmt=self.log_file_date_format | ||||
|         ) | ||||
| 
 | ||||
|         log_file = get_option_ini(config, "log_file") | ||||
|         if log_file: | ||||
|             self.log_file_handler = logging.FileHandler( | ||||
|                 log_file, mode="w", encoding="UTF-8" | ||||
|             ) | ||||
|             log_file_formatter = logging.Formatter( | ||||
|                 log_file_format, datefmt=log_file_date_format | ||||
|             ) | ||||
|             self.log_file_handler.setFormatter(log_file_formatter) | ||||
|             self.log_file_handler.setFormatter(self.log_file_formatter) | ||||
|         else: | ||||
|             self.log_file_handler = None | ||||
| 
 | ||||
|  | @ -468,6 +468,27 @@ class LoggingPlugin(object): | |||
|             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): | ||||
|         """Return True if log_cli should be considered enabled, either explicitly | ||||
|         or because --log-cli-level was given in the command-line. | ||||
|  | @ -490,6 +511,15 @@ class LoggingPlugin(object): | |||
| 
 | ||||
|     @contextmanager | ||||
|     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.""" | ||||
|         with catching_logs( | ||||
|             LogCaptureHandler(), formatter=self.formatter, level=self.log_level | ||||
|  |  | |||
|  | @ -1002,3 +1002,51 @@ def test_log_in_hooks(testdir): | |||
|         assert "sessionstart" in contents | ||||
|         assert "runtestloop" 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