2015-04-21 17:51:01 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2015-04-21 21:33:04 +08:00
|
|
|
|
2015-04-26 03:46:16 +08:00
|
|
|
"github.com/divan/termui"
|
2015-04-21 17:51:01 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
// TermUI is a termUI implementation of UI interface.
|
|
|
|
type TermUI struct {
|
2015-04-26 03:46:16 +08:00
|
|
|
Title *termui.Par
|
|
|
|
Status *termui.Par
|
|
|
|
Services *termui.List
|
2015-05-01 23:48:34 +08:00
|
|
|
Lists map[VarName]*termui.List
|
2015-04-26 03:46:16 +08:00
|
|
|
MemSparkline *termui.Sparklines
|
2015-04-21 17:51:01 +08:00
|
|
|
}
|
|
|
|
|
2015-05-01 23:48:34 +08:00
|
|
|
// Init creates widgets, sets sizes and labels.
|
|
|
|
func (t *TermUI) Init(data UIData) error {
|
2015-04-21 17:51:01 +08:00
|
|
|
err := termui.Init()
|
|
|
|
if err != nil {
|
2015-05-01 23:48:34 +08:00
|
|
|
return err
|
2015-04-21 17:51:01 +08:00
|
|
|
}
|
|
|
|
|
2015-05-01 23:48:34 +08:00
|
|
|
t.Lists = make(map[VarName]*termui.List)
|
2015-05-01 21:49:19 +08:00
|
|
|
|
2015-04-21 17:51:01 +08:00
|
|
|
termui.UseTheme("helloworld")
|
2015-04-26 03:46:16 +08:00
|
|
|
|
|
|
|
t.Title = func() *termui.Par {
|
|
|
|
p := termui.NewPar("")
|
|
|
|
p.Height = 3
|
|
|
|
p.TextFgColor = termui.ColorWhite
|
|
|
|
p.Border.Label = "Services Monitor"
|
|
|
|
p.Border.FgColor = termui.ColorCyan
|
|
|
|
return p
|
|
|
|
}()
|
|
|
|
t.Status = func() *termui.Par {
|
|
|
|
p := termui.NewPar("")
|
|
|
|
p.Height = 3
|
|
|
|
p.TextFgColor = termui.ColorWhite
|
|
|
|
p.Border.Label = "Status"
|
|
|
|
p.Border.FgColor = termui.ColorCyan
|
|
|
|
return p
|
|
|
|
}()
|
|
|
|
t.Services = func() *termui.List {
|
2015-05-01 21:49:19 +08:00
|
|
|
list := termui.NewList()
|
|
|
|
list.ItemFgColor = termui.ColorGreen
|
|
|
|
list.Border.Label = "Services"
|
|
|
|
list.Height = len(data.Services) + 2
|
|
|
|
return list
|
2015-04-26 03:46:16 +08:00
|
|
|
}()
|
2015-05-01 21:49:19 +08:00
|
|
|
|
|
|
|
for _, name := range data.Vars {
|
2015-05-01 23:48:34 +08:00
|
|
|
_, ok := t.Lists[name]
|
2015-05-01 21:49:19 +08:00
|
|
|
if !ok {
|
|
|
|
list := termui.NewList()
|
|
|
|
list.ItemFgColor = termui.ColorBlue | termui.AttrBold
|
2015-05-01 23:48:34 +08:00
|
|
|
list.Border.Label = name.Short()
|
2015-05-01 21:49:19 +08:00
|
|
|
list.Height = len(data.Services) + 2
|
2015-05-01 23:48:34 +08:00
|
|
|
t.Lists[name] = list
|
2015-05-01 21:49:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-26 03:46:16 +08:00
|
|
|
t.MemSparkline = func() *termui.Sparklines {
|
|
|
|
var sparklines []termui.Sparkline
|
|
|
|
for _, service := range data.Services {
|
|
|
|
spl := termui.NewSparkline()
|
|
|
|
spl.Height = 1
|
|
|
|
spl.LineColor = termui.ColorGreen
|
|
|
|
spl.Title = service.Name
|
|
|
|
sparklines = append(sparklines, spl)
|
|
|
|
}
|
|
|
|
|
|
|
|
s := termui.NewSparklines(sparklines...)
|
2015-05-01 21:49:19 +08:00
|
|
|
s.Height = 2*len(data.Services) + 2
|
2015-04-26 03:46:16 +08:00
|
|
|
s.HasBorder = true
|
2015-05-02 01:12:23 +08:00
|
|
|
s.Border.Label = fmt.Sprintf("Monitoring %s", data.Vars[0])
|
2015-04-26 03:46:16 +08:00
|
|
|
return s
|
|
|
|
}()
|
|
|
|
|
2015-05-01 23:48:34 +08:00
|
|
|
cellW, firstW := calculateCellWidth(len(data.Vars) + 1)
|
|
|
|
col := termui.NewCol(firstW, 0, t.Services)
|
|
|
|
cols := []*termui.Row{col}
|
|
|
|
for _, name := range data.Vars {
|
|
|
|
cols = append(cols, termui.NewCol(cellW, 0, t.Lists[name]))
|
|
|
|
}
|
|
|
|
listsRow := termui.NewRow(cols...)
|
|
|
|
|
2015-04-26 03:46:16 +08:00
|
|
|
termui.Body.AddRows(
|
|
|
|
termui.NewRow(
|
|
|
|
termui.NewCol(6, 0, t.Title),
|
|
|
|
termui.NewCol(6, 0, t.Status)),
|
2015-05-01 23:48:34 +08:00
|
|
|
listsRow,
|
|
|
|
termui.NewRow(termui.NewCol(12, 0, t.MemSparkline)),
|
2015-04-26 03:46:16 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
termui.Body.Align()
|
2015-05-01 23:48:34 +08:00
|
|
|
|
|
|
|
return nil
|
2015-04-21 17:51:01 +08:00
|
|
|
}
|
|
|
|
|
2015-05-02 00:13:23 +08:00
|
|
|
// Update updates UI widgets from UIData.
|
2015-05-01 19:37:28 +08:00
|
|
|
func (t *TermUI) Update(data UIData) {
|
2015-05-02 00:26:28 +08:00
|
|
|
t.Title.Text = fmt.Sprintf("monitoring %d services, press q to quit", len(data.Services))
|
2015-04-26 03:46:16 +08:00
|
|
|
t.Status.Text = fmt.Sprintf("Last update: %v", data.LastTimestamp.Format("15:04:05 02/Jan/06"))
|
|
|
|
|
|
|
|
var services []string
|
2015-04-21 17:51:01 +08:00
|
|
|
for _, service := range data.Services {
|
2015-04-26 03:46:16 +08:00
|
|
|
services = append(services, service.StatusLine())
|
|
|
|
}
|
|
|
|
t.Services.Items = services
|
2015-04-21 21:33:04 +08:00
|
|
|
|
2015-05-01 21:49:19 +08:00
|
|
|
for _, name := range data.Vars {
|
|
|
|
var lines []string
|
|
|
|
for _, service := range data.Services {
|
|
|
|
lines = append(lines, service.Value(name))
|
|
|
|
}
|
2015-05-01 23:48:34 +08:00
|
|
|
t.Lists[name].Items = lines
|
2015-05-01 21:49:19 +08:00
|
|
|
}
|
2015-04-21 21:33:04 +08:00
|
|
|
|
2015-04-26 03:46:16 +08:00
|
|
|
// Sparklines
|
|
|
|
for i, service := range data.Services {
|
|
|
|
t.MemSparkline.Lines[i].Title = service.Name
|
2015-05-02 00:36:11 +08:00
|
|
|
t.MemSparkline.Lines[i].Data = service.Values(data.Vars[0])
|
2015-04-21 17:51:01 +08:00
|
|
|
}
|
2015-04-25 21:29:19 +08:00
|
|
|
|
2015-04-26 03:46:16 +08:00
|
|
|
termui.Body.Width = termui.TermWidth()
|
|
|
|
termui.Body.Align()
|
|
|
|
termui.Render(termui.Body)
|
2015-04-21 17:51:01 +08:00
|
|
|
}
|
|
|
|
|
2015-05-01 23:48:34 +08:00
|
|
|
// Close shuts down UI module.
|
2015-04-21 17:51:01 +08:00
|
|
|
func (t *TermUI) Close() {
|
|
|
|
termui.Close()
|
|
|
|
}
|
2015-05-01 23:48:34 +08:00
|
|
|
|
|
|
|
// GridSz defines grid size used in TermUI
|
|
|
|
const GridSz = 12
|
|
|
|
|
|
|
|
// calculateCellWidth does some heuristics to calculate optimal cells width
|
|
|
|
// for all cells, and adjust first width (with service names) if needed.
|
|
|
|
func calculateCellWidth(num int) (cellW int, firstW int) {
|
|
|
|
cellW = GridSz / num
|
|
|
|
firstW = cellW + (GridSz - (num * cellW))
|
|
|
|
return
|
|
|
|
}
|