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