Repository navigation
feature: top and stats, and the supervisor history behind them - #4
Merged
Merged
Conversation
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.
Summary
psanswers what is running now. This adds the two questions it cannot answer: what is happening second to second, and what happened while I was not looking.top—pskept live in the terminal: state, health, uptime, restarts, CPU, memory and ports per service, an events pane for what changed between polls, and the selected service's logs. Read-only — it takes no lock and starts or stops nothing, so it runs beside a supervisor.stats— CPU, memory, network and disk per service over a window, summarised from a history the supervisor records.psalso gains a fix along the way:observeno longer gates oncontainer system status, sopsworks over SSH where it previously refused (see Runtime below).What's in it
Resource history —
crates/supervisorhistory.rs:Sample/Readingand the JSONL file at~/Library/Application Support/container-compose/history/<project>.jsonl(CONTAINER_COMPOSE_HISTORY_DIRoverrides it, which is how the tests stay out of a real history). Raw counters only; rates are derived when read, so the file stays a plain record of what the runtime said. Lines older than seven days are pruned at start and hourly.sampler.rs: a thread, becausecontainer stats --no-streamblocks for two seconds and would otherwise sit in front of every restart and probe. It owns its state, shares only the interrupt counter, and reports distinct problems to the loop over a channel once each.run.rs: starts the sampler, and publishesrestarts,last_restart_atandgave_upinto the health cache — history for a reader, deliberately separate from the tick's attempt counter, which still resets after 60 s of healthy uptime.statsA service missing from a sample means the runtime gave no reading — never zero. A restart (a changed container start time) breaks the series rather than producing a negative rate; a gap means no supervisor was running, and the header counts it.
--jsonemits one typed document (samples,first_at,last_at,gaps, and a summary per service). The stack file only orders the rows; without one, services come from the history.topNew
crates/top, split so the logic is testable without a terminal:modelis pure (a poll and the clock in, rows and events out),pollis the worker thread that owns every runtime call, thenappandui. It polls withcontainer listalone rather than the full observation, so it does not gate oncontainer system statuseither. It works without the stack file, from the project's containers, and refuses without a terminal, pointing atps --json.Dependency:
ratatui,default-features = false, features = ["crossterm"]— no calendar/macros/layout-cache features nothing uses, and no separate crossterm pin, sinceratatui::crosstermis the crossterm it was built against.Runtime
observe::statsparsesstats --no-stream --format jsonintoObservedStats;PortSpec::displayrenders thepsform.observetreatscontainer system statusas advisory. It answersunregisteredto any launchd session other than the one that started the runtime — an SSH login, typically — whilelistworks from anywhere. Status now only supplies the actionable "runcontainer system start" message whenlistalso fails.dev/fake-containergrew astatssubcommand;scripts/capture-runtime-fixtures.shnow captures a realcontainer-stats.json, whichruntime/tests/captured.rsparses.Docs
docs/03-cli.mdgainstopandstatssections, including the runtime quirk found on the midnight-lab node: a container whose PID 1 holds an auto-bound route netlink socket (libp2p's interface watcher does) takes port ID 1, which the VM's init needs for its own statistics socket — the runtime then silently omits that container fromcontainer stats.init = truemoves the process off PID 1; apple/containerization#910 fixes the bind itself.docs/01-model.mdcovers the cache's new fields and why the history is not disposable.CLAUDE.mdis a regenerated managed block, not hand-edited.Example output
top(fromdocs/03-cli.md):stats(fromdocs/03-cli.md):No screenshot attached:
topneeds a live supervisor and a terminal, so it was not captured from this branch.Compatibility
#[serde(default)];a_cache_written_before_restart_history_still_readspins that a cache from the previous version still parses.topandstatsare new commands; nothing existing changes shape.statswrites nothing — only a supervisor writes history.Testing
cargo test --workspace: 195 passed, 0 failed, 1 ignored — the ignored one isa_real_stack_round_trips_through_up_exec_run_ps_probe_and_down, which creates real containers.33 new tests:
crates/topsupervisor::historysupervisor::samplercli/tests/up.rsstatsend to end through the real binary against the fake runtimeruntime/tests/captured.rscontainer-stats.jsonparsessupervisor::cachestack::portsPortSpec::display