diff --git a/invokeai/backend/util/logging.py b/invokeai/backend/util/logging.py index be8aeec9c9..c607e91835 100644 --- a/invokeai/backend/util/logging.py +++ b/invokeai/backend/util/logging.py @@ -342,14 +342,13 @@ class InvokeAILogger(object): # noqa D102 cls, name: str = "InvokeAI", config: InvokeAIAppConfig = InvokeAIAppConfig.get_config() ) -> logging.Logger: # noqa D102 if name in cls.loggers: - logger = cls.loggers[name] - logger.handlers.clear() - else: - logger = logging.getLogger(name) + return cls.loggers[name] + + logger = logging.getLogger(name) logger.setLevel(config.log_level.upper()) # yes, strings work here for ch in cls.get_loggers(config): logger.addHandler(ch) - cls.loggers[name] = logger + cls.loggers[name] = logger return cls.loggers[name] @classmethod @@ -358,7 +357,7 @@ class InvokeAILogger(object): # noqa D102 handlers = [] for handler in handler_strs: handler_name, *args = handler.split("=", 2) - args = args[0] if len(args) > 0 else None + arg = args[0] if len(args) > 0 else None # console and file get the fancy formatter. # syslog gets a simple one @@ -370,16 +369,16 @@ class InvokeAILogger(object): # noqa D102 handlers.append(ch) elif handler_name == "syslog": - ch = cls._parse_syslog_args(args) + ch = cls._parse_syslog_args(arg) handlers.append(ch) elif handler_name == "file": - ch = cls._parse_file_args(args) + ch = cls._parse_file_args(arg) ch.setFormatter(formatter()) handlers.append(ch) elif handler_name == "http": - ch = cls._parse_http_args(args) + ch = cls._parse_http_args(arg) handlers.append(ch) return handlers diff --git a/tests/backend/util/test_logging.py b/tests/backend/util/test_logging.py new file mode 100644 index 0000000000..0d229df7c1 --- /dev/null +++ b/tests/backend/util/test_logging.py @@ -0,0 +1,57 @@ +""" +Test interaction of logging with configuration system. +""" +import io +import logging +import re + +from invokeai.app.services.config import InvokeAIAppConfig +from invokeai.backend.util.logging import LOG_FORMATTERS, InvokeAILogger + + +# test formatting +# Would prefer to use the capfd/capsys fixture here, but it is broken +# when used with the logging module: https://github.com/pytest-dev/pytest/issue +def test_formatting(): + logger = InvokeAILogger.get_logger() + stream = io.StringIO() + handler = logging.StreamHandler(stream) + handler.setFormatter(LOG_FORMATTERS["plain"]()) + logger.addHandler(handler) + logger.info("test1") + output = stream.getvalue() + assert re.search(r"\[InvokeAI\]::INFO --> test1$", output) + + handler.setFormatter(LOG_FORMATTERS["legacy"]()) + logger.info("test2") + output = stream.getvalue() + assert re.search(r">> test2$", output) + + +# test independence of two loggers with different names +def test_independence(): + logger1 = InvokeAILogger.get_logger() + logger2 = InvokeAILogger.get_logger("Test") + assert logger1.name == "InvokeAI" + assert logger2.name == "Test" + assert logger1.level == logging.INFO + assert logger2.level == logging.INFO + logger2.setLevel(logging.DEBUG) + assert logger1.level == logging.INFO + assert logger2.level == logging.DEBUG + + +# test that the logger is returned from two similar get_logger() calls +def test_retrieval(): + logger1 = InvokeAILogger.get_logger() + logger2 = InvokeAILogger.get_logger() + logger3 = InvokeAILogger.get_logger("Test") + assert logger1 == logger2 + assert logger1 != logger3 + + +# test that the configuration is used to set the initial logging level +def test_config(): + config = InvokeAIAppConfig(log_level="debug") + logger1 = InvokeAILogger.get_logger("DebugTest", config=config) + assert logger1.level == logging.DEBUG