From 8a679bf662f412d910bef21527cc341e836ae05c Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Sun, 3 May 2026 07:10:19 -0500 Subject: [PATCH] chore(hooks): tracing::warn on hook failures (#455 follow-up) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hook failures were silent — the executor returned a `HookResult` with `success=false`, but every call site discards it with `let _ = ...`. Operators tailing `deepseek` had no visibility into hook errors short of running each hook command by hand. Centralizes the logging inside `HookExecutor::execute` so every fire site benefits without sprinkling instrumentation. Logs through `tracing::warn!` with structured fields (`hook`, `event`, `exit_code`, `duration_ms`, `error`, `stderr_head`) so operators can `RUST_LOG=warn deepseek` and immediately see which hooks are misbehaving. Successful runs log nothing — `tool_call_before` / `tool_call_after` fire on every tool dispatch, so per-call success logging would be unreadably noisy. No behavioral change for users with no hooks (the function fast-paths out before reaching this branch). No behavioral change for users with passing hooks. Failed hooks still respect `continue_on_error` and the surrounding loop is unchanged. --- crates/tui/src/hooks.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/crates/tui/src/hooks.rs b/crates/tui/src/hooks.rs index 76234aab..f6be4f55 100644 --- a/crates/tui/src/hooks.rs +++ b/crates/tui/src/hooks.rs @@ -521,6 +521,24 @@ impl HookExecutor { self.execute_sync(hook, &env_vars) }; + // Log failures via tracing so operators tailing + // `deepseek` with `RUST_LOG=warn` can see hook errors + // without instrumenting each call site. Successful runs + // log nothing (would be too noisy on per-tool events). + if !result.success { + let label = result.name.as_deref().unwrap_or("(unnamed)"); + tracing::warn!( + target: "hooks", + hook = label, + event = event.as_str(), + exit_code = ?result.exit_code, + duration_ms = result.duration.as_millis() as u64, + error = result.error.as_deref().unwrap_or(""), + stderr_head = %result.stderr.lines().next().unwrap_or(""), + "hook failed" + ); + } + let should_continue = result.success || hook.continue_on_error; results.push(result);