From 8e638a21a550004a98233dca39e9ecf4caff22d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20Prchl=C3=ADk?= Date: Sun, 5 Mar 2023 23:27:02 +0100 Subject: [PATCH] Adds "bootstrap logger" for logging before CLI options are recognized (#1839) Aims at parts of tmt lifetime where logging is needed, but CLI options like --debug are unknown yet. This would be code that's executed in import time, the most visible one is plugin exploration & importing, but there may be others. At this moment, `fmf.utils.Logging` is used for this purpose, but that's tmt's logging "sneaking" away from what `tmt.log` offers and implements. And that's not good, as it may mean slightly different logging behavior than the one exhibited during the rest of tmt run. --- tests/unit/test_logging.py | 4 ++++ tmt/log.py | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/tests/unit/test_logging.py b/tests/unit/test_logging.py index a6ab32d8c0..9d07332eab 100644 --- a/tests/unit/test_logging.py +++ b/tests/unit/test_logging.py @@ -220,3 +220,7 @@ def test_labels(caplog: _pytest.logging.LogCaptureFixture, root_logger: Logger) root_logger.labels += ['bar'] _exercise_logger(caplog, root_logger, labels=['foo', 'bar']) + + +def test_bootstrap_logger(caplog: _pytest.logging.LogCaptureFixture) -> None: + _exercise_logger(caplog, Logger.get_boostrap_logger()) diff --git a/tmt/log.py b/tmt/log.py index b4953d3a83..19373ca286 100644 --- a/tmt/log.py +++ b/tmt/log.py @@ -609,3 +609,29 @@ def fail( 'shift': shift } ) + + _bootstrap_logger: Optional['Logger'] = None + + @classmethod + def get_boostrap_logger(cls) -> 'Logger': + """ + Create a logger designed for tmt startup time. + + .. warning:: + + This logger has a **very** limited use case span, i.e. before tmt can + digest its command-line options and create a proper logger. This happens + inside :py:funs:`tmt.cli.main` function, but there are some actions taken + by tmt code before this function is called by Click, actions that need + to emit logging messages. Using it anywhere outside of this brief time + in tmt's runtime should be ruled out. + """ + + if cls._bootstrap_logger is None: + # Stay away of our future main logger + actual_logger = Logger._normalize_logger(logging.getLogger('_tmt_bootstrap')) + + cls._bootstrap_logger = Logger.create(actual_logger=actual_logger) + cls._bootstrap_logger.add_console_handler() + + return cls._bootstrap_logger