disc: emit Pass 1 summary INFO log at sweep exit

Wires the existing PassSummary infrastructure (in read_error.rs as
of a832bad) into the sweep loop's exit path. One INFO log line per
Pass 1 completion gives operators an at-a-glance damage profile
without grepping per-error WARN lines:

  INFO pass1_summary  total_reads_ok=384521 total_errors=5
                      zones_entered=1 jumps_taken=2
                      bytes_good=38_725_644_288 bytes_pending=46_GB
                      copy_elapsed_ms=1751650

Particularly useful for post-mortem analysis when combined with
the per-error structured WARN logs (ms_since_last_error /
ms_since_last_success / sense_family / wedge_transition) shipped
in 0.18.10. Single line tells you the pass shape; preceding WARN
lines tell you the per-error detail.

Pass N (Disc::patch) intentionally NOT covered in this commit —
Pass N has its own retry-budget summary semantics that warrant a
separate design pass. Pass 1 sweep is where wedge incidents
originate, so it gets the diagnostic surface first.

Staged for 0.18.11. 0.18.10 already shipped the per-error WARN
layer; this is the finishing companion log.
This commit is contained in:
MattJackson
2026-05-10 17:21:37 -07:00
parent 06be4defd2
commit d7fb1b35ed
+20
View File
@@ -1901,6 +1901,26 @@ impl Disc {
copy_elapsed_ms = copy_t0.elapsed().as_millis() as u64, copy_elapsed_ms = copy_t0.elapsed().as_millis() as u64,
"Disc::sweep returning" "Disc::sweep returning"
); );
// End-of-pass diagnostic summary (added 2026-05-10 alongside
// the per-error timing instrumentation in read_error.rs).
// One INFO line per sweep that lets a post-mortem analyst tell
// at a glance how much damage the disc + drive saw, without
// grepping through the per-error WARN log. The PassSummary
// counters come from `ReadCtx`'s accumulated state.
let pass_sum = read_ctx.pass_summary();
tracing::info!(
target: "freemkv::disc",
phase = "pass1_summary",
total_reads_ok = pass_sum.total_reads_ok,
total_errors = pass_sum.total_errors,
zones_entered = pass_sum.zones_entered,
jumps_taken = pass_sum.jumps_taken,
bytes_good = stats.bytes_good,
bytes_pending = stats.bytes_pending,
copy_elapsed_ms = copy_t0.elapsed().as_millis() as u64,
"Pass 1 complete"
);
Ok(CopyResult { Ok(CopyResult {
bytes_total: total_bytes, bytes_total: total_bytes,
bytes_good: stats.bytes_good, bytes_good: stats.bytes_good,