blob: 95d08ee10f0b1a989ed05ccda3a75aacab55c3c7 [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001package metrics
2
3import (
4 "bytes"
5 "fmt"
6 "io"
7 "os"
8 "os/signal"
9 "sync"
10 "syscall"
11)
12
13// InmemSignal is used to listen for a given signal, and when received,
14// to dump the current metrics from the InmemSink to an io.Writer
15type InmemSignal struct {
16 signal syscall.Signal
17 inm *InmemSink
18 w io.Writer
19 sigCh chan os.Signal
20
21 stop bool
22 stopCh chan struct{}
23 stopLock sync.Mutex
24}
25
26// NewInmemSignal creates a new InmemSignal which listens for a given signal,
27// and dumps the current metrics out to a writer
28func NewInmemSignal(inmem *InmemSink, sig syscall.Signal, w io.Writer) *InmemSignal {
29 i := &InmemSignal{
30 signal: sig,
31 inm: inmem,
32 w: w,
33 sigCh: make(chan os.Signal, 1),
34 stopCh: make(chan struct{}),
35 }
36 signal.Notify(i.sigCh, sig)
37 go i.run()
38 return i
39}
40
41// DefaultInmemSignal returns a new InmemSignal that responds to SIGUSR1
42// and writes output to stderr. Windows uses SIGBREAK
43func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
44 return NewInmemSignal(inmem, DefaultSignal, os.Stderr)
45}
46
47// Stop is used to stop the InmemSignal from listening
48func (i *InmemSignal) Stop() {
49 i.stopLock.Lock()
50 defer i.stopLock.Unlock()
51
52 if i.stop {
53 return
54 }
55 i.stop = true
56 close(i.stopCh)
57 signal.Stop(i.sigCh)
58}
59
60// run is a long running routine that handles signals
61func (i *InmemSignal) run() {
62 for {
63 select {
64 case <-i.sigCh:
65 i.dumpStats()
66 case <-i.stopCh:
67 return
68 }
69 }
70}
71
72// dumpStats is used to dump the data to output writer
73func (i *InmemSignal) dumpStats() {
74 buf := bytes.NewBuffer(nil)
75
76 data := i.inm.Data()
77 // Skip the last period which is still being aggregated
78 for i := 0; i < len(data)-1; i++ {
79 intv := data[i]
80 intv.RLock()
81 for name, val := range intv.Gauges {
82 fmt.Fprintf(buf, "[%v][G] '%s': %0.3f\n", intv.Interval, name, val)
83 }
84 for name, vals := range intv.Points {
85 for _, val := range vals {
86 fmt.Fprintf(buf, "[%v][P] '%s': %0.3f\n", intv.Interval, name, val)
87 }
88 }
89 for name, agg := range intv.Counters {
90 fmt.Fprintf(buf, "[%v][C] '%s': %s\n", intv.Interval, name, agg)
91 }
92 for name, agg := range intv.Samples {
93 fmt.Fprintf(buf, "[%v][S] '%s': %s\n", intv.Interval, name, agg)
94 }
95 intv.RUnlock()
96 }
97
98 // Write out the bytes
99 i.w.Write(buf.Bytes())
100}