blob: c1853b173ff3052c918a975a5b8c3ed753a4417b [file] [log] [blame] [view]
# Gauges Example
Table of Contents
=================
- [Summary](#summary)
- [Run the example](#run-the-example)
- [How to use gauges?](#how-to-use-gauges-)
* [Initialize Metric Registry](#initialize-metric-registry)
* [Create gauge metric](#create-gauge-metric)
* [Create gauge entry](#create-gauge-entry)
* [Set gauge values](#set-gauge-values)
* [Complete Example](#complete-example)
## Summary
[top](#Table-of-Contents)
This example shows how to use gauge metrics. The program records two gauges.
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.
1. **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. Metrics can be viewed at
[file:///tmp/metrics.log](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.
## Run the example
```
$ go get go.opencensus.io/examples/gauges/...
```
then:
```
$ go run $(go env GOPATH)/src/go.opencensus.io/examples/gauges/gauge.go
```
## How to use gauges?
### Initialize Metric Registry
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.
[embedmd]:# (gauge.go reg)
```go
r := metric.NewRegistry()
metricproducer.GlobalManager().AddProducer(r)
```
### Create gauge metric
Create a gauge metric. In this example we have two metrics.
**process_heap_alloc**
[embedmd]:# (gauge.go alloc)
```go
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**
[embedmd]:# (gauge.go idle)
```go
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)
}
```
### Create gauge entry
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**
[embedmd]:# (gauge.go entryAlloc)
```go
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**
[embedmd]:# (gauge.go entryIdle)
```go
ratioEntry, err = ratioGauge.GetEntry()
if err != nil {
log.Fatalf("error getting process heap idle to allocate ratio gauge entry, error %v\n", err)
}
```
### Set gauge values
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.
[embedmd]:# (gauge.go record)
```go
allocEntry.Set(int64(getAlloc())) // int64 gauge
ratioEntry.Set(getIdleToAllocRatio()) // float64 gauge
```
### Complete Example
[embedmd]:# (gauge.go entire)
```go
// 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()
}
```