refactor(logging): preserve tracebacks and add channel context

- Preserve tracebacks: logger.error in except blocks → logger.exception
- Channel context: BaseChannel injects self.logger = logger.bind(channel=name)
- Third-party bridge: redirect_lib_logging() replaces ad-hoc stdlib-to-loguru bridges
- Log levels: network timeouts downgraded from ERROR → WARNING
- Fix --verbose flag to actually work with loguru (set handler to DEBUG)
This commit is contained in:
chengyongru
2026-05-06 21:17:45 +08:00
committed by Xubin Ren
parent e54fbfeb2a
commit 05e0106592
35 changed files with 631 additions and 579 deletions
+1 -1
View File
@@ -643,7 +643,7 @@ def test_persist_tool_result_logs_cleanup_failures(monkeypatch, tmp_path):
lambda *_args, **_kwargs: (_ for _ in ()).throw(OSError("busy")),
)
monkeypatch.setattr(
"nanobot.utils.helpers.logger.warning",
"nanobot.utils.helpers.logger.exception",
lambda message, *args: warnings.append(message.format(*args)),
)
+13 -8
View File
@@ -306,17 +306,19 @@ async def test_on_error_logs_network_issues_as_warning(monkeypatch) -> None:
recorded: list[tuple[str, str]] = []
monkeypatch.setattr(
"nanobot.channels.telegram.logger.warning",
channel.logger,
"warning",
lambda message, error: recorded.append(("warning", message.format(error))),
)
monkeypatch.setattr(
"nanobot.channels.telegram.logger.error",
channel.logger,
"error",
lambda message, error: recorded.append(("error", message.format(error))),
)
await channel._on_error(object(), SimpleNamespace(error=NetworkError("proxy disconnected")))
assert recorded == [("warning", "Telegram network issue: proxy disconnected")]
assert recorded == [("warning", "network issue: proxy disconnected")]
@pytest.mark.asyncio
@@ -330,13 +332,14 @@ async def test_on_error_summarizes_empty_network_error(monkeypatch) -> None:
recorded: list[tuple[str, str]] = []
monkeypatch.setattr(
"nanobot.channels.telegram.logger.warning",
channel.logger,
"warning",
lambda message, error: recorded.append(("warning", message.format(error))),
)
await channel._on_error(object(), SimpleNamespace(error=NetworkError("")))
assert recorded == [("warning", "Telegram network issue: NetworkError")]
assert recorded == [("warning", "network issue: NetworkError")]
@pytest.mark.asyncio
@@ -348,17 +351,19 @@ async def test_on_error_keeps_non_network_exceptions_as_error(monkeypatch) -> No
recorded: list[tuple[str, str]] = []
monkeypatch.setattr(
"nanobot.channels.telegram.logger.warning",
channel.logger,
"warning",
lambda message, error: recorded.append(("warning", message.format(error))),
)
monkeypatch.setattr(
"nanobot.channels.telegram.logger.error",
channel.logger,
"error",
lambda message, error: recorded.append(("error", message.format(error))),
)
await channel._on_error(object(), SimpleNamespace(error=RuntimeError("boom")))
assert recorded == [("error", "Telegram error: boom")]
assert recorded == [("error", "error: boom")]
@pytest.mark.asyncio
+1 -1
View File
@@ -835,7 +835,7 @@ async def test_start_logs_install_hint_when_pyjwt_missing(make_channel, monkeypa
ch = make_channel()
errors = []
monkeypatch.setattr(msteams_module, "MSTEAMS_AVAILABLE", False)
monkeypatch.setattr(msteams_module.logger, "error", lambda message, *args: errors.append(message.format(*args)))
monkeypatch.setattr(ch.logger, "error", lambda message, *args: errors.append(message.format(*args)))
await ch.start()
+1 -1
View File
@@ -467,7 +467,7 @@ async def test_connect_mcp_servers_logs_stdio_pollution_hint(
yield # pragma: no cover
monkeypatch.setattr(sys.modules["mcp.client.stdio"], "stdio_client", _broken_stdio_client)
monkeypatch.setattr("nanobot.agent.tools.mcp.logger.error", _error)
monkeypatch.setattr("nanobot.agent.tools.mcp.logger.exception", _error)
registry = ToolRegistry()
stacks = await connect_mcp_servers({"gh": MCPServerConfig(command="github-mcp")}, registry)