From 98660c19ccf9950c7f986310512aa616d7fd893f Mon Sep 17 00:00:00 2001 From: Lanre Shittu <136805224+Shizoqua@users.noreply.github.com> Date: Thu, 20 Aug 2026 16:33:39 +0100 Subject: [PATCH] fix(matrix): interpolate error log context Matrix error logs used printf-style placeholders with Loguru, leaving filenames, room IDs, and chat IDs out of diagnostic output. Use Loguru placeholders and cover each affected failure path with focused regression assertions. Signed-off-by: Lanre Shittu <136805224+Shizoqua@users.noreply.github.com> --- nanobot/channels/matrix/runtime.py | 6 ++-- .../matrix/tests/test_matrix_channel.py | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/nanobot/channels/matrix/runtime.py b/nanobot/channels/matrix/runtime.py index f0d9187ef..fb801811a 100644 --- a/nanobot/channels/matrix/runtime.py +++ b/nanobot/channels/matrix/runtime.py @@ -561,7 +561,7 @@ class MatrixChannel(BaseChannel): filesize=size_bytes, ) except Exception: - self.logger.error("Matrix media upload failed for %s", filename, exc_info=True) + self.logger.error("Matrix media upload failed for {}", filename, exc_info=True) return fail is_tuple_result = isinstance(cast(object, upload_result), tuple) @@ -586,7 +586,7 @@ class MatrixChannel(BaseChannel): try: await self._send_room_content(room_id, content) except Exception: - self.logger.error("Matrix room content send failed for room_id=%s", room_id, exc_info=True) + self.logger.error("Matrix room content send failed for room_id={}", room_id, exc_info=True) return fail return None @@ -681,7 +681,7 @@ class MatrixChannel(BaseChannel): # we are editing the same message all the time, so only the first time the event id needs to be set buf.event_id = cast(RoomSendResponse, response).event_id except Exception: - self.logger.error("Stream send/edit failed for chat_id=%s", chat_id, exc_info=True) + self.logger.error("Stream send/edit failed for chat_id={}", chat_id, exc_info=True) await self._stop_typing_keepalive(chat_id, clear_typing=True) diff --git a/nanobot/channels/matrix/tests/test_matrix_channel.py b/nanobot/channels/matrix/tests/test_matrix_channel.py index ae5729a52..03d7e2771 100644 --- a/nanobot/channels/matrix/tests/test_matrix_channel.py +++ b/nanobot/channels/matrix/tests/test_matrix_channel.py @@ -4,6 +4,7 @@ import asyncio import sys from pathlib import Path from types import SimpleNamespace +from unittest.mock import MagicMock from urllib.parse import unquote import pytest @@ -1566,6 +1567,7 @@ async def test_send_workspace_restriction_blocks_external_attachment(tmp_path) - @pytest.mark.asyncio async def test_send_handles_upload_exception_and_reports_failure(tmp_path) -> None: channel = MatrixChannel(_make_config(), MessageBus()) + channel.logger = MagicMock() client = _FakeAsyncClient("", "", "", None) client.raise_on_upload = True channel.client = client @@ -1588,6 +1590,34 @@ async def test_send_handles_upload_exception_and_reports_failure(tmp_path) -> No client.room_send_calls[0]["content"]["body"] == "Please review.\n[attachment: broken.txt - upload failed]" ) + channel.logger.error.assert_called_once_with( + "Matrix media upload failed for {}", "broken.txt", exc_info=True + ) + + +@pytest.mark.asyncio +async def test_attachment_room_send_error_logs_room_id(tmp_path) -> None: + channel = MatrixChannel(_make_config(), MessageBus()) + channel.logger = MagicMock() + client = _FakeAsyncClient("", "", "", None) + client.raise_on_send = True + channel.client = client + + file_path = tmp_path / "report.txt" + file_path.write_text("hello", encoding="utf-8") + + failure = await channel._upload_and_send_attachment( + room_id="!room:matrix.org", + path=file_path, + limit_bytes=1024, + ) + + assert failure == "[attachment: report.txt - upload failed]" + channel.logger.error.assert_called_once_with( + "Matrix room content send failed for room_id={}", + "!room:matrix.org", + exc_info=True, + ) @pytest.mark.asyncio @@ -2212,6 +2242,7 @@ async def test_send_delta_stream_end_noop_when_buffer_missing() -> None: @pytest.mark.asyncio async def test_send_delta_on_error_stops_typing(monkeypatch) -> None: channel = MatrixChannel(_make_config(), MessageBus()) + channel.logger = MagicMock() client = _FakeAsyncClient("", "", "", None) client.raise_on_send = True channel.client = client @@ -2226,6 +2257,9 @@ async def test_send_delta_on_error_stops_typing(monkeypatch) -> None: assert len(client.room_send_calls) == 1 assert len(client.typing_calls) == 1 + channel.logger.error.assert_called_once_with( + "Stream send/edit failed for chat_id={}", "!room:matrix.org", exc_info=True + ) @pytest.mark.asyncio