diff --git a/gator/common/logger.py b/gator/common/logger.py index 3464a13..57cdb6d 100644 --- a/gator/common/logger.py +++ b/gator/common/logger.py @@ -152,8 +152,11 @@ async def log( # Generate a timestamp if required if timestamp is None: timestamp = datetime.now() + # Always forward warnings, errors, and critical messages from Gator itself + # (not forwarded from children), regardless of forward setting + should_forward = forward or (not forwarded and severity >= LogSeverity.WARNING) # If linked to parent and forwarding requested, push log upwards - if forward and self.ws_cli.linked and severity >= self.verbosity: + if should_forward and self.ws_cli.linked and severity >= self.verbosity: await self.ws_cli.log( timestamp=int(timestamp.timestamp()), hierarchy=hierarchy, diff --git a/tests/common/test_logger.py b/tests/common/test_logger.py index f2975b3..787c081 100644 --- a/tests/common/test_logger.py +++ b/tests/common/test_logger.py @@ -111,6 +111,77 @@ async def test_local(self, logger_local): ) logger._Logger__console.log.reset_mock() + @pytest.mark.asyncio + async def test_linked_no_forward(self, logger_linked): + """When forward=False, warnings and errors are still forwarded""" + logger = logger_linked + logger.forward = False + logger.verbosity = LogSeverity.DEBUG + # Debug should not be forwarded + await logger.debug("Testing debug") + assert not logger.ws_cli.log.called + logger._Logger__console.log.assert_called_with( + "[bold cyan]DEBUG [/bold cyan] " + TestLogger.ROOT_STR + " Testing debug" + ) + logger._Logger__console.log.reset_mock() + # Info should not be forwarded + await logger.info("Testing info") + assert not logger.ws_cli.log.called + logger._Logger__console.log.assert_called_with( + "[bold]INFO [/bold] " + TestLogger.ROOT_STR + " Testing info" + ) + logger._Logger__console.log.reset_mock() + # Warning should be forwarded (even though forward=False) + await logger.warning("Testing warning") + logger.ws_cli.log.assert_called_with( + timestamp=1234, + hierarchy="root", + severity="WARNING", + message="Testing warning", + posted=True, + ) + logger._Logger__console.log.assert_called_with( + "[bold yellow]WARNING[/bold yellow] " + TestLogger.ROOT_STR + " Testing warning" + ) + logger.ws_cli.log.reset_mock() + logger._Logger__console.log.reset_mock() + # Error should be forwarded (even though forward=False) + await logger.error("Testing error") + logger.ws_cli.log.assert_called_with( + timestamp=1234, + hierarchy="root", + severity="ERROR", + message="Testing error", + posted=True, + ) + logger._Logger__console.log.assert_called_with( + "[bold red]ERROR [/bold red] " + TestLogger.ROOT_STR + " Testing error" + ) + logger.ws_cli.log.reset_mock() + logger._Logger__console.log.reset_mock() + # Critical should be forwarded (even though forward=False) + await logger.critical("Testing critical") + logger.ws_cli.log.assert_called_with( + timestamp=1234, + hierarchy="root", + severity="CRITICAL", + message="Testing critical", + posted=True, + ) + logger._Logger__console.log.assert_called_with( + "[bold white on red]CRITICAL[/bold white on red] " + + TestLogger.ROOT_STR + + " Testing critical" + ) + logger.ws_cli.log.reset_mock() + logger._Logger__console.log.reset_mock() + # Forwarded messages should only be forwarded when forward=True + await logger.warning("Forwarded warning", forwarded=True) + assert not logger.ws_cli.log.called + logger._Logger__console.log.assert_called_with( + "[bold yellow]WARNING[/bold yellow] " + TestLogger.ROOT_STR + " Forwarded warning" + ) + @pytest.mark.asyncio async def test_linked(self, logger_linked): """Local logging goes to the console"""