diff --git a/nixos/doc/manual/redirects.json b/nixos/doc/manual/redirects.json index feb535c2142c2..71a137b0fa336 100644 --- a/nixos/doc/manual/redirects.json +++ b/nixos/doc/manual/redirects.json @@ -2207,6 +2207,9 @@ "test-opt-interactive": [ "index.html#test-opt-interactive" ], + "test-opt-logLevel": [ + "index.html#test-opt-logLevel" + ], "test-opt-meta": [ "index.html#test-opt-meta" ], diff --git a/nixos/lib/test-driver/src/test_driver/__init__.py b/nixos/lib/test-driver/src/test_driver/__init__.py index 0f42f2842c77e..da527f46b8244 100644 --- a/nixos/lib/test-driver/src/test_driver/__init__.py +++ b/nixos/lib/test-driver/src/test_driver/__init__.py @@ -12,6 +12,7 @@ from test_driver.logger import ( CompositeLogger, JunitXMLLogger, + LogLevel, TerminalLogger, XMLLogger, ) @@ -151,6 +152,15 @@ def main() -> None: help="indicates that the interactive SSH backdoor is active and dumps information about it on start", type=int, ) + log_level_map = {level.name.lower(): level for level in LogLevel} + arg_parser.add_argument( + "--log-level", + metavar="LOG_LEVEL", + action=EnvDefault, + envvar="logLevel", + choices=log_level_map, + help="Set the log level", + ) args = arg_parser.parse_args() @@ -169,6 +179,9 @@ def main() -> None: if args.junit_xml: logger.add_logger(JunitXMLLogger(output_directory / args.junit_xml)) + if args.log_level: + logger.set_log_level(log_level_map[args.log_level]) + if not args.keep_machine_state: logger.info( "Machine state will be reset. To keep it, pass --keep-machine-state" diff --git a/nixos/lib/test-driver/src/test_driver/logger.py b/nixos/lib/test-driver/src/test_driver/logger.py index a218d234fe3f8..3c2cb41d33b1b 100644 --- a/nixos/lib/test-driver/src/test_driver/logger.py +++ b/nixos/lib/test-driver/src/test_driver/logger.py @@ -7,6 +7,7 @@ from abc import ABC, abstractmethod from collections.abc import Iterator from contextlib import ExitStack, contextmanager +from enum import IntEnum from pathlib import Path from queue import Empty, Queue from typing import Any @@ -17,6 +18,12 @@ from junit_xml import TestCase, TestSuite +class LogLevel(IntEnum): + INFO = 1 + WARNING = 2 + ERROR = 3 + + class AbstractLogger(ABC): @abstractmethod def log(self, message: str, attributes: dict[str, str] = {}) -> None: @@ -56,6 +63,10 @@ def log_serial(self, message: str, machine: str) -> None: def print_serial_logs(self, enable: bool) -> None: pass + @abstractmethod + def set_log_level(self, level: LogLevel) -> None: + pass + class JunitXMLLogger(AbstractLogger): class TestCaseState: @@ -71,6 +82,7 @@ def __init__(self, outfile: Path) -> None: self.currentSubtest = "main" self.outfile: Path = outfile self._print_serial_logs = True + self._log_level = LogLevel.INFO atexit.register(self.close) def log(self, message: str, attributes: dict[str, str] = {}) -> None: @@ -92,10 +104,12 @@ def nested(self, message: str, attributes: dict[str, str] = {}) -> Iterator[None yield def info(self, *args, **kwargs) -> None: # type: ignore - self.tests[self.currentSubtest].stdout += args[0] + os.linesep + if self._log_level <= LogLevel.INFO: + self.tests[self.currentSubtest].stdout += args[0] + os.linesep def warning(self, *args, **kwargs) -> None: # type: ignore - self.tests[self.currentSubtest].stdout += args[0] + os.linesep + if self._log_level <= LogLevel.WARNING: + self.tests[self.currentSubtest].stdout += args[0] + os.linesep def error(self, *args, **kwargs) -> None: # type: ignore self.tests[self.currentSubtest].stderr += args[0] + os.linesep @@ -113,6 +127,9 @@ def log_serial(self, message: str, machine: str) -> None: def print_serial_logs(self, enable: bool) -> None: self._print_serial_logs = enable + def set_log_level(self, level: LogLevel) -> None: + self._log_level = level + def close(self) -> None: with open(self.outfile, "w") as f: test_cases = [] @@ -180,10 +197,15 @@ def log_serial(self, message: str, machine: str) -> None: for logger in self.logger_list: logger.log_serial(message, machine) + def set_log_level(self, level: LogLevel) -> None: + for logger in self.logger_list: + logger.set_log_level(level) + class TerminalLogger(AbstractLogger): def __init__(self) -> None: self._print_serial_logs = True + self._log_level = LogLevel.INFO def maybe_prefix(self, message: str, attributes: dict[str, str]) -> str: if "machine" in attributes: @@ -216,10 +238,12 @@ def nested(self, message: str, attributes: dict[str, str] = {}) -> Iterator[None self.log(f"(finished: {message}, in {toc - tic:.2f} seconds)", attributes) def info(self, *args, **kwargs) -> None: # type: ignore - self.log(*args, **kwargs) + if self._log_level <= LogLevel.INFO: + self.log(*args, **kwargs) def warning(self, *args, **kwargs) -> None: # type: ignore - self.log(*args, **kwargs) + if self._log_level <= LogLevel.WARNING: + self.log(*args, **kwargs) def error(self, *args, **kwargs) -> None: # type: ignore self.log(*args, **kwargs) @@ -227,6 +251,9 @@ def error(self, *args, **kwargs) -> None: # type: ignore def print_serial_logs(self, enable: bool) -> None: self._print_serial_logs = enable + def set_log_level(self, level: LogLevel) -> None: + self._log_level = level + def log_serial(self, message: str, machine: str) -> None: if not self._print_serial_logs: return @@ -246,6 +273,7 @@ def __init__(self, outfile: str) -> None: self.queue: Queue[dict[str, str]] = Queue() self._print_serial_logs = True + self._log_level = LogLevel.INFO self.xml.startDocument() self.xml.startElement("logfile", attrs=AttributesImpl({})) @@ -269,10 +297,12 @@ def log_line(self, message: str, attributes: dict[str, str]) -> None: self.xml.endElement("line") def info(self, *args, **kwargs) -> None: # type: ignore - self.log(*args, **kwargs) + if self._log_level <= LogLevel.INFO: + self.log(*args, **kwargs) def warning(self, *args, **kwargs) -> None: # type: ignore - self.log(*args, **kwargs) + if self._log_level <= LogLevel.WARNING: + self.log(*args, **kwargs) def error(self, *args, **kwargs) -> None: # type: ignore self.log(*args, **kwargs) @@ -287,6 +317,9 @@ def log(self, message: str, attributes: dict[str, str] = {}) -> None: def print_serial_logs(self, enable: bool) -> None: self._print_serial_logs = enable + def set_log_level(self, level: LogLevel) -> None: + self._log_level = level + def log_serial(self, message: str, machine: str) -> None: if not self._print_serial_logs: return diff --git a/nixos/lib/testing/driver.nix b/nixos/lib/testing/driver.nix index 5cd7c2ebb8066..d5638718dda76 100644 --- a/nixos/lib/testing/driver.nix +++ b/nixos/lib/testing/driver.nix @@ -119,6 +119,7 @@ let --set testScript "$out/test-script" \ --set globalTimeout "${toString config.globalTimeout}" \ --set vlans '${toString vlans}' \ + --set logLevel "${config.logLevel}" \ ${lib.escapeShellArgs ( lib.concatMap (arg: [ "--add-flags" @@ -219,6 +220,17 @@ in This may speed up your iteration cycle, unless you're working on the [{option}`testScript`](#test-opt-testScript). ''; }; + + logLevel = mkOption { + description = "Log level for the test driver."; + type = types.enum [ + "info" + "warning" + "error" + ]; + default = "info"; + example = "warning"; + }; }; config = {