From c97ac19b7bfbe19443a12950e6ee9feb4f3a24d4 Mon Sep 17 00:00:00 2001 From: kimi Date: Fri, 20 Mar 2026 23:48:33 -0400 Subject: [PATCH] fix: add logging to silent except Exception handlers across codebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add logger.exception() calls to 20 silent except Exception handlers that were swallowing errors without any logging, making production debugging extremely difficult. Files fixed: - timmy/loop_qa.py (6 handlers in probe functions + orchestrator) - timmy/backends.py (2 handlers in health_check methods) - timmy/tools_delegation/__init__.py (1 handler in _run_kimi) - timmy/tools_intro/__init__.py (4 handlers in introspection tools) - dashboard/middleware/request_logging.py (1 handler upgraded debug→warning) - dashboard/routes/health.py (1 handler in _check_sqlite) - dashboard/routes/grok.py (2 handlers in query and stats) - dashboard/routes/voice.py (1 handler in tts_speak) - dashboard/routes/db_explorer.py (2 handlers in _query_database) No control flow changes — only added logging before existing returns. Fixes #646 Co-Authored-By: Claude Opus 4.6 --- src/dashboard/middleware/request_logging.py | 2 +- src/dashboard/routes/db_explorer.py | 2 ++ src/dashboard/routes/grok.py | 2 ++ src/dashboard/routes/health.py | 1 + src/dashboard/routes/voice.py | 1 + src/timmy/backends.py | 2 ++ src/timmy/loop_qa.py | 6 ++++++ src/timmy/tools_delegation/__init__.py | 1 + src/timmy/tools_intro/__init__.py | 4 ++++ 9 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/dashboard/middleware/request_logging.py b/src/dashboard/middleware/request_logging.py index 8d6e8f0f..57688206 100644 --- a/src/dashboard/middleware/request_logging.py +++ b/src/dashboard/middleware/request_logging.py @@ -116,7 +116,7 @@ class RequestLoggingMiddleware(BaseHTTPMiddleware): }, ) except Exception as exc: - logger.debug("Escalation logging error: %s", exc) + logger.warning("Escalation logging error: %s", exc) pass # never let escalation break the request # Re-raise the exception diff --git a/src/dashboard/routes/db_explorer.py b/src/dashboard/routes/db_explorer.py index 007cfb47..3335bec7 100644 --- a/src/dashboard/routes/db_explorer.py +++ b/src/dashboard/routes/db_explorer.py @@ -75,6 +75,7 @@ def _query_database(db_path: str) -> dict: "truncated": count > MAX_ROWS, } except Exception as exc: + logger.exception("Failed to query table %s", table_name) result["tables"][table_name] = { "error": str(exc), "columns": [], @@ -83,6 +84,7 @@ def _query_database(db_path: str) -> dict: "truncated": False, } except Exception as exc: + logger.exception("Failed to query database %s", db_path) result["error"] = str(exc) return result diff --git a/src/dashboard/routes/grok.py b/src/dashboard/routes/grok.py index 4b44316d..cf6ef33e 100644 --- a/src/dashboard/routes/grok.py +++ b/src/dashboard/routes/grok.py @@ -135,6 +135,7 @@ def _run_grok_query(message: str) -> dict: result = backend.run(message) return {"response": f"**[Grok]{invoice_note}:** {result.content}", "error": None} except Exception as exc: + logger.exception("Grok query failed") return {"response": None, "error": f"Grok error: {exc}"} @@ -193,6 +194,7 @@ async def grok_stats(): "model": settings.grok_default_model, } except Exception as exc: + logger.exception("Failed to load Grok stats") return {"error": str(exc)} diff --git a/src/dashboard/routes/health.py b/src/dashboard/routes/health.py index 7b57ac49..f9a19614 100644 --- a/src/dashboard/routes/health.py +++ b/src/dashboard/routes/health.py @@ -148,6 +148,7 @@ def _check_sqlite() -> DependencyStatus: details={"path": str(db_path)}, ) except Exception as exc: + logger.exception("SQLite health check failed") return DependencyStatus( name="SQLite Database", status="unavailable", diff --git a/src/dashboard/routes/voice.py b/src/dashboard/routes/voice.py index 00e7659b..10ea95ad 100644 --- a/src/dashboard/routes/voice.py +++ b/src/dashboard/routes/voice.py @@ -59,6 +59,7 @@ async def tts_speak(text: str = Form(...)): voice_tts.speak(text) return {"spoken": True, "text": text} except Exception as exc: + logger.exception("TTS speak failed") return {"spoken": False, "reason": str(exc)} diff --git a/src/timmy/backends.py b/src/timmy/backends.py index 3102a6b5..3ecd3d6f 100644 --- a/src/timmy/backends.py +++ b/src/timmy/backends.py @@ -264,6 +264,7 @@ class GrokBackend: }, } except Exception as exc: + logger.exception("Grok health check failed") return { "ok": False, "error": str(exc), @@ -430,6 +431,7 @@ class ClaudeBackend: ) return {"ok": True, "error": None, "backend": "claude", "model": self._model} except Exception as exc: + logger.exception("Claude health check failed") return {"ok": False, "error": str(exc), "backend": "claude", "model": self._model} # ── Private helpers ─────────────────────────────────────────────────── diff --git a/src/timmy/loop_qa.py b/src/timmy/loop_qa.py index a6673339..bba84b92 100644 --- a/src/timmy/loop_qa.py +++ b/src/timmy/loop_qa.py @@ -97,6 +97,7 @@ async def probe_tool_use() -> dict: "error_type": "empty_result", } except Exception as exc: + logger.exception("Tool use probe failed") return { "success": False, "capability": cap, @@ -129,6 +130,7 @@ async def probe_multistep_planning() -> dict: "error_type": "verification_failed", } except Exception as exc: + logger.exception("Multistep planning probe failed") return { "success": False, "capability": cap, @@ -151,6 +153,7 @@ async def probe_memory_write() -> dict: "error_type": None, } except Exception as exc: + logger.exception("Memory write probe failed") return { "success": False, "capability": cap, @@ -179,6 +182,7 @@ async def probe_memory_read() -> dict: "error_type": "empty_result", } except Exception as exc: + logger.exception("Memory read probe failed") return { "success": False, "capability": cap, @@ -214,6 +218,7 @@ async def probe_self_coding() -> dict: "error_type": "verification_failed", } except Exception as exc: + logger.exception("Self-coding probe failed") return { "success": False, "capability": cap, @@ -325,6 +330,7 @@ class LoopQAOrchestrator: result = await probe_fn() except Exception as exc: # Probe itself crashed — record failure and report + logger.exception("Loop QA probe %s crashed", cap.value) capture_error(exc, source="loop_qa", context={"capability": cap.value}) result = { "success": False, diff --git a/src/timmy/tools_delegation/__init__.py b/src/timmy/tools_delegation/__init__.py index 65c4bcdf..dee9e8a5 100644 --- a/src/timmy/tools_delegation/__init__.py +++ b/src/timmy/tools_delegation/__init__.py @@ -139,6 +139,7 @@ def _run_kimi(cmd: list[str], workdir: str) -> dict[str, Any]: "error": "Kimi timed out after 300s. Task may be too broad — try breaking it into smaller pieces.", } except Exception as exc: + logger.exception("Failed to run Kimi subprocess") return { "success": False, "error": f"Failed to run Kimi: {exc}", diff --git a/src/timmy/tools_intro/__init__.py b/src/timmy/tools_intro/__init__.py index abff208f..5f230ae2 100644 --- a/src/timmy/tools_intro/__init__.py +++ b/src/timmy/tools_intro/__init__.py @@ -122,6 +122,7 @@ def check_ollama_health() -> dict[str, Any]: models = response.json().get("models", []) result["available_models"] = [m.get("name", "") for m in models] except Exception as e: + logger.exception("Ollama health check failed") result["error"] = str(e) return result @@ -289,6 +290,7 @@ def get_live_system_status() -> dict[str, Any]: try: result["system"] = get_system_info() except Exception as exc: + logger.exception("Failed to get system info") result["system"] = {"error": str(exc)} # Task queue @@ -301,6 +303,7 @@ def get_live_system_status() -> dict[str, Any]: try: result["memory"] = get_memory_status() except Exception as exc: + logger.exception("Failed to get memory status") result["memory"] = {"error": str(exc)} # Uptime @@ -406,4 +409,5 @@ def run_self_tests(scope: str = "fast", _repo_root: str | None = None) -> dict[s except subprocess.TimeoutExpired: return {"success": False, "error": "Test run timed out (120s limit)"} except Exception as exc: + logger.exception("Self-test run failed") return {"success": False, "error": str(exc)} -- 2.43.0