This repository has been archived by the owner on Jul 31, 2023. It is now read-only.
/
gauge.go
214 lines (187 loc) · 5.79 KB
/
gauge.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// Copyright 2019, OpenCensus Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// START entire
// This example shows how to use gauge metrics. The program records two gauges, one to demonstrate
// a gauge with int64 value and the other to demonstrate a gauge with float64 value.
//
// # Metrics
//
// 1. process_heap_alloc (int64): Total bytes used by objects allocated in the heap.
// It includes objects currently used and objects that are freed but not garbage collected.
//
// 2. process_heap_idle_to_alloc_ratio (float64): It is the ratio of Idle bytes to allocated
// bytes in the heap.
//
// It periodically runs a function that retrieves the memory stats and updates the above two
// metrics. These metrics are then exported using log exporter.
// The program lets you choose the amount of memory (in MB) to consume. Choose different values
// and query the metrics to see the change in metrics.
package main
import (
"bufio"
"fmt"
"log"
"os"
"runtime"
"strconv"
"strings"
"time"
"go.opencensus.io/examples/exporter"
"go.opencensus.io/metric"
"go.opencensus.io/metric/metricdata"
"go.opencensus.io/metric/metricproducer"
)
const (
metricsLogFile = "/tmp/metrics.log"
)
var (
mem = &runtime.MemStats{}
)
type memObj struct {
size int
b []byte
}
func newMemObj(size int) *memObj {
n := &memObj{size: size, b: make([]byte, size)}
for i := 0; i < n.size; i++ {
n.b[i] = byte(i)
}
return n
}
var allocEntry *metric.Int64GaugeEntry
var ratioEntry *metric.Float64Entry
var arr []*memObj
func getAlloc() uint64 {
runtime.ReadMemStats(mem)
return mem.HeapAlloc
}
func getIdleToAllocRatio() float64 {
runtime.ReadMemStats(mem)
return float64(mem.HeapIdle) / float64(mem.HeapAlloc)
}
func consumeMem(sizeMB int) {
arr = make([]*memObj, sizeMB)
for i := 0; i < sizeMB; i++ {
arr = append(arr, newMemObj(1000000))
}
}
func doSomeWork(sizeMB int) {
// do some work
consumeMem(sizeMB)
}
func recordMetrics(delay int, done chan int) {
tick := time.NewTicker(time.Duration(delay) * time.Second)
for {
select {
case <-done:
return
case <-tick.C:
// record heap allocation and idle to allocation ratio.
// START record
allocEntry.Set(int64(getAlloc())) // int64 gauge
ratioEntry.Set(getIdleToAllocRatio()) // float64 gauge
// END record
}
}
}
func getInput() int {
reader := bufio.NewReader(os.Stdin)
limit := 50
for {
fmt.Printf("Enter memory (in MB between 1-%d): ", limit)
text, _ := reader.ReadString('\n')
sizeMB, err := strconv.Atoi(strings.TrimSuffix(text, "\n"))
if err == nil {
if sizeMB < 1 || sizeMB > limit {
fmt.Printf("invalid value %s\n", text)
continue
}
fmt.Printf("consuming %dMB\n", sizeMB)
return sizeMB
}
fmt.Printf("error %v\n", err)
}
}
func work() {
fmt.Printf("Program periodically records following gauge metrics.\n")
fmt.Printf(" 1. process_heap_alloc = the heap allocation (used + freed but not garbage collected)\n")
fmt.Printf(" 2. process_idle_to_alloc_ratio = heap idle (unused) /allocation ratio\n")
fmt.Printf("\nGo to file://%s to see the metrics. OR do `tail -f %s` in another terminal\n\n\n",
metricsLogFile, metricsLogFile)
fmt.Printf("Enter memory you would like to allocate in MB to change the value of above metrics.\n")
// Do some work and record gauge metrics.
for {
sizeMB := getInput()
doSomeWork(sizeMB)
fmt.Printf("press CTRL+C to terminate the program\n")
}
}
func main() {
// Using log exporter to export metrics but you can choose any supported exporter.
exporter, err := exporter.NewLogExporter(exporter.Options{
ReportingInterval: 10 * time.Second,
MetricsLogFile: metricsLogFile,
})
if err != nil {
log.Fatalf("Error creating log exporter: %v", err)
}
exporter.Start()
defer exporter.Stop()
defer exporter.Close()
// Create metric registry and register it with global producer manager.
// START reg
r := metric.NewRegistry()
metricproducer.GlobalManager().AddProducer(r)
// END reg
// Create Int64Gauge to report memory usage of a process.
// START alloc
allocGauge, err := r.AddInt64Gauge(
"process_heap_alloc",
metric.WithDescription("Process heap allocation"),
metric.WithUnit(metricdata.UnitBytes))
if err != nil {
log.Fatalf("error creating heap allocation gauge, error %v\n", err)
}
// END alloc
// START entryAlloc
allocEntry, err = allocGauge.GetEntry()
if err != nil {
log.Fatalf("error getting heap allocation gauge entry, error %v\n", err)
}
// END entryAlloc
// Create Float64Gauge to report fractional cpu consumed by Garbage Collection.
// START idle
ratioGauge, err := r.AddFloat64Gauge(
"process_heap_idle_to_alloc_ratio",
metric.WithDescription("process heap idle to allocate ratio"),
metric.WithUnit(metricdata.UnitDimensionless))
if err != nil {
log.Fatalf("error creating process heap idle to allocate ratio gauge, error %v\n", err)
}
// END idle
// START entryIdle
ratioEntry, err = ratioGauge.GetEntry()
if err != nil {
log.Fatalf("error getting process heap idle to allocate ratio gauge entry, error %v\n", err)
}
// END entryIdle
// record gauge metrics every 5 seconds. This example records the gauges periodically. However,
// depending on the application it can be non-periodic and can be recorded at any time.
done := make(chan int)
defer close(done)
go recordMetrics(1, done)
// do your work.
work()
}
// END entire