mirror of https://github.com/divan/expvarmon.git
Refactored sparklines
This commit is contained in:
parent
58da318423
commit
c921159cac
1
data.go
1
data.go
|
@ -5,6 +5,7 @@ import "time"
|
|||
// Data represents data to be passed to UI.
|
||||
type Data struct {
|
||||
Services Services
|
||||
Total int
|
||||
TotalMemory *Stack
|
||||
LastTimestamp time.Time
|
||||
}
|
||||
|
|
11
main.go
11
main.go
|
@ -5,11 +5,11 @@ import (
|
|||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/gizak/termui"
|
||||
"github.com/divan/termui"
|
||||
)
|
||||
|
||||
var (
|
||||
interval = flag.Duration("i", 1*time.Second, "Polling interval")
|
||||
interval = flag.Duration("i", 10*time.Second, "Polling interval")
|
||||
portsArg = flag.String("ports", "40001,40002,40000,40004,1233,1234,1235", "Ports for accessing services expvars")
|
||||
dummy = flag.Bool("dummy", false, "Use dummy (console) output")
|
||||
)
|
||||
|
@ -27,12 +27,13 @@ func main() {
|
|||
service := NewService(port)
|
||||
data.Services = append(data.Services, service)
|
||||
}
|
||||
data.Total = len(data.Services)
|
||||
|
||||
var ui UI = &TermUI{}
|
||||
if *dummy {
|
||||
ui = &DummyUI{}
|
||||
}
|
||||
ui.Init()
|
||||
ui.Init(data)
|
||||
defer ui.Close()
|
||||
|
||||
tick := time.NewTicker(*interval)
|
||||
|
@ -61,6 +62,10 @@ func main() {
|
|||
if e.Type == termui.EventKey && e.Ch == 'q' {
|
||||
return
|
||||
}
|
||||
if e.Type == termui.EventResize {
|
||||
termui.Body.Width = termui.TermWidth()
|
||||
termui.Body.Align()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
23
service.go
23
service.go
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pyk/byten"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -60,7 +61,7 @@ func (s *Service) Update() {
|
|||
// Put metrics data
|
||||
mem, ok := s.Values["memory"]
|
||||
if !ok {
|
||||
s.Values["memory"] = NewStack(40)
|
||||
s.Values["memory"] = NewStack(1200)
|
||||
mem = s.Values["memory"]
|
||||
}
|
||||
mem.Push(int(s.MemStats.Alloc) / 1024)
|
||||
|
@ -72,3 +73,23 @@ func (s *Service) Update() {
|
|||
func (s Service) Addr() string {
|
||||
return fmt.Sprintf("http://localhost:%s%s", s.Port, ExpvarsUrl)
|
||||
}
|
||||
|
||||
// StatusLine returns status line for services with it's name and status.
|
||||
func (s Service) StatusLine() string {
|
||||
if s.Err != nil {
|
||||
return fmt.Sprintf("[ERR] %s failed", s.Name)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[R] %s", s.Name)
|
||||
}
|
||||
|
||||
// Meminfo returns memory info string for the given service.
|
||||
func (s Service) Meminfo() string {
|
||||
if s.Err != nil || s.MemStats == nil {
|
||||
return "N/A"
|
||||
}
|
||||
|
||||
allocated := byten.Size(int64(s.MemStats.Alloc))
|
||||
sys := byten.Size(int64(s.MemStats.Sys))
|
||||
return fmt.Sprintf("Alloc/Sys: %s / %s", allocated, sys)
|
||||
}
|
||||
|
|
2
ui.go
2
ui.go
|
@ -2,7 +2,7 @@ package main
|
|||
|
||||
// UI represents UI module
|
||||
type UI interface {
|
||||
Init()
|
||||
Init(Data)
|
||||
Close()
|
||||
Update(Data)
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
// DummyUI is an simple console UI mockup, for testing purposes.
|
||||
type DummyUI struct{}
|
||||
|
||||
func (u *DummyUI) Init() {}
|
||||
func (u *DummyUI) Close() {}
|
||||
func (u *DummyUI) Update(data Data) {
|
||||
func (*DummyUI) Init(Data) {}
|
||||
func (*DummyUI) Close() {}
|
||||
func (*DummyUI) Update(data Data) {
|
||||
if data.Services == nil {
|
||||
return
|
||||
}
|
||||
|
|
214
ui_termui.go
214
ui_termui.go
|
@ -4,116 +4,156 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/gizak/termui"
|
||||
"github.com/pyk/byten"
|
||||
"github.com/divan/termui"
|
||||
)
|
||||
|
||||
// TermUI is a termUI implementation of UI interface.
|
||||
type TermUI struct {
|
||||
Title *termui.Par
|
||||
Status *termui.Par
|
||||
Services *termui.List
|
||||
Meminfo *termui.List
|
||||
MemSparkline *termui.Sparklines
|
||||
}
|
||||
|
||||
func (t *TermUI) Init() {
|
||||
func (t *TermUI) Init(data Data) {
|
||||
err := termui.Init()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
termui.UseTheme("helloworld")
|
||||
|
||||
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 {
|
||||
l := termui.NewList()
|
||||
l.ItemFgColor = termui.ColorGreen
|
||||
l.Border.Label = "Services"
|
||||
return l
|
||||
}()
|
||||
t.Meminfo = func() *termui.List {
|
||||
l := termui.NewList()
|
||||
l.ItemFgColor = termui.ColorBlue | termui.AttrBold
|
||||
l.Border.Label = "Memory Usage"
|
||||
return l
|
||||
}()
|
||||
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...)
|
||||
s.Height = 2*data.Total + 2
|
||||
s.HasBorder = true
|
||||
s.Border.Label = "Memory Track"
|
||||
return s
|
||||
}()
|
||||
|
||||
termui.Body.AddRows(
|
||||
termui.NewRow(
|
||||
termui.NewCol(6, 0, t.Title),
|
||||
termui.NewCol(6, 0, t.Status)),
|
||||
termui.NewRow(
|
||||
termui.NewCol(3, 0, t.Services),
|
||||
termui.NewCol(9, 0, t.Meminfo)),
|
||||
termui.NewRow(
|
||||
termui.NewCol(12, 0, t.MemSparkline)),
|
||||
)
|
||||
|
||||
termui.Body.Align()
|
||||
}
|
||||
|
||||
func (t *TermUI) Update(data Data) {
|
||||
total := len(data.Services)
|
||||
text := fmt.Sprintf("monitoring %d services, press q to quit", total)
|
||||
t.Title.Text = fmt.Sprintf("monitoring %d services, press q to quit", data.Total)
|
||||
t.Status.Text = fmt.Sprintf("Last update: %v", data.LastTimestamp.Format("15:04:05 02/Jan/06"))
|
||||
|
||||
p := termui.NewPar(text)
|
||||
p.Height = 3
|
||||
p.Width = termui.TermWidth() / 2
|
||||
p.TextFgColor = termui.ColorWhite
|
||||
p.Border.Label = "Services Monitor"
|
||||
p.Border.FgColor = termui.ColorCyan
|
||||
|
||||
text1 := fmt.Sprintf("Last update: %v", data.LastTimestamp.Format("15:04:05 02/Jan/06"))
|
||||
p1 := termui.NewPar(text1)
|
||||
p1.Height = 3
|
||||
p1.X = p.X + p.Width
|
||||
p1.Width = termui.TermWidth() - p1.X
|
||||
p1.TextFgColor = termui.ColorWhite
|
||||
p1.Border.Label = "Status"
|
||||
p1.Border.FgColor = termui.ColorCyan
|
||||
|
||||
names := termui.NewList()
|
||||
names.Y = 3
|
||||
names.ItemFgColor = termui.ColorYellow
|
||||
names.Border.Label = "Services"
|
||||
names.Height = total + 2
|
||||
names.Width = termui.TermWidth() / 4
|
||||
|
||||
meminfo := termui.NewList()
|
||||
meminfo.Y = 3
|
||||
meminfo.X = names.X + names.Width
|
||||
meminfo.Width = meminfo.X + termui.TermWidth()/3
|
||||
meminfo.Height = total + 2
|
||||
meminfo.ItemFgColor = termui.ColorBlue
|
||||
meminfo.Border.Label = "Memory Usage (Alloc/HeapAlloc)"
|
||||
|
||||
goroutines := termui.NewList()
|
||||
goroutines.Y = 3
|
||||
goroutines.X = meminfo.X + meminfo.Width
|
||||
goroutines.Width = termui.TermWidth() - goroutines.X
|
||||
goroutines.Height = total + 2
|
||||
goroutines.ItemFgColor = termui.ColorGreen
|
||||
goroutines.Border.Label = "Goroutines"
|
||||
|
||||
var totalAlloc int64
|
||||
var services []string
|
||||
var meminfos []string
|
||||
for _, service := range data.Services {
|
||||
if service.Err != nil {
|
||||
names.Items = append(names.Items, fmt.Sprintf("[ERR] %s failed", service.Name))
|
||||
meminfo.Items = append(meminfo.Items, "N/A")
|
||||
goroutines.Items = append(goroutines.Items, "N/A")
|
||||
continue
|
||||
services = append(services, service.StatusLine())
|
||||
meminfos = append(meminfos, service.Meminfo())
|
||||
}
|
||||
t.Services.Items = services
|
||||
t.Services.Height = data.Total + 2
|
||||
|
||||
t.Meminfo.Items = meminfos
|
||||
t.Meminfo.Height = data.Total + 2
|
||||
|
||||
// Sparklines
|
||||
for i, service := range data.Services {
|
||||
t.MemSparkline.Lines[i].Title = service.Name
|
||||
t.MemSparkline.Lines[i].Data = service.Values["memory"].Values
|
||||
}
|
||||
|
||||
termui.Body.Width = termui.TermWidth()
|
||||
termui.Body.Align()
|
||||
termui.Render(termui.Body)
|
||||
/*
|
||||
|
||||
goroutines := termui.NewList()
|
||||
goroutines.Y = 3
|
||||
goroutines.X = meminfo.X + meminfo.Width
|
||||
goroutines.Width = termui.TermWidth() - goroutines.X
|
||||
goroutines.Height = total + 2
|
||||
goroutines.ItemFgColor = termui.ColorGreen
|
||||
goroutines.Border.Label = "Goroutines"
|
||||
|
||||
var totalAlloc int64
|
||||
for _, service := range data.Services {
|
||||
if service.Err != nil {
|
||||
names.Items = append(names.Items, fmt.Sprintf("[ERR] %s failed", service.Name))
|
||||
meminfo.Items = append(meminfo.Items, "N/A")
|
||||
goroutines.Items = append(goroutines.Items, "N/A")
|
||||
continue
|
||||
}
|
||||
alloc := byten.Size(int64(service.MemStats.Alloc))
|
||||
heap := byten.Size(int64(service.MemStats.HeapAlloc))
|
||||
totalAlloc += int64(service.MemStats.Alloc)
|
||||
|
||||
name := fmt.Sprintf("[R] %s", service.Name)
|
||||
meminfos := fmt.Sprintf("%s/%s", alloc, heap)
|
||||
|
||||
names.Items = append(names.Items, name)
|
||||
meminfo.Items = append(meminfo.Items, meminfos)
|
||||
}
|
||||
alloc := byten.Size(int64(service.MemStats.Alloc))
|
||||
heap := byten.Size(int64(service.MemStats.HeapAlloc))
|
||||
totalAlloc += int64(service.MemStats.Alloc)
|
||||
|
||||
name := fmt.Sprintf("[R] %s", service.Name)
|
||||
meminfos := fmt.Sprintf("%s/%s", alloc, heap)
|
||||
|
||||
names.Items = append(names.Items, name)
|
||||
meminfo.Items = append(meminfo.Items, meminfos)
|
||||
}
|
||||
data.TotalMemory.Push(int(totalAlloc / 1024))
|
||||
|
||||
var sparklines []termui.Sparkline
|
||||
for _, service := range data.Services {
|
||||
spl := termui.NewSparkline()
|
||||
spl.Data = service.Values["memory"].Values
|
||||
spl.Height = 1
|
||||
spl.LineColor = termui.ColorGreen
|
||||
sparklines = append(sparklines, spl)
|
||||
}
|
||||
spl3 := termui.NewSparkline()
|
||||
spl3.Data = data.TotalMemory.Values
|
||||
spl3.Height = termui.TermHeight() - 3 - (total + 2) - 3
|
||||
spl3.LineColor = termui.ColorYellow
|
||||
|
||||
spls := termui.NewSparklines(sparklines...)
|
||||
spls.Height = len(data.Services) + 1
|
||||
spls.Width = 40
|
||||
spls.Y = 3
|
||||
spls.X = meminfo.X + meminfo.Width - spls.Width - 1
|
||||
spls.HasBorder = false
|
||||
spls2 := termui.NewSparklines(spl3)
|
||||
spls2.Y = 3 + (total + 2)
|
||||
spls2.Height = termui.TermHeight() - spls2.Y
|
||||
spls2.Width = termui.TermWidth()
|
||||
spls2.Border.FgColor = termui.ColorCyan
|
||||
spls2.Border.Label = fmt.Sprintf("Total Memory Usage: %s", byten.Size(totalAlloc))
|
||||
|
||||
data.TotalMemory.Push(int(totalAlloc / 1024))
|
||||
|
||||
spl3 := termui.NewSparkline()
|
||||
spl3.Data = data.TotalMemory.Values
|
||||
spl3.Height = termui.TermHeight() - 3 - (total + 2) - 3
|
||||
spl3.LineColor = termui.ColorYellow
|
||||
|
||||
spls2 := termui.NewSparklines(spl3)
|
||||
spls2.Y = 3 + (total + 2)
|
||||
spls2.Height = termui.TermHeight() - spls2.Y
|
||||
spls2.Width = termui.TermWidth()
|
||||
spls2.Border.FgColor = termui.ColorCyan
|
||||
spls2.Border.Label = fmt.Sprintf("Total Memory Usage: %s", byten.Size(totalAlloc))
|
||||
|
||||
termui.Render(p, p1, names, meminfo, goroutines, spls2, spls)
|
||||
termui.Render(p, p1, names, meminfo, goroutines, spls2, spls)
|
||||
*/
|
||||
}
|
||||
|
||||
func (t *TermUI) Close() {
|
||||
|
|
Loading…
Reference in New Issue