diff --git a/CHANGELOG.md b/CHANGELOG.md index 49ea8ad9..7895c3e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ All notable changes to the Zowe Client Python SDK will be documented in this fil - Fixed a bug on `create` in `Datasets` where the target dataset gets created with a different block size when `like` is specified [#295] (https://github.com/zowe/zowe-client-python-sdk/issues/295) +- Fixed a bug on `logger` that it would affect all Python application loggers. + ## `1.0.0-dev17` ### Enhancements diff --git a/src/core/zowe/core_for_zowe_sdk/logger.py b/src/core/zowe/core_for_zowe_sdk/logger.py index dff3bfca..f7141c71 100644 --- a/src/core/zowe/core_for_zowe_sdk/logger.py +++ b/src/core/zowe/core_for_zowe_sdk/logger.py @@ -9,18 +9,29 @@ class Log: ------- loggers: set The set of all loggers + dirname: str + Path where the log file is saved + file_handler: logging.FileHandler + Shared FileHandler object for managing log file output + console_handler: logging.StreamHandler + Shared StreamHandler object for managing log console output + file_output: bool + Specifies whether log messages would be saved to a file. True by default. + console_output: bool + Specifies whether log messages would be printed out on console. True by default. """ - dirname = os.path.join(os.path.expanduser("~"), ".zowe/logs") - + dirname: str = os.path.join(os.path.expanduser("~"), ".zowe/logs") os.makedirs(dirname, exist_ok=True) - - logging.basicConfig( - filename=os.path.join(dirname, "python_sdk_logs.log"), - level=logging.INFO, - format="[%(asctime)s] [%(levelname)s] [%(name)s] - %(message)s", - datefmt="%m/%d/%Y %I:%M:%S %p", + file_handler: logging.FileHandler = logging.FileHandler(os.path.join(dirname, "python_sdk_logs.log")) + file_handler.setLevel(logging.INFO) + file_handler.setFormatter( + logging.Formatter("[%(asctime)s] [%(levelname)s] [%(name)s] - %(message)s", "%m/%d/%Y %I:%M:%S %p") ) + console_handler = logging.StreamHandler() + + file_output: bool = True + console_output: bool = True loggers = set() @@ -40,6 +51,11 @@ def registerLogger(name: str): A Logger object named after the file where it is created """ logger = logging.getLogger(name) + if Log.console_output: + logger.addHandler(Log.console_handler) + if Log.file_output: + logger.addHandler(Log.file_handler) + logger.propagate = False Log.loggers.add(logger) return logger @@ -55,6 +71,8 @@ def setAllLoggerLevel(level: int): """ for logger in Log.loggers: logger.setLevel(level) + for handler in logger.handlers: + handler.setLevel(level) @staticmethod def close(logger): @@ -82,16 +100,64 @@ def open(logger): @staticmethod def closeAll(): - """ - Disable all loggers - """ + """Disable all loggers.""" for logger in Log.loggers: logger.disabled = True @staticmethod def openAll(): + """Enable all loggers.""" + for logger in Log.loggers: + logger.disabled = False + + @staticmethod + def close_console_output(): + """Turn off log output to console.""" + Log.console_output = False + for logger in Log.loggers: + logger.removeHandler(Log.console_handler) + + @staticmethod + def open_console_output(): + """Turn on log output to console.""" + Log.console_output = True + for logger in Log.loggers: + logger.addHandler(Log.console_handler) + + @staticmethod + def set_console_output_level(level: int): """ - Enable all loggers + Set the level for the console handler. + + Parameters + ---------- + level: int + The intended console output level """ + Log.console_handler.level = level + + @staticmethod + def close_file_output(): + """Turn off log output to a file.""" + Log.file_output = False for logger in Log.loggers: - logger.disabled = False + logger.removeHandler(Log.file_handler) + + @staticmethod + def open_file_output(): + """Turn on log output to a file.""" + Log.file_output = True + for logger in Log.loggers: + logger.addHandler(Log.file_handler) + + @staticmethod + def set_file_output_level(level: int): + """ + Set the level for the file handler. + + Parameters + ---------- + level: int + The intended file output level + """ + Log.file_handler.level = level diff --git a/tests/unit/core/test_logger.py b/tests/unit/core/test_logger.py index f7f7ba35..145b58cd 100644 --- a/tests/unit/core/test_logger.py +++ b/tests/unit/core/test_logger.py @@ -2,6 +2,8 @@ # Including necessary paths import logging +import os +from unittest import mock from pyfakefs.fake_filesystem_unittest import TestCase from zowe.core_for_zowe_sdk.logger import Log @@ -52,3 +54,25 @@ def test_all_loggers(self): test_2.error("hi") self.assertIn("hi", log2.output[0]) + + def test_console_handler(self): + Log.close_console_output() + test = Log.registerLogger("test") + self.assertEqual(test.handlers[0], Log.file_handler) + + Log.open_console_output() + self.assertEqual(test.handlers[1], Log.console_handler) + + Log.set_console_output_level(logging.ERROR) + self.assertEqual(logging.ERROR, test.handlers[1].level) + + def test_file_handler(self): + Log.close_file_output() + test = Log.registerLogger("test") + self.assertEqual(test.handlers[0], Log.console_handler) + + Log.open_file_output() + self.assertEqual(test.handlers[1], Log.file_handler) + + Log.set_file_output_level(logging.ERROR) + self.assertEqual(logging.ERROR, test.handlers[1].level) diff --git a/tests/unit/core/test_profile_manager.py b/tests/unit/core/test_profile_manager.py index 95df9833..f5ee5e1e 100644 --- a/tests/unit/core/test_profile_manager.py +++ b/tests/unit/core/test_profile_manager.py @@ -48,6 +48,7 @@ def setUp(self): self.original_nested_file_path = os.path.join(FIXTURES_PATH, "nested.zowe.config.json") self.original_nested_user_file_path = os.path.join(FIXTURES_PATH, "nested.zowe.config.user.json") self.original_schema_file_path = os.path.join(FIXTURES_PATH, "zowe.schema.json") + self.fs.create_dir(os.path.join(os.path.expanduser("~"), ".zowe/logs")) loader = importlib.util.find_spec("jsonschema") module_path = loader.origin