v0.83.0: observability pass — always-DEBUG capture ring + GET /debug/logs + heartbeat log-pull + gap-fill sweep
Capture layer: applog.New returns (logger, Ring) — slog fan-out, stderr at the configured level, ~1000-entry ring fixed at LevelDebug (remote diagnostics without a config flip). GET /debug/logs (token-authed, ?raw=1) + request-level DEBUG middleware. Heartbeat log-pull mirrors the report logtail pattern: envelope log_tail_requested -> next heartbeat carries log_tail (128KB cap, consume-once, failed-push retry proven). Gap-fill sweep over netverify/ netstorage/netmount/signedjobs/selfupdate/disks/controller-swap/desired/loop. Red-proofs: ring-at-emit-level FAILs capture test; drain removed FAILs consume-once; dropped phase line FAILs the S7 log-sequence smoke. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -319,6 +319,7 @@ func (s *Server) handleDiskAssign(w http.ResponseWriter, r *http.Request, vmid i
|
||||
writeErr(w, http.StatusBadRequest, "assign failed: "+err.Error())
|
||||
return
|
||||
}
|
||||
s.logger.Info("local-api: disk assigned (host mount ensured)", "vmid", vmid, "where", req.Where)
|
||||
writeOK(w, map[string]any{"vmid": vmid, "assigned": req.Where})
|
||||
}
|
||||
|
||||
@@ -372,6 +373,8 @@ func (s *Server) handleDiskEject(w http.ResponseWriter, r *http.Request, vmid in
|
||||
return
|
||||
}
|
||||
}
|
||||
s.logger.Info("local-api: drive ejected (bind detached, raw mount kept)",
|
||||
"vmid", vmid, "where", req.Where, "dependent_guests", len(dependents))
|
||||
writeOK(w, map[string]any{"vmid": vmid, "ejected": req.Where, "dependent_guests": dependents})
|
||||
}
|
||||
|
||||
@@ -440,6 +443,8 @@ func (s *Server) handleDiskDecommission(w http.ResponseWriter, r *http.Request,
|
||||
// the RAW /mnt/<name> host mount — that would orphan the drive (a non-removable SATA drive doesn't get
|
||||
// re-plugged), so a one-click re-enroll (H3) could not re-bind it. The soft decommission marker blocks
|
||||
// scheduling; physical removal is the separate "remove from system" action. NEVER format/mkfs here.
|
||||
s.logger.Info("local-api: drive decommissioned (logical retire, data untouched)",
|
||||
"vmid", vmid, "where", req.Where, "durable_id", id, "dependent_guests", len(dependents))
|
||||
writeOK(w, map[string]any{"vmid": vmid, "decommissioned": req.Where, "dependent_guests": dependents})
|
||||
}
|
||||
|
||||
@@ -920,7 +925,10 @@ func (s *Server) ReassertGuestBinds(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for vmid, ids := range s.guestBinds.Guests() {
|
||||
guests := s.guestBinds.Guests()
|
||||
s.logger.Debug("reconcile: guest-bind re-assert pass",
|
||||
"guests", len(guests), "resolved_mounts", len(mountByDurable))
|
||||
for vmid, ids := range guests {
|
||||
for _, id := range ids {
|
||||
// Intent-aware (B2, load-bearing): NEVER bind a drive that is not currently `enrolled` — an
|
||||
// ejected or decommissioned drive must not auto-rebind, even if still host-mounted. A nil
|
||||
|
||||
Reference in New Issue
Block a user