Trace every libvirt call in the KVM provider at V(1), visible in the integration test

A tracingAPI decorator wraps the 17-method libvirt seam and logs one
"libvirt call" line per RPC after it returns: method, the identifiers it
was given, curated results, duration, and on failure the error with its
libvirt code, name and message. At V(2) the same line carries the domain
and volume XML, metadata and addresses; upload bodies are never logged.
The pool applies it in call() when V(1) is enabled and logs connect,
dial-failure and drop events, taking the caller's logger explicitly like
every other helper in the package.

The integration test installs a testr logger at KVM_TEST_LOG_LEVEL
(default 1) so the trace interleaves with t.Log output, which also ends
the "log.SetLogger(...) was never called" warning. Docs gained a Logging
section and the test env var; the KVM provider execution log records run
4 (guest hang at GRUB) that prompted this.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 19:13:51 +00:00
co-authored by Claude Fable 5.1
parent aa8b36e1d0
commit f50d30e58e
13 changed files with 904 additions and 39 deletions
@@ -0,0 +1,57 @@
# Execution: Trace every libvirt call in the KVM provider
Plan: [2026-09-10-0805-kvm-libvirt-tracing.md](../plans/2026-09-10-0805-kvm-libvirt-tracing.md)
- [x] Step 0 — Save plan
- [x] Step 1 — `errors.go`: shared error fields
- [x] Step 2 — `trace.go`: the `tracingAPI` decorator
- [x] Step 3 — `conn.go`: pool logging and wrapping
- [x] Step 4 — Call sites
- [x] Step 5 — Integration test output
- [x] Step 6 — Unit tests
- [ ] Step 7 — Docs, execution log, CHANGELOG (docs and this log done; CHANGELOG waits for the live run)
## Steps 1–6 — Tracer, pool logging, tests, integration wiring
Done as one commit on `feat/kvm-provider`; the plan's assumption that
this belongs on the KVM branch rather than its own feature branch was
accepted at plan approval.
The code follows the plan closely. Things that came out differently
or are worth knowing:
- **Logger names join with `/` in funcr, `.` in zap.** The trace lines
are `kvm/libvirt` in the unit-test capture and in `testr` output, and
`kvm.libvirt` under the operator's zap logger. The docs use the zap
spelling; the unit test asserts the funcr one. First run of the tier
test failed on exactly this.
- **Cancel is not reported as a transport error.** The original `call`
dropped the connection twice on cancellation (once from the abort
closure, once from the "not a libvirt error" branch, harmlessly, since
drop is idempotent). With a log line on each drop that would have
printed both `context cancelled` and `transport error` for one event,
so the transport branch now skips `ctx.Err()`. Covered by
`TestHostPool_call_logsDropReason`.
- **`ConnectListAllDomains` in the fake includes every defined domain**,
so the trace test's fixture (one running managed domain plus one
stopped domain for `DomainCreate` to start) lists two; the V(2)
assertion checks for the `names` key rather than an exact list.
- **`libvirtErrorFields` also feeds `logAPIError`**, which therefore
gains `libvirtCodeName` (e.g. `ErrNoDomain`) next to the numeric code.
- The seam-coverage guard (`reflect` count of `libvirtAPI` methods vs
the test table) is the only thing standing between a future 18th RPC
and a silently untraced call; keep it.
Verification run before committing:
```bash
go build ./... && go vet ./... && go vet -tags=integration ./internal/provider/kvm/
go test -short ./...
go test -race -count=1 -cover ./internal/provider/kvm/ # 90.2 %, up from 88.2
go test -tags=integration -count=1 -run TestKVM ./internal/provider/kvm/ # self-skips without env
```
Worth noting: the live run (`make test-integration-kvm` against beelink)
had not happened when this was written; it is what Step 7 of the KVM
provider plan is waiting on, and its output is the acceptance test for
this feature. Expected shape is in the plan's Verification section.