diff --git a/tests/pytest/logger/test_logger_buffer.py b/tests/pytest/logger/test_logger_buffer.py index 20455076..4b159501 100644 --- a/tests/pytest/logger/test_logger_buffer.py +++ b/tests/pytest/logger/test_logger_buffer.py @@ -27,6 +27,7 @@ def test_multiple_logs_stored(test_logger): assert msg in logs[i]["message"] def test_log_levels_stored(test_logger): + """Debug messages are filtered when print_debug is False (default).""" logger, buffer = test_logger logger.debug("Debug message") logger.info("Info message") @@ -34,7 +35,30 @@ def test_log_levels_stored(test_logger): logger.error("Error message") logs = buffer.get_logs() levels = [log["level"] for log in logs] - assert levels == ["DEBUG", "INFO", "WARNING", "ERROR"] + assert levels == ["INFO", "WARNING", "ERROR"] + + +def test_log_levels_stored_with_print_debug(test_logger): + """Debug messages pass through when print_debug is enabled.""" + from webserver.logger.config import LoggerConfig + from webserver.logger import get_logger + + LoggerConfig.print_debug = True + try: + # Re-fetch logger to apply new level to handlers + logger, buffer = get_logger("test_logger", use_buffer=True) + buffer.clear() + logger.debug("Debug message") + logger.info("Info message") + logger.warning("Warning message") + logger.error("Error message") + logs = buffer.get_logs() + levels = [log["level"] for log in logs] + assert levels == ["DEBUG", "INFO", "WARNING", "ERROR"] + finally: + LoggerConfig.print_debug = False + # Re-fetch to restore INFO level on handlers + get_logger("test_logger", use_buffer=True) def test_normalize_no_microseconds(test_logger): logger, buffer = test_logger diff --git a/webserver/logger/__init__.py b/webserver/logger/__init__.py index 1469219b..25704e14 100644 --- a/webserver/logger/__init__.py +++ b/webserver/logger/__init__.py @@ -2,7 +2,6 @@ import logging import sys -from .logger import get_logger from .parser import LogParser from .bufferhandler import BufferHandler from .formatter import JsonFormatter, HumanReadableFormatter @@ -49,7 +48,6 @@ def get_logger(name="runtime", use_buffer: bool = False): # Always update all handler levels to reflect current config for h in logger.handlers: - if isinstance(h, logging.StreamHandler): - h.setLevel(effective_level) + h.setLevel(effective_level) return logger, shared_buffer_handler diff --git a/webserver/logger/logger.py b/webserver/logger/logger.py deleted file mode 100644 index 943cbd77..00000000 --- a/webserver/logger/logger.py +++ /dev/null @@ -1,28 +0,0 @@ -# logger/logger.py -import logging -import sys -from .formatter import JsonFormatter, HumanReadableFormatter -from .bufferhandler import BufferHandler - - -def get_logger(name: str = "logger", - level: int = logging.INFO, - use_buffer: bool = False): - """Return a logger instance with custom formatting.""" - - collector_logger = logging.getLogger(name) - collector_logger.setLevel(logging.DEBUG) - - # Always ensure a StreamHandler exists - if not any(isinstance(h, logging.StreamHandler) for h in collector_logger.handlers): - stream_handler = logging.StreamHandler(sys.stdout) - stream_handler.setFormatter(HumanReadableFormatter()) - collector_logger.addHandler(stream_handler) - - buffer_handler = None - if use_buffer and not any(isinstance(h, BufferHandler) for h in collector_logger.handlers): - buffer_handler = BufferHandler() - buffer_handler.setFormatter(JsonFormatter()) - collector_logger.addHandler(buffer_handler) - - return collector_logger, buffer_handler diff --git a/webserver/logger/parser.py b/webserver/logger/parser.py index 05bcda62..c0b7195b 100644 --- a/webserver/logger/parser.py +++ b/webserver/logger/parser.py @@ -9,11 +9,17 @@ LEVEL_MAP = { "DEBUG": logging.DEBUG, "INFO": logging.INFO, + "WARN": logging.WARNING, "WARNING": logging.WARNING, "ERROR": logging.ERROR, "CRITICAL": logging.CRITICAL, } +# Normalize non-standard level names to Python conventions +LEVEL_NORMALIZE = { + "WARN": "WARNING", +} + class LogParser: def __init__(self, collector_logger: logging.Logger): @@ -37,7 +43,9 @@ def parse_and_log(self, line: str): # Preserve incoming JSON fields, but ensure timestamp is present parsed.setdefault("timestamp", str(timestamp)) level_name = parsed.get("level", "INFO") + level_name = LEVEL_NORMALIZE.get(level_name, level_name) level = LEVEL_MAP.get(level_name, logging.INFO) + parsed["level"] = level_name log_entry = parsed else: raise ValueError("Not a valid log JSON dict") @@ -46,6 +54,7 @@ def parse_and_log(self, line: str): match = LOG_PATTERN.match(sline) if match: level_name = match["level"] + level_name = LEVEL_NORMALIZE.get(level_name, level_name) level = LEVEL_MAP.get(level_name, logging.INFO) message = match["message"] else: