m/node/core/tconsole: implement log scrollback
Change-Id: I7ad6b42e16308366d8d34629c6d8d15ca5f1faf0
Reviewed-on: https://review.monogon.dev/c/monogon/+/4462
Tested-by: Jenkins CI
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/metropolis/node/core/tconsole/tconsole.go b/metropolis/node/core/tconsole/tconsole.go
index 315dca9..db69b01 100644
--- a/metropolis/node/core/tconsole/tconsole.go
+++ b/metropolis/node/core/tconsole/tconsole.go
@@ -21,6 +21,11 @@
"source.monogon.dev/osbase/supervisor"
)
+type page interface {
+ render(*Console)
+ processEvent(*Console, tcell.Event)
+}
+
type Config struct {
Terminal Terminal
LogTree *logtree.LogTree
@@ -46,8 +51,8 @@
// constructed dynamically in Run.
activePage int
- config Config
- reader *logtree.LogReader
+ config Config
+ logReader *logtree.LogReader
}
// New creates a new Console, taking over the TTY at the given path. The given
@@ -57,7 +62,12 @@
// network, roles, curatorConn point to various Metropolis subsystems that are
// used to populate the console data.
func New(config Config, ttyPath string) (*Console, error) {
- reader, err := config.LogTree.Read("", logtree.WithChildren(), logtree.WithStream())
+ reader, err := config.LogTree.Read(
+ "",
+ logtree.WithChildren(),
+ logtree.WithStream(),
+ logtree.WithBacklog(logtree.BacklogAllAvailable),
+ )
if err != nil {
return nil, fmt.Errorf("lt.Read: %w", err)
}
@@ -96,7 +106,7 @@
Quit: make(chan struct{}),
activePage: 0,
config: config,
- reader: reader,
+ logReader: reader,
}, nil
}
@@ -104,7 +114,7 @@
// the Metropolis console always runs.
func (c *Console) Cleanup() {
c.screen.Fini()
- c.reader.Close()
+ c.logReader.Close()
}
func (c *Console) processEvent(ev tcell.Event) {
@@ -145,18 +155,22 @@
supervisor.Signal(ctx, supervisor.SignalHealthy)
// Per-page data.
- pageStatus := pageStatusData{
+ pageStatus := pageStatus{
netAddr: "Waiting...",
roles: "Waiting...",
id: "Waiting...",
fingerprint: "Waiting...",
}
- pageLogs := pageLogsData{}
+ pageLogs := pageLogs{}
+ // Fetch backlog
+ for _, le := range c.logReader.Backlog {
+ pageLogs.appendLine(le)
+ }
// Page references and names.
- pages := []func(){
- func() { c.pageStatus(&pageStatus) },
- func() { c.pageLogs(&pageLogs) },
+ pages := []page{
+ &pageStatus,
+ &pageLogs,
}
pageNames := []string{
"Status", "Logs",
@@ -175,7 +189,8 @@
for {
// Draw active page.
c.activePage %= len(pages)
- pages[c.activePage]()
+ page := pages[c.activePage]
+ page.render(c)
// Draw status bar.
c.statusBar(c.activePage, pageNames...)
@@ -191,6 +206,7 @@
return ctx.Err()
case ev := <-evC:
c.processEvent(ev)
+ page.processEvent(c, ev)
case t := <-netAddrC:
pageStatus.netAddr = t.ExternalAddress.String()
case t := <-rolesC:
@@ -214,8 +230,8 @@
sum := sha256.New()
sum.Write(cert.Raw)
pageStatus.fingerprint = hex.EncodeToString(sum.Sum(nil))
- case le := <-c.reader.Stream:
- pageLogs.appendLine(le.String())
+ case le := <-c.logReader.Stream:
+ pageLogs.appendLine(le)
}
}
}