Skip to content

Prettier live terminal output - #1108

Draft
kke wants to merge 8 commits into
mainfrom
tui-improvements
Draft

Prettier live terminal output#1108
kke wants to merge 8 commits into
mainfrom
tui-improvements

Conversation

@kke

@kke kke commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

[POC]

More entertaining output while k0sctl is operating.

tui2

kke added 8 commits July 2, 2026 16:34
Introduce internal/log, a thin printf-style facade over log/slog with
custom trace and fatal levels, and route all logging through it:

- The screen gets a minimal colored handler (level tag, host-prefixed
  messages, trailing attrs) and the log file gets structured logfmt via
  slog.TextHandler. Both hang off a fanout handler, replacing the
  logrus hook pair. Flag semantics (--debug/--trace/silent) unchanged.
- Host-scoped messages now go through h.Log(), which attaches a "host"
  attribute instead of the manual "%s: " message prefix. Attribute
  keys are shared with rig v2, and rig now receives the real base
  logger at Connect instead of going through the slog-logrus bridge,
  so k0sctl and rig records carry a uniform host attribute.
- Retry attempts are logged with structured attempt/error attributes
  through a context-carried logger injected per host in Hosts.Each and
  ParallelEach, and surface at info level after ~15s of retrying so
  long waits are no longer invisible at the default log level.

This is groundwork for separating logging from display; a richer
terminal UI can replace the screen handler without touching call sites.

Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
Add internal/display, a slog-handler-based display layer that separates
what the user sees from what gets logged:

- On a TTY at the default log level, a live inline view (bubbletea)
  shows the current phase with a spinner and elapsed time, per-host
  status rows with live retry counters, and persisted checkmark lines
  with durations for completed phases. Per-host log tails are shown
  automatically when few hosts are active; with more hosts, number keys
  focus a host's log tail and 'l' toggles all tails. Ctrl-C cancels the
  run like a SIGINT, with the same press-again-to-force behavior.
- Non-TTY output, CI, --debug/--trace and --dry-run keep plain line
  output via the existing screen handler.
- Regardless of mode, the display keeps a trace-level ring buffer of
  recent records per host; when the run fails, the recent log tail of
  each failed host is printed before the final error so the "what was
  it doing before it failed" question is answered without opening the
  log file.

The phase manager now emits phase start/completion as log records
carrying phase, duration and error attributes, so displays track
progress through the same slog pipeline as the log file — no separate
event channel, no message parsing. Hosts.Each/ParallelEach log a
host-attributed error record when a host fails a phase, which marks the
host row red and feeds the failure dump.

ANSI colors baked into log messages are gone along with the aurora
dependency; the dry-run report and the rig migration banner use
lipgloss, and everything else is styled by the display at render time.

Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
Cover event parsing and attr routing, ring buffer wrap-around and
failed-host tracking, the plain display's below-level capture and
once-only failure dump on fatal records, and the TTY model's phase
lifecycle, host rows, retry counters, key handling and ctrl-c
interrupt semantics — all without starting a real terminal program.

Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
Driving k0sctl in a real pty surfaced four issues:

- The live view started lazily on the first log record, which arrives
  during config parsing — before the logo and the rig migration banner
  are written. bubbletea had already switched the terminal to raw mode,
  so the banners rendered staircased. The live view now starts on the
  first phase record, which by definition comes after all direct
  startup output; earlier records render as plain lines.
- Host identity was inconsistent before and after connecting: rig tags
  pre-connection records with the connection config string (e.g.
  `ssh.Config{addr:port}`) while established connections use plain
  `addr:port`, splitting each host into two display rows. Host.String()
  now derives addr:port directly from the connection config, and the
  display normalizes the config-wrapper format on rig's own records.
- Failure dump tails printed attribute values verbatim; multi-kilobyte
  multi-line remote command scripts shredded the layout. Values are now
  escaped and truncated to keep one event per line.
- Multi-line content persisted above the live region (phase failure
  errors) garbled the repaint; such lines are now reduced to their
  first line, with full detail still in the final error output.

Also calms the live view down: host row status only tracks info-level
progress messages (debug chatter stays in the log tails), rows with no
status yet show their latest log activity dimmed, and the phase header
gains a step counter (e.g. "Connect to hosts · 2/28") fed by new
step/total attributes on phase start records.

Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
Terminals don't deliver key-release events, so hold-to-peek isn't
portable; press-to-toggle is the equivalent. Space expands every host's
log tail to 10 lines regardless of host count, space or esc collapses
back.

Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
The per-host ring buffers capture records down to trace level, so the
tails mix levels; a T/D/I/W/E/F marker after the timestamp makes them
distinguishable.

Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
Feedback on the tail format: single-letter level markers read poorly
and per-line clocks eat width without adding much while watching live.
Tail lines now carry only the message and attributes, with the whole
line colored by level (red errors, yellow warnings, plain info, faint
debug/trace) in both the live tails and the failure dump. The failure
dump keeps its timestamps — there the timing of events leading up to
the failure is the point.

Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
In the expanded host view, each info-level progress message now appends
to a per-host stack (capped at 5, consecutive duplicates skipped)
instead of replacing the previous one, so the narrative of what a host
has been through builds up visibly. The faint debug feed streams below
the stack and no longer repeats info records; retry counters attach to
the latest step. Collapsed rows (many hosts, tails hidden) keep the
single-line latest-status form.

Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
@kke kke added the enhancement New feature or request label Jul 2, 2026
@jnummelin

Copy link
Copy Markdown
Member

Looks pretty sweet, very docker build like experience

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants