-
Notifications
You must be signed in to change notification settings - Fork 101
/
main.go
123 lines (106 loc) · 2.71 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package main
import (
"flag"
"fmt"
"log"
"os"
"sync"
"time"
"github.com/gizak/termui"
)
var (
interval = flag.Duration("i", 5*time.Second, "Polling interval")
urls = flag.String("ports", "", "Ports/URLs for accessing services expvars (start-end,port2,port3,https://host:port)")
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)")
dummy = flag.Bool("dummy", false, "Use dummy (console) output")
self = flag.Bool("self", false, "Monitor itself")
endpoint = flag.String("endpoint", DefaultEndpoint, "URL endpoint for expvars")
)
func main() {
flag.Usage = Usage
flag.Parse()
DefaultEndpoint = *endpoint
// Process ports/urls
ports, _ := ParsePorts(*urls)
if *self {
port, err := StartSelfMonitor()
if err == nil {
ports = append(ports, port)
}
}
if len(ports) == 0 {
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")
Usage()
os.Exit(1)
}
// Process vars
vars, err := ParseVars(*varsArg)
if err != nil {
log.Fatal(err)
}
// Init UIData
data := NewUIData(vars)
for _, port := range ports {
service := NewService(port, vars)
data.Services = append(data.Services, service)
}
// Start proper UI
var ui UI
if len(data.Services) > 1 {
ui = &TermUI{}
} else {
ui = &TermUISingle{}
}
if *dummy {
ui = &DummyUI{}
}
if err := ui.Init(*data); err != nil {
log.Fatal(err)
}
defer ui.Close()
tick := time.NewTicker(*interval)
UpdateAll(ui, data)
for {
select {
case <-tick.C:
UpdateAll(ui, data)
case e := <-termui.PollEvents():
if e.Type == termui.KeyboardEvent && e.ID == "q" {
return
}
if e.Type == termui.ResizeEvent {
ui.Update(*data)
}
}
}
}
// 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)
}
// 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,http://example.com:80-81" -i=1m
%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)
}