v1.1.2 — stability pass: time-merged multi-pod logs
Stability release: the multi-pod logs fix everyone felt, plus a full
review pass over the TUI loop, port-forwards and the k8s client layer.
No new keybindings, no behaviour you need to relearn — just fewer
glitches.
Why
Tailing several pods at once (l on a service) used to dump the whole
--tail history of pod A, then the whole history of pod B — the
per-pod reader goroutines raced to the shared channel. History is now
buffered per pod, merged by Kubernetes log timestamps, then live lines
stream through as they arrive.
The rest of the release is a systematic bug hunt: leaks that pinned
local ports across context switches, exec shells landing in the wrong
cluster, duplicate refresh loops, and a dashboard that fetched
megabytes of objects every 5 seconds just to count them.
What
Logs
internal/tui/views/logs/merge.go— two-phase merge: historical tail
is requested withTimestamps=true, parsed, stable-sorted across
pods, then live lines pass through. Single-pod streaming keeps the
old zero-overhead path.
Port-forward
- Service forwards now tunnel to the service's
targetPort(previously
the tunnel went green but hit the service port, not the container port). - Switching contexts tears down live forwards — local ports are freed
instead of leaking SPDY sessions until exit. - The forwards list and the startup restore prompt are scoped to the
active context. - SPDY upgrade gets a 15s
ResponseHeaderTimeout: a stuck API server
fails fast instead of leaking a goroutine; established tunnels are
untouched. - Nil-client guard before the first API call.
Exec / contexts
kubectl execnow passes--contextfor the context selected inside
k4s — previously it silently used the kubeconfig file's
current-context, so a shell could open in the wrong cluster.- The
★marker no longer eats the first letter of the active context
name (ANSI-styled cell vs. table width truncation).
TUI loop
- Generation guard in every auto-refreshing view: returning to a view
no longer stacks duplicate tick/fetch chains. - Busy guard: a new fetch (tick or
r) is skipped while the previous
one is still in flight — on a slow API the 5s tick used to overlap
the 5s timeout. - Async list responses are fenced by namespace: stale replies after a
namespace switch are dropped. Escfrom describe/logs returns to the previous list view instead of
doing nothing.- Footer errors auto-clear after 5s; the cursor now actually blinks in
command/prompt modes. topignores metrics from the wrong mode after togglingn.
Dashboard
- Stats are 4 parallel
Limit: 1count queries using
RemainingItemCountinstead of four full object lists — drastically
less traffic on big clusters. - Per-resource error isolation: an RBAC denial on one resource no
longer blanks the whole dashboard; failed counters are listed as
unavailable: ….
k8s client
- Deployment log/exec resolution supports
matchExpressionsselectors. describetruncation is UTF-8 safe; events are listed with a
server-sideinvolvedObject.namefield selector.
Deps
- Go 1.26.7,
k8s.io/*v0.36.4,charmbracelet/x/ansiv0.11.8.
Coverage
New tests: log-merge unit tests + a cluster-tagged smoke test
(-tags cluster), stats partial/total failure via fake-client
reactors, busy-guard and namespace-fencing tests for list views,
matchExpressions resolution, UTF-8 truncate, SPDY transport cloning,
cmdError TTL. Every fix above was also exercised live against a real
cluster (tmux-driven TUI smoke with the race detector enabled:
multi-pod logs, exec, forward start/stop with port checks, context
switching, key-spam stress — zero races, zero panics).
Quality
go vet✓golangci-lint✓ (0 issues)go test -race✓govulncheck✓
Install
go install github.com/LywwKkA-aD/k4s/cmd/k4s@v1.1.2Website: https://k4scli.io