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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//! Scoped `tracing` capture helper for warn-fire integration tests.
//!
//! # Why this exists
//!
//! brontes emits `tracing::warn!` at several sites that encode user-facing
//! behavior contracts:
//!
//! - Flag-value nested-container handling: when a tool call's JSON flag
//! value contains a nested object/array that cannot be rendered as a
//! scalar argv token, brontes warns and skips rather than passing the
//! value through verbatim like ophis does.
//! - Unknown `--log-level` policy: brontes warns on an unrecognized level
//! and falls back to `INFO`; ophis silently maps to `INFO`. The warn
//! surfaces typos at startup rather than letting the user wonder why
//! their level had no effect.
//! - 64-character MCP tool name warn: fires exactly once per offending
//! tool so consumers know to set `Config::tool_name_prefix`.
//! - `OUTPUT_CAP_BYTES` soft-cap exhaustion: a runaway tool subprocess
//! that floods stdout/stderr is silently truncated, with one warn per
//! stream so operators see the truncation in their logs.
//! - Selector substring no-match: a `selectors::allow_cmds_containing(..)`
//! needle that matches no walked command path is a misconfiguration the
//! user wants to know about at startup.
//!
//! Without this infrastructure, every one of these `tracing::warn!` sites
//! could be deleted and CI would stay green. The helper closes that gap.
//!
//! # Design
//!
//! The helper installs a [`tracing_subscriber::fmt`]-style subscriber whose
//! writer is a shared `Mutex<Vec<u8>>` buffer, scoped via
//! [`tracing::subscriber::with_default`] — i.e., the subscriber is the
//! thread-local default for the duration of the supplied closure (or the
//! awaited async future). It is **not** installed globally; parallel
//! `cargo test` threads each get their own subscriber.
//!
//! The captured output is the formatter's standard text representation,
//! which includes both the event message AND its structured fields
//! (`field = value` pairs). Tests assert on substrings of the captured
//! text, so an assertion like `"value = \"verbose\""` exercises the
//! field-renderer path that the production logs would surface to an
//! operator.
use ;
use ;
use MakeWriter;
/// Buffered writer that owns a `Mutex<Vec<u8>>` so multiple `fmt`
/// subscriber writes during a single `with_default` scope accumulate
/// into one buffer. Cloning shares the buffer (it is `Arc`-backed).
/// `MakeWriter` impl that hands the formatter a `BufHandle` writing into
/// our shared buffer. The handle takes the mutex lock for the lifetime of
/// each write call only; the formatter writes one event at a time so
/// the lock is not held across `await` points.
/// One-call writer handle. `Drop` is a no-op; `flush` is a no-op (the
/// underlying `Vec<u8>` does not buffer beyond what the lock-guarded
/// `write_all` already commits).
/// Run a synchronous closure with a thread-local `WARN`-level
/// subscriber installed. Returns the captured output.
///
/// Use this for code paths that synchronously emit warns
/// (e.g., `parse_log_level`, `generate_tools`).
/// Run an async future with a thread-local `WARN`-level subscriber
/// installed for the duration of the future's polling.
///
/// `with_default` returns once the inner closure returns; for an async
/// body we drive the future to completion inside the closure via a
/// shared current-thread runtime so the subscriber is in scope for
/// every `poll`. Tests that need a multi-threaded runtime should
/// install the subscriber inside their own runtime block instead.
pub async
/// Assert that `haystack` contains every substring in `needles`. On
/// failure, prints the full captured output once so the user sees what
/// actually fired.
/// Count occurrences of `needle` in `haystack`. Used to assert that a
/// once-per-event warn (e.g., 64-char tool name) fires exactly once.