...

Source file src/go.opencensus.io/examples/gauges/gauge.go

Documentation: go.opencensus.io/examples/gauges

     1  // Copyright 2019, OpenCensus Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // START entire
    16  
    17  // This example shows how to use gauge metrics. The program records two gauges, one to demonstrate
    18  // a gauge with int64 value and the other to demonstrate a gauge with float64 value.
    19  //
    20  // # Metrics
    21  //
    22  // 1. process_heap_alloc (int64): Total bytes used by objects allocated in the heap.
    23  // It includes objects currently used and objects that are freed but not garbage collected.
    24  //
    25  // 2. process_heap_idle_to_alloc_ratio (float64): It is the ratio of Idle bytes to allocated
    26  // bytes in the heap.
    27  //
    28  // It periodically runs a function that retrieves the memory stats and updates the above two
    29  // metrics. These metrics are then exported using log exporter.
    30  // The program lets you choose the amount of memory (in MB) to consume. Choose different values
    31  // and query the metrics to see the change in metrics.
    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  	// do some work
    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  			// record heap allocation and idle to allocation ratio.
   105  			// START record
   106  			allocEntry.Set(int64(getAlloc()))     // int64 gauge
   107  			ratioEntry.Set(getIdleToAllocRatio()) // float64 gauge
   108  			// END record
   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  	// Do some work and record gauge metrics.
   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  	// Using log exporter to export metrics but you can choose any supported exporter.
   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  	// Create metric registry and register it with global producer manager.
   162  	// START reg
   163  	r := metric.NewRegistry()
   164  	metricproducer.GlobalManager().AddProducer(r)
   165  	// END reg
   166  
   167  	// Create Int64Gauge to report memory usage of a process.
   168  	// START alloc
   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  	// END alloc
   177  
   178  	// START entryAlloc
   179  	allocEntry, err = allocGauge.GetEntry()
   180  	if err != nil {
   181  		log.Fatalf("error getting heap allocation gauge entry, error %v\n", err)
   182  	}
   183  	// END entryAlloc
   184  
   185  	// Create Float64Gauge to report fractional cpu consumed by Garbage Collection.
   186  	// START idle
   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  	// END idle
   195  
   196  	// START entryIdle
   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  	// END entryIdle
   202  
   203  	// record gauge metrics every 5 seconds. This example records the gauges periodically. However,
   204  	// depending on the application it can be non-periodic and can be recorded at any time.
   205  	done := make(chan int)
   206  	defer close(done)
   207  	go recordMetrics(1, done)
   208  
   209  	// do your work.
   210  	work()
   211  
   212  }
   213  
   214  // END entire
   215  

View as plain text