...
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 package main
33
34 import (
35 "bufio"
36 "fmt"
37 "log"
38 "os"
39 "runtime"
40 "strconv"
41 "strings"
42 "time"
43
44 "go.opencensus.io/examples/exporter"
45 "go.opencensus.io/metric"
46 "go.opencensus.io/metric/metricdata"
47 "go.opencensus.io/metric/metricproducer"
48 )
49
50 const (
51 metricsLogFile = "/tmp/metrics.log"
52 )
53
54 var (
55 mem = &runtime.MemStats{}
56 )
57
58 type memObj struct {
59 size int
60 b []byte
61 }
62
63 func newMemObj(size int) *memObj {
64 n := &memObj{size: size, b: make([]byte, size)}
65 for i := 0; i < n.size; i++ {
66 n.b[i] = byte(i)
67 }
68 return n
69 }
70
71 var allocEntry *metric.Int64GaugeEntry
72 var ratioEntry *metric.Float64Entry
73 var arr []*memObj
74
75 func getAlloc() uint64 {
76 runtime.ReadMemStats(mem)
77 return mem.HeapAlloc
78 }
79
80 func getIdleToAllocRatio() float64 {
81 runtime.ReadMemStats(mem)
82 return float64(mem.HeapIdle) / float64(mem.HeapAlloc)
83 }
84
85 func consumeMem(sizeMB int) {
86 arr = make([]*memObj, sizeMB)
87 for i := 0; i < sizeMB; i++ {
88 arr = append(arr, newMemObj(1000000))
89 }
90 }
91
92 func doSomeWork(sizeMB int) {
93
94 consumeMem(sizeMB)
95 }
96
97 func recordMetrics(delay int, done chan int) {
98 tick := time.NewTicker(time.Duration(delay) * time.Second)
99 for {
100 select {
101 case <-done:
102 return
103 case <-tick.C:
104
105
106 allocEntry.Set(int64(getAlloc()))
107 ratioEntry.Set(getIdleToAllocRatio())
108
109 }
110 }
111 }
112
113 func getInput() int {
114 reader := bufio.NewReader(os.Stdin)
115 limit := 50
116 for {
117 fmt.Printf("Enter memory (in MB between 1-%d): ", limit)
118 text, _ := reader.ReadString('\n')
119 sizeMB, err := strconv.Atoi(strings.TrimSuffix(text, "\n"))
120 if err == nil {
121 if sizeMB < 1 || sizeMB > limit {
122 fmt.Printf("invalid value %s\n", text)
123 continue
124 }
125 fmt.Printf("consuming %dMB\n", sizeMB)
126 return sizeMB
127 }
128 fmt.Printf("error %v\n", err)
129 }
130 }
131
132 func work() {
133 fmt.Printf("Program periodically records following gauge metrics.\n")
134 fmt.Printf(" 1. process_heap_alloc = the heap allocation (used + freed but not garbage collected)\n")
135 fmt.Printf(" 2. process_idle_to_alloc_ratio = heap idle (unused) /allocation ratio\n")
136 fmt.Printf("\nGo to file://%s to see the metrics. OR do `tail -f %s` in another terminal\n\n\n",
137 metricsLogFile, metricsLogFile)
138 fmt.Printf("Enter memory you would like to allocate in MB to change the value of above metrics.\n")
139
140
141 for {
142 sizeMB := getInput()
143 doSomeWork(sizeMB)
144 fmt.Printf("press CTRL+C to terminate the program\n")
145 }
146 }
147
148 func main() {
149
150 exporter, err := exporter.NewLogExporter(exporter.Options{
151 ReportingInterval: 10 * time.Second,
152 MetricsLogFile: metricsLogFile,
153 })
154 if err != nil {
155 log.Fatalf("Error creating log exporter: %v", err)
156 }
157 exporter.Start()
158 defer exporter.Stop()
159 defer exporter.Close()
160
161
162
163 r := metric.NewRegistry()
164 metricproducer.GlobalManager().AddProducer(r)
165
166
167
168
169 allocGauge, err := r.AddInt64Gauge(
170 "process_heap_alloc",
171 metric.WithDescription("Process heap allocation"),
172 metric.WithUnit(metricdata.UnitBytes))
173 if err != nil {
174 log.Fatalf("error creating heap allocation gauge, error %v\n", err)
175 }
176
177
178
179 allocEntry, err = allocGauge.GetEntry()
180 if err != nil {
181 log.Fatalf("error getting heap allocation gauge entry, error %v\n", err)
182 }
183
184
185
186
187 ratioGauge, err := r.AddFloat64Gauge(
188 "process_heap_idle_to_alloc_ratio",
189 metric.WithDescription("process heap idle to allocate ratio"),
190 metric.WithUnit(metricdata.UnitDimensionless))
191 if err != nil {
192 log.Fatalf("error creating process heap idle to allocate ratio gauge, error %v\n", err)
193 }
194
195
196
197 ratioEntry, err = ratioGauge.GetEntry()
198 if err != nil {
199 log.Fatalf("error getting process heap idle to allocate ratio gauge entry, error %v\n", err)
200 }
201
202
203
204
205 done := make(chan int)
206 defer close(done)
207 go recordMetrics(1, done)
208
209
210 work()
211
212 }
213
214
215
View as plain text