2015-04-21 12:51:01 +03:00
package main
import (
"flag"
2015-05-03 20:21:19 +03:00
"fmt"
2015-04-21 12:51:01 +03:00
"log"
2015-05-03 20:21:19 +03:00
"os"
2015-05-01 20:12:23 +03:00
"sync"
2015-04-21 12:51:01 +03:00
"time"
2019-01-19 11:40:36 +02:00
"github.com/gizak/termui"
2015-04-21 12:51:01 +03:00
)
var (
2015-05-01 20:12:23 +03:00
interval = flag . Duration ( "i" , 5 * time . Second , "Polling interval" )
2015-07-10 19:44:30 +03:00
urls = flag . String ( "ports" , "" , "Ports/URLs for accessing services expvars (start-end,port2,port3,https://host:port)" )
2015-08-20 21:48:28 -04:00
varsArg = flag . String ( "vars" , "mem:memstats.Alloc,mem:memstats.Sys,mem:memstats.HeapAlloc,mem:memstats.HeapInuse,duration:memstats.PauseNs,duration:memstats.PauseTotalNs" , "Vars to monitor (comma-separated)" )
2015-05-01 20:12:23 +03:00
dummy = flag . Bool ( "dummy" , false , "Use dummy (console) output" )
2015-05-03 20:21:19 +03:00
self = flag . Bool ( "self" , false , "Monitor itself" )
2015-10-15 23:11:48 -04:00
endpoint = flag . String ( "endpoint" , DefaultEndpoint , "URL endpoint for expvars" )
2015-04-21 12:51:01 +03:00
)
func main ( ) {
2015-05-03 20:21:19 +03:00
flag . Usage = Usage
2015-04-21 12:51:01 +03:00
flag . Parse ( )
2015-05-03 19:58:50 +03:00
2015-10-15 23:11:48 -04:00
DefaultEndpoint = * endpoint
2015-07-10 19:29:22 +03:00
// Process ports/urls
ports , _ := ParsePorts ( * urls )
2015-05-03 20:21:19 +03:00
if * self {
port , err := StartSelfMonitor ( )
if err == nil {
ports = append ( ports , port )
}
2015-05-03 19:58:50 +03:00
}
2015-05-03 20:21:19 +03:00
if len ( ports ) == 0 {
2015-05-04 16:33:48 -04: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-03 20:21:19 +03:00
Usage ( )
os . Exit ( 1 )
2015-04-21 12:51:01 +03:00
}
2015-05-03 20:21:19 +03:00
// Process vars
2015-05-01 20:12:23 +03:00
vars , err := ParseVars ( * varsArg )
2015-05-01 16:49:19 +03:00
if err != nil {
log . Fatal ( err )
}
2015-05-03 20:21:19 +03:00
// Init UIData
2015-05-01 16:49:19 +03:00
data := NewUIData ( vars )
2015-04-21 12:51:01 +03:00
for _ , port := range ports {
2015-05-01 16:49:19 +03:00
service := NewService ( port , vars )
2015-04-21 12:51:01 +03:00
data . Services = append ( data . Services , service )
}
2015-05-03 20:21:19 +03:00
// Start proper UI
2015-05-02 21:17:51 +03:00
var ui UI
if len ( data . Services ) > 1 {
ui = & TermUI { }
} else {
ui = & TermUISingle { }
}
2015-04-21 12:51:01 +03:00
if * dummy {
ui = & DummyUI { }
}
2015-05-02 21:17:51 +03:00
2015-05-01 19:13:23 +03:00
if err := ui . Init ( * data ) ; err != nil {
log . Fatal ( err )
}
2015-04-21 12:51:01 +03:00
defer ui . Close ( )
tick := time . NewTicker ( * interval )
2015-05-01 20:12:23 +03:00
UpdateAll ( ui , data )
2015-04-21 12:51:01 +03:00
for {
select {
case <- tick . C :
2015-05-01 20:12:23 +03:00
UpdateAll ( ui , data )
2019-01-19 11:40:36 +02:00
case e := <- termui . PollEvents ( ) :
if e . Type == termui . KeyboardEvent && e . ID == "q" {
2015-04-21 12:51:01 +03:00
return
}
2019-01-19 11:40:36 +02:00
if e . Type == termui . ResizeEvent {
2015-05-03 17:54:56 +03:00
ui . Update ( * data )
2015-04-25 22:46:16 +03:00
}
2015-04-21 12:51:01 +03:00
}
}
}
2015-05-01 20:12:23 +03: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-03 20:21:19 +03: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"
2015-07-10 19:44:30 +03:00
% s - ports = "23000-23010,http://example.com:80-81" - i = 1 m
2015-05-03 20:21:19 +03:00
% 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 )
}