From b57deaf9e1e1845d64e05a9e92a2b84626ff1760 Mon Sep 17 00:00:00 2001 From: Czar Echavez Date: Wed, 17 Apr 2024 18:13:00 +0100 Subject: [PATCH] #2470: implementing log levels into sys log --- src/primaite/simulator/__init__.py | 19 +++ src/primaite/simulator/system/core/sys_log.py | 17 +- .../_simulator/_system/core/test_sys_log.py | 149 ++++++++++++++++++ 3 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 tests/unit_tests/_primaite/_simulator/_system/core/test_sys_log.py diff --git a/src/primaite/simulator/__init__.py b/src/primaite/simulator/__init__.py index 9e2ce9a1..cfae2ab7 100644 --- a/src/primaite/simulator/__init__.py +++ b/src/primaite/simulator/__init__.py @@ -1,5 +1,6 @@ """Warning: SIM_OUTPUT is a mutable global variable for the simulation output directory.""" from datetime import datetime +from enum import Enum from pathlib import Path from primaite import _PRIMAITE_ROOT @@ -7,6 +8,23 @@ from primaite import _PRIMAITE_ROOT __all__ = ["SIM_OUTPUT"] +class LogLevel(Enum): + """Enum containing all the available log levels for PrimAITE simulation output.""" + + OFF = 999 + """No logs will be output to terminal or log file.""" + DEBUG = 1 + """Debug items will be output to terminal or log file.""" + INFO = 2 + """Info items will be output to terminal or log file.""" + WARNING = 3 + """Warnings will be output to terminal or log file.""" + ERROR = 4 + """Errors will be output to terminal or log file.""" + CRITICAL = 5 + """Critical errors will be output to terminal or log file.""" + + class _SimOutput: def __init__(self): self._path: Path = ( @@ -15,6 +33,7 @@ class _SimOutput: self.save_pcap_logs: bool = False self.save_sys_logs: bool = False self.write_sys_log_to_terminal: bool = False + self.log_level: LogLevel = LogLevel.INFO # default log level is at INFO @property def path(self) -> Path: diff --git a/src/primaite/simulator/system/core/sys_log.py b/src/primaite/simulator/system/core/sys_log.py index c10f7d3c..775f9b30 100644 --- a/src/primaite/simulator/system/core/sys_log.py +++ b/src/primaite/simulator/system/core/sys_log.py @@ -3,7 +3,7 @@ from pathlib import Path from prettytable import MARKDOWN, PrettyTable -from primaite.simulator import SIM_OUTPUT +from primaite.simulator import LogLevel, SIM_OUTPUT class _NotJSONFilter(logging.Filter): @@ -99,6 +99,9 @@ class SysLog: :param msg: The message to be logged. :param to_terminal: If True, prints to the terminal too. """ + if SIM_OUTPUT.log_level.value > LogLevel.DEBUG.value: + return + if SIM_OUTPUT.save_sys_logs: self.logger.debug(msg) self._write_to_terminal(msg, "DEBUG", to_terminal) @@ -110,6 +113,9 @@ class SysLog: :param msg: The message to be logged. :param to_terminal: If True, prints to the terminal too. """ + if SIM_OUTPUT.log_level.value > LogLevel.INFO.value: + return + if SIM_OUTPUT.save_sys_logs: self.logger.info(msg) self._write_to_terminal(msg, "INFO", to_terminal) @@ -121,6 +127,9 @@ class SysLog: :param msg: The message to be logged. :param to_terminal: If True, prints to the terminal too. """ + if SIM_OUTPUT.log_level.value > LogLevel.WARNING.value: + return + if SIM_OUTPUT.save_sys_logs: self.logger.warning(msg) self._write_to_terminal(msg, "WARNING", to_terminal) @@ -132,6 +141,9 @@ class SysLog: :param msg: The message to be logged. :param to_terminal: If True, prints to the terminal too. """ + if SIM_OUTPUT.log_level.value > LogLevel.ERROR.value: + return + if SIM_OUTPUT.save_sys_logs: self.logger.error(msg) self._write_to_terminal(msg, "ERROR", to_terminal) @@ -143,6 +155,9 @@ class SysLog: :param msg: The message to be logged. :param to_terminal: If True, prints to the terminal too. """ + if LogLevel.CRITICAL.value < SIM_OUTPUT.log_level.value: + return + if SIM_OUTPUT.save_sys_logs: self.logger.critical(msg) self._write_to_terminal(msg, "CRITICAL", to_terminal) diff --git a/tests/unit_tests/_primaite/_simulator/_system/core/test_sys_log.py b/tests/unit_tests/_primaite/_simulator/_system/core/test_sys_log.py new file mode 100644 index 00000000..610aad1c --- /dev/null +++ b/tests/unit_tests/_primaite/_simulator/_system/core/test_sys_log.py @@ -0,0 +1,149 @@ +from uuid import uuid4 + +import pytest + +from primaite.simulator import LogLevel, SIM_OUTPUT +from primaite.simulator.system.core.sys_log import SysLog + + +@pytest.fixture(scope="function") +def syslog() -> SysLog: + return SysLog(hostname="test") + + +def test_off_log_level(syslog, capsys): + """Test that the debug log level logs debug syslogs and above.""" + SIM_OUTPUT.log_level = LogLevel.OFF + SIM_OUTPUT.write_sys_log_to_terminal = True + + test_string = str(uuid4()) + + syslog.debug(test_string) + syslog.info(test_string) + syslog.warning(test_string) + syslog.error(test_string) + syslog.critical(test_string) + + captured = "".join(capsys.readouterr()) + + assert test_string not in captured + assert "DEBUG" not in captured + assert "INFO" not in captured + assert "WARNING" not in captured + assert "ERROR" not in captured + assert "CRITICAL" not in captured + + +def test_debug_log_level(syslog, capsys): + """Test that the debug log level logs debug syslogs and above.""" + SIM_OUTPUT.log_level = LogLevel.DEBUG + SIM_OUTPUT.write_sys_log_to_terminal = True + + test_string = str(uuid4()) + + syslog.debug(test_string) + syslog.info(test_string) + syslog.warning(test_string) + syslog.error(test_string) + syslog.critical(test_string) + + captured = "".join(capsys.readouterr()) + + assert test_string in captured + assert "DEBUG" in captured + assert "INFO" in captured + assert "WARNING" in captured + assert "ERROR" in captured + assert "CRITICAL" in captured + + +def test_info_log_level(syslog, capsys): + """Test that the debug log level logs debug syslogs and above.""" + SIM_OUTPUT.log_level = LogLevel.INFO + SIM_OUTPUT.write_sys_log_to_terminal = True + + test_string = str(uuid4()) + + syslog.debug(test_string) + syslog.info(test_string) + syslog.warning(test_string) + syslog.error(test_string) + syslog.critical(test_string) + + captured = "".join(capsys.readouterr()) + + assert test_string in captured + assert "DEBUG" not in captured + assert "INFO" in captured + assert "WARNING" in captured + assert "ERROR" in captured + assert "CRITICAL" in captured + + +def test_warning_log_level(syslog, capsys): + """Test that the debug log level logs debug syslogs and above.""" + SIM_OUTPUT.log_level = LogLevel.WARNING + SIM_OUTPUT.write_sys_log_to_terminal = True + + test_string = str(uuid4()) + + syslog.debug(test_string) + syslog.info(test_string) + syslog.warning(test_string) + syslog.error(test_string) + syslog.critical(test_string) + + captured = "".join(capsys.readouterr()) + + assert test_string in captured + assert "DEBUG" not in captured + assert "INFO" not in captured + assert "WARNING" in captured + assert "ERROR" in captured + assert "CRITICAL" in captured + + +def test_error_log_level(syslog, capsys): + """Test that the debug log level logs debug syslogs and above.""" + SIM_OUTPUT.log_level = LogLevel.ERROR + SIM_OUTPUT.write_sys_log_to_terminal = True + + test_string = str(uuid4()) + + syslog.debug(test_string) + syslog.info(test_string) + syslog.warning(test_string) + syslog.error(test_string) + syslog.critical(test_string) + + captured = "".join(capsys.readouterr()) + + assert test_string in captured + assert "DEBUG" not in captured + assert "INFO" not in captured + assert "WARNING" not in captured + assert "ERROR" in captured + assert "CRITICAL" in captured + + +def test_critical_log_level(syslog, capsys): + """Test that the debug log level logs debug syslogs and above.""" + SIM_OUTPUT.log_level = LogLevel.CRITICAL + SIM_OUTPUT.write_sys_log_to_terminal = True + + test_string = str(uuid4()) + + syslog.debug(test_string) + syslog.info(test_string) + syslog.warning(test_string) + syslog.error(test_string) + syslog.critical(test_string) + + captured = "".join(capsys.readouterr()) + + assert test_string in captured + assert "DEBUG" not in captured + assert "INFO" not in captured + assert "WARNING" not in captured + assert "ERROR" not in captured + assert "CRITICAL" in captured