1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//! Write every panic to the log before the process or the task loses it.
//!
//! **A panic inside `tokio::spawn` is swallowed by the task**, and almost everything NetGet does
//! on behalf of a peer runs inside one. `JoinHandle` carries the `JoinError`, but nothing here
//! awaits those handles — a connection task is spawned and forgotten — so the panic went
//! nowhere at all. The observable result was the shape recorded three times in the root
//! `CLAUDE.md`: the task dies, the server stays `Running`, the log shows the operation
//! succeeding, and the peer hangs until its own timeout. `block_on` inside
//! `UsbInterfaceHandler::handle_urb`, `blocking_lock()` in SMB's connection task and the
//! `.unwrap()`s inside spawned client tasks were all found by reading code, because there was
//! nothing to grep for.
//!
//! The only `set_hook` in the tree before this one lives in the dashboard's event loop and
//! restores the terminal. It is installed by the TUI alone, so `--mcp`, `--mcp-http` and
//! non-interactive runs had no hook at all.
//!
//! This hook is installed from `cli::setup::init_logging`, which every entry point calls
//! before doing any work, and it **chains to whatever hook it replaced** — so the dashboard's
//! terminal-restore hook (installed later, over this one, via `take_hook`) still runs first and
//! this one still logs.
use Once;
static INSTALLED: Once = new;
/// Install the logging panic hook. Idempotent; safe to call from every entry point.
///
/// Call this *after* the tracing subscriber is initialised — a panic logged before there is a
/// subscriber goes to the same place the panic would have gone, which is nowhere.
/// Extract a panic payload's message.
///
/// Public because `tests/panic_is_logged_test.rs` asserts the `String` arm: `panic!("{x}")`
/// produces a `String` payload rather than a `&str`, and a hook that only downcasts to `&str`
/// reports every formatted panic — which is most of them — as unreadable.