feat(dashboard): live CPU/mem stats stream (spec 16) - #104
Merged
Conversation
Implement the reserved dashboard CPU/mem stats feature (spec 16 §CPU/mem,
§gotchas [Q-DASH-STATS]).
docker:
- Add a read-only ContainerStats method to the Client interface + moby impl:
a one-shot ContainerStats with IncludePreviousSample so CPU% is computed
from the cpu/precpu delta in a single call (no streaming reader held open).
Decoded to a small Stats{CPUPercent, MemUsage, MemLimit, MemPercent}.
- cpuPercent applies the Docker formula (cpuDelta/systemDelta × onlineCPUs),
guarded against counter resets / the first sample. Memory is cache-adjusted
(inactive_file subtracted) to match `docker stats`.
- Mirror ContainerStats in MockClient with a StatsCalls counter + StatsErr.
dashboard:
- dashRow carries HasStats/CPUPercent/MemUsage/MemLimit; the table gains
"CPU% (engine)" and MEM columns (labeled engine per spec: VM-skewed on
Desktop/WSL2), rendered "—" when no sample was taken; detail pane shows both.
- collectDashboardData fetches a bounded, read-only sample per visible
container each poll and folds it into the matching row (keyed by the row's
display name: shared alias / "<project>/<service>").
- --no-stats now actually disables the fetch (zero ContainerStats calls);
stats default ON for the cockpit. The --json snapshot includes a "stats"
section when enabled and available.
Stays strictly read-only: no flock, only SDK reads. Tests: table-driven CPU%
computation + full projection, cache-adjusted memory, the mock feeding the
collector/model, --no-stats skipping the fetch, and the CPU%/MEM columns
rendering via Update/View without a TTY.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Implements the reserved dashboard live CPU/mem stats feature (spec 16 §CPU/mem, §gotchas [Q-DASH-STATS]) — the
--no-statsflag was previously a no-op.internal/dockerContainerStats(ctx, id) (Stats, error)on theClientinterface + moby impl. Uses a one-shotContainerStatswithIncludePreviousSampleso CPU% is computed from the cpu/precpu delta in a single call (no streaming reader held open — the dashboard fetches per visible container each poll).Stats{CPUPercent, MemUsage, MemLimit, MemPercent}.cpuPercentapplies the Docker formula(cpuDelta/systemDelta) × onlineCPUs × 100, guarded against counter resets and the first (no-previous) sample. Memory is cache-adjusted (inactive_file/total_inactive_filesubtracted) to matchdocker stats.MockClientwith aStatsCallscounter +StatsErr.dashboard (
internal/cli)dashRowcarriesHasStats/CPUPercent/MemUsage/MemLimit; the table gains CPU% (engine) and MEM columns (labeled engine per spec — VM-skewed on Desktop/WSL2), rendered—when no sample was taken. Detail pane shows cpu/mem too.collectDashboardDatadoes a bounded, read-only stats fetch per visible container on the existing poll and folds each sample into the matching row (keyed by the row's display name: shared DNS alias /<project>/<service>).--no-statsnow actually disables the fetch (zeroContainerStatscalls); stats default on for the cockpit. The non-TTY--jsonsnapshot includes astatssection when enabled and available.Why
Closes the reserved stats slice of spec 16, making the shared-services graph's live resource usage observable in the cockpit while keeping a cheap opt-out for low-power machines.
Read-only invariant
No flock taken, only SDK reads — consistent with the dashboard's "observe, never mutate" contract.
How tested
CGO_ENABLED=0 go build ./...,CGO_ENABLED=1 go test ./internal/...(+-raceon docker/cli),gofmt -lclean,go vet ./...clean. New table-driven tests:statsFromResponseprojection + cache-adjusted memory.ContainerStatsfeeding the collector and the Bubble Tea model (Update/View render the CPU%/MEM columns without a TTY).--no-statsissues zeroContainerStatscalls.🤖 Generated with Claude Code