1
0
mirror of https://github.com/divan/expvarmon.git synced 2025-04-25 13:48:54 +08:00

Code cleanups

This commit is contained in:
Ivan Daniluk 2015-05-01 20:12:23 +03:00
parent 0114f247c8
commit 41c8dfdc9a
7 changed files with 42 additions and 61 deletions

16
data.go
View File

@ -4,7 +4,7 @@ import "time"
// UIData represents data to be passed to UI.
type UIData struct {
Services Services
Services []*Service
Vars []VarName
LastTimestamp time.Time
}
@ -15,17 +15,3 @@ func NewUIData(vars []VarName) *UIData {
Vars: vars,
}
}
// FindService returns existing service by port.
func (d *UIData) FindService(port string) *Service {
if d.Services == nil {
return nil
}
for _, service := range d.Services {
if service.Port == port {
return service
}
}
return nil
}

44
main.go
View File

@ -3,17 +3,17 @@ package main
import (
"flag"
"log"
"sync"
"time"
"github.com/divan/termui"
)
var (
interval = flag.Duration("i", 5*time.Second, "Polling interval")
portsArg = flag.String("ports", "40001,40002,40000,40004,1233,1234,1235", "Ports for accessing services expvars")
defaultVars = flag.String("vars", "memstats.Alloc,memstats.Sys", "Default vars to monitor")
extraVars = flag.String("extravars", "", "Comma-separated extra vars exported with expvars")
dummy = flag.Bool("dummy", false, "Use dummy (console) output")
interval = flag.Duration("i", 5*time.Second, "Polling interval")
portsArg = flag.String("ports", "1234", "Ports for accessing services expvars")
varsArg = flag.String("vars", "memstats.Alloc,memstats.Sys", "Default vars to monitor")
dummy = flag.Bool("dummy", false, "Use dummy (console) output")
)
func main() {
@ -23,7 +23,7 @@ func main() {
log.Fatal("cannot parse ports:", err)
}
vars, err := ParseVars(*defaultVars, *extraVars)
vars, err := ParseVars(*varsArg)
if err != nil {
log.Fatal(err)
}
@ -46,25 +46,11 @@ func main() {
tick := time.NewTicker(*interval)
evtCh := termui.EventCh()
update := func() {
for _, port := range ports {
service := data.FindService(port)
if service == nil {
continue
}
service.Update()
}
data.LastTimestamp = time.Now()
ui.Update(*data)
}
update()
UpdateAll(ui, data)
for {
select {
case <-tick.C:
update()
UpdateAll(ui, data)
case e := <-evtCh:
if e.Type == termui.EventKey && e.Ch == 'q' {
return
@ -76,3 +62,17 @@ func main() {
}
}
}
// UpdateAll collects data from expvars and refreshes UI.
func UpdateAll(ui UI, data *UIData) {
var wg sync.WaitGroup
for _, service := range data.Services {
wg.Add(1)
go service.Update(&wg)
}
wg.Wait()
data.LastTimestamp = time.Now()
ui.Update(*data)
}

View File

@ -5,11 +5,9 @@ import (
"net"
"strconv"
"strings"
"sync"
)
// Services is just a slice of Service.
type Services []*Service
// Service represents constantly updating info about single service.
type Service struct {
Port string
@ -36,7 +34,8 @@ func NewService(port string, vars []VarName) *Service {
}
// Update updates Service info from Expvar variable.
func (s *Service) Update() {
func (s *Service) Update(wg *sync.WaitGroup) {
defer wg.Done()
expvar, err := FetchExpvar(s.Addr())
s.Err = err

View File

@ -74,7 +74,7 @@ func (t *TermUI) Init(data UIData) error {
s := termui.NewSparklines(sparklines...)
s.Height = 2*len(data.Services) + 2
s.HasBorder = true
s.Border.Label = fmt.Sprintf("Sparklines for %s", data.Vars[0])
s.Border.Label = fmt.Sprintf("Monitoring %s", data.Vars[0])
return s
}()

View File

@ -7,22 +7,15 @@ import (
// ParseVars returns parsed and validated slice of strings with
// variables names that will be used for monitoring.
func ParseVars(def, extra string) ([]VarName, error) {
if def == "" && extra == "" {
func ParseVars(vars string) ([]VarName, error) {
if vars == "" {
return nil, errors.New("no vars specified")
}
fields := func(s string) []VarName {
ss := strings.FieldsFunc(s, func(r rune) bool { return r == ',' })
ret := []VarName{}
for _, str := range ss {
ret = append(ret, VarName(str))
}
return ret
}
ss := strings.FieldsFunc(vars, func(r rune) bool { return r == ',' })
var ret []VarName
ret = append(ret, fields(def)...)
ret = append(ret, fields(extra)...)
for _, s := range ss {
ret = append(ret, VarName(s))
}
return ret, nil
}

View File

@ -3,10 +3,9 @@ package main
import "testing"
func TestUtils(t *testing.T) {
def := "memstats.Alloc,memstats.Sys"
extra := ""
str := "memstats.Alloc,memstats.Sys"
vars, err := ParseVars(def, extra)
vars, err := ParseVars(str)
if err != nil {
t.Fatalf("Err not nil: %v", err)
}
@ -15,10 +14,9 @@ func TestUtils(t *testing.T) {
t.Fatalf("vars should contain 2 elements, but has %d", len(vars))
}
def = "memstats.Alloc,memstats.Sys"
extra = "goroutines,counter.A"
str = "memstats.Alloc,memstats.Sys,goroutines,Counter.A"
vars, err = ParseVars(def, extra)
vars, err = ParseVars(str)
if err != nil {
t.Fatalf("Err not nil: %v", err)
}

View File

@ -11,4 +11,9 @@ func TestVarName(t *testing.T) {
if len(slice) != 2 || slice[0] != "memstats" || slice[1] != "Alloc" {
t.Fatalf("ToSlice failed: %v", slice)
}
short := v.Short()
if short != "Alloc" {
t.Fatalf("Expecting Short() to be 'Alloc', but got: %s", short)
}
}