2015-04-21 17:51:01 +08:00
package main
import (
"flag"
2015-05-04 01:21:19 +08:00
"fmt"
2015-04-21 17:51:01 +08:00
"log"
2015-05-04 01:21:19 +08:00
"os"
2015-05-02 01:12:23 +08:00
"sync"
2015-04-21 17:51:01 +08:00
"time"
2015-05-04 00:46:36 +08:00
"github.com/gizak/termui"
2015-04-21 17:51:01 +08:00
)
var (
2015-05-02 01:12:23 +08:00
interval = flag . Duration ( "i" , 5 * time . Second , "Polling interval" )
2015-05-04 01:21:19 +08:00
portsArg = flag . String ( "ports" , "" , "Ports for accessing services expvars (start-end,port2,port3)" )
2015-05-03 21:52:38 +08:00
varsArg = flag . String ( "vars" , "mem:memstats.Alloc,mem:memstats.Sys,mem:memstats.HeapAlloc,mem:memstats.HeapInuse,memstats.EnableGC,memstats.NumGC,duration:memstats.PauseTotalNs" , "Vars to monitor (comma-separated)" )
2015-05-02 01:12:23 +08:00
dummy = flag . Bool ( "dummy" , false , "Use dummy (console) output" )
2015-05-04 01:21:19 +08:00
self = flag . Bool ( "self" , false , "Monitor itself" )
2015-04-21 17:51:01 +08:00
)
func main ( ) {
2015-05-04 01:21:19 +08:00
flag . Usage = Usage
2015-04-21 17:51:01 +08:00
flag . Parse ( )
2015-05-04 00:58:50 +08:00
2015-05-04 01:21:19 +08:00
// Process ports
ports , _ := ParsePorts ( * portsArg )
if * self {
port , err := StartSelfMonitor ( )
if err == nil {
ports = append ( ports , port )
}
2015-05-04 00:58:50 +08:00
}
2015-05-04 01:21:19 +08:00
if len ( ports ) == 0 {
2015-05-05 04:33:48 +08:00
fmt . Fprintln ( os . Stderr , "no ports specified. Use -ports arg to specify ports of Go apps to monitor" )
Usage ( )
os . Exit ( 1 )
}
if * interval <= 0 {
fmt . Fprintln ( os . Stderr , "update interval is not valid. Valid examples: 5s, 1m, 1h30m" )
2015-05-04 01:21:19 +08:00
Usage ( )
os . Exit ( 1 )
2015-04-21 17:51:01 +08:00
}
2015-05-04 01:21:19 +08:00
// Process vars
2015-05-02 01:12:23 +08:00
vars , err := ParseVars ( * varsArg )
2015-05-01 21:49:19 +08:00
if err != nil {
log . Fatal ( err )
}
2015-05-04 01:21:19 +08:00
// Init UIData
2015-05-01 21:49:19 +08:00
data := NewUIData ( vars )
2015-04-21 17:51:01 +08:00
for _ , port := range ports {
2015-05-01 21:49:19 +08:00
service := NewService ( port , vars )
2015-04-21 17:51:01 +08:00
data . Services = append ( data . Services , service )
}
2015-05-04 01:21:19 +08:00
// Start proper UI
2015-05-03 02:17:51 +08:00
var ui UI
if len ( data . Services ) > 1 {
ui = & TermUI { }
} else {
ui = & TermUISingle { }
}
2015-04-21 17:51:01 +08:00
if * dummy {
ui = & DummyUI { }
}
2015-05-03 02:17:51 +08:00
2015-05-02 00:13:23 +08:00
if err := ui . Init ( * data ) ; err != nil {
log . Fatal ( err )
}
2015-04-21 17:51:01 +08:00
defer ui . Close ( )
tick := time . NewTicker ( * interval )
evtCh := termui . EventCh ( )
2015-05-02 01:12:23 +08:00
UpdateAll ( ui , data )
2015-04-21 17:51:01 +08:00
for {
select {
case <- tick . C :
2015-05-02 01:12:23 +08:00
UpdateAll ( ui , data )
2015-04-21 17:51:01 +08:00
case e := <- evtCh :
if e . Type == termui . EventKey && e . Ch == 'q' {
return
}
2015-04-26 03:46:16 +08:00
if e . Type == termui . EventResize {
2015-05-03 22:54:56 +08:00
ui . Update ( * data )
2015-04-26 03:46:16 +08:00
}
2015-04-21 17:51:01 +08:00
}
}
}
2015-05-02 01:12:23 +08:00
// 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 )
}
2015-05-04 01:21:19 +08:00
// Usage reimplements flag.Usage
func Usage ( ) {
progname := os . Args [ 0 ]
fmt . Fprintf ( os . Stderr , "Usage of %s:\n" , progname )
flag . PrintDefaults ( )
fmt . Fprintf ( os . Stderr , `
Examples :
% s - ports = "80"
% s - ports = "23000-23010,80" - i = 1 m
% s - ports = "80,remoteapp:80" - vars = "mem:memstats.Alloc,duration:Response.Mean,Counter"
% s - ports = "1234-1236" - vars = "Goroutines" - self
For more details and docs , see README : http : //github.com/divan/expvarmon
` , progname , progname , progname , progname )
}