jason 075d766964 first | 3 éve | |
---|---|---|
.. | ||
README.md | 3 éve | |
gauge.go | 3 éve |
This example shows how to use gauge metrics. The program records two gauges.
It periodically runs a function that retrieves the memory stats and updates the above two metrics.
These metrics are then exported using log exporter. Metrics can be viewed at
file:///tmp/metrics.log
once the program is running. Alternatively you could do tail -f /tmp/metrics.log
on Linux/OSx.
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.
$ go get go.opencensus.io/examples/gauges/...
then:
$ go run $(go env GOPATH)/src/go.opencensus.io/examples/gauges/gauge.go
Create a new metric registry for all your metrics. This step is a general step for any kind of metrics and not specific to gauges. Register newly created registry with global producer manager.
r := metric.NewRegistry()
metricproducer.GlobalManager().AddProducer(r)
Create a gauge metric. In this example we have two metrics.
process_heap_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)
}
process_heap_idle_to_alloc_ratio
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)
}
Now, create or get a unique entry (equivalent of a row in a table) for a given set of tags. Since we are not using any tags in this example we only have one entry for each gauge metric.
entry for process_heap_alloc
allocEntry, err = allocGauge.GetEntry()
if err != nil {
log.Fatalf("error getting heap allocation gauge entry, error %v\n", err)
}
entry for process_heap_idle_to_alloc_ratio
ratioEntry, err = ratioGauge.GetEntry()
if err != nil {
log.Fatalf("error getting process heap idle to allocate ratio gauge entry, error %v\n", err)
}
Use Set
or Add
function to update the value of gauge entries. You can call these methods anytime based on your metric and your application. In this example, Set
is called periodically.
allocEntry.Set(int64(getAlloc())) // int64 gauge
ratioEntry.Set(getIdleToAllocRatio()) // float64 gauge
// 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.
allocEntry.Set(int64(getAlloc())) // int64 gauge
ratioEntry.Set(getIdleToAllocRatio()) // float64 gauge
}
}
}
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: time.Duration(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.
r := metric.NewRegistry()
metricproducer.GlobalManager().AddProducer(r)
// Create Int64Gauge to report memory usage of a process.
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)
}
allocEntry, err = allocGauge.GetEntry()
if err != nil {
log.Fatalf("error getting heap allocation gauge entry, error %v\n", err)
}
// Create Float64Gauge to report fractional cpu consumed by Garbage Collection.
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)
}
ratioEntry, err = ratioGauge.GetEntry()
if err != nil {
log.Fatalf("error getting process heap idle to allocate ratio gauge entry, error %v\n", err)
}
// 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()
}