Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / armon / go-metrics / inmem_signal.go
1 package metrics
2
3 import (
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
15 type 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
28 func 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
43 func DefaultInmemSignal(inmem *InmemSink) *InmemSignal {
44         return NewInmemSignal(inmem, DefaultSignal, os.Stderr)
45 }
46
47 // Stop is used to stop the InmemSignal from listening
48 func (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
61 func (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
73 func (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 }