gauge.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. // START entire
  15. // This example shows how to use gauge metrics. The program records two gauges, one to demonstrate
  16. // a gauge with int64 value and the other to demonstrate a gauge with float64 value.
  17. //
  18. // Metrics
  19. //
  20. // 1. process_heap_alloc (int64): Total bytes used by objects allocated in the heap.
  21. // It includes objects currently used and objects that are freed but not garbage collected.
  22. //
  23. // 2. process_heap_idle_to_alloc_ratio (float64): It is the ratio of Idle bytes to allocated
  24. // bytes in the heap.
  25. //
  26. // It periodically runs a function that retrieves the memory stats and updates the above two
  27. // metrics. These metrics are then exported using log exporter.
  28. // The program lets you choose the amount of memory (in MB) to consume. Choose different values
  29. // and query the metrics to see the change in metrics.
  30. package main
  31. import (
  32. "bufio"
  33. "fmt"
  34. "log"
  35. "os"
  36. "runtime"
  37. "strconv"
  38. "strings"
  39. "time"
  40. "go.opencensus.io/examples/exporter"
  41. "go.opencensus.io/metric"
  42. "go.opencensus.io/metric/metricdata"
  43. "go.opencensus.io/metric/metricproducer"
  44. )
  45. const (
  46. metricsLogFile = "/tmp/metrics.log"
  47. )
  48. var (
  49. mem = &runtime.MemStats{}
  50. )
  51. type memObj struct {
  52. size int
  53. b []byte
  54. }
  55. func newMemObj(size int) *memObj {
  56. n := &memObj{size: size, b: make([]byte, size)}
  57. for i := 0; i < n.size; i++ {
  58. n.b[i] = byte(i)
  59. }
  60. return n
  61. }
  62. var allocEntry *metric.Int64GaugeEntry
  63. var ratioEntry *metric.Float64Entry
  64. var arr []*memObj
  65. func getAlloc() uint64 {
  66. runtime.ReadMemStats(mem)
  67. return mem.HeapAlloc
  68. }
  69. func getIdleToAllocRatio() float64 {
  70. runtime.ReadMemStats(mem)
  71. return float64(mem.HeapIdle) / float64(mem.HeapAlloc)
  72. }
  73. func consumeMem(sizeMB int) {
  74. arr = make([]*memObj, sizeMB)
  75. for i := 0; i < sizeMB; i++ {
  76. arr = append(arr, newMemObj(1000000))
  77. }
  78. }
  79. func doSomeWork(sizeMB int) {
  80. // do some work
  81. consumeMem(sizeMB)
  82. }
  83. func recordMetrics(delay int, done chan int) {
  84. tick := time.NewTicker(time.Duration(delay) * time.Second)
  85. for {
  86. select {
  87. case <-done:
  88. return
  89. case <-tick.C:
  90. // record heap allocation and idle to allocation ratio.
  91. // START record
  92. allocEntry.Set(int64(getAlloc())) // int64 gauge
  93. ratioEntry.Set(getIdleToAllocRatio()) // float64 gauge
  94. // END record
  95. }
  96. }
  97. }
  98. func getInput() int {
  99. reader := bufio.NewReader(os.Stdin)
  100. limit := 50
  101. for {
  102. fmt.Printf("Enter memory (in MB between 1-%d): ", limit)
  103. text, _ := reader.ReadString('\n')
  104. sizeMB, err := strconv.Atoi(strings.TrimSuffix(text, "\n"))
  105. if err == nil {
  106. if sizeMB < 1 || sizeMB > limit {
  107. fmt.Printf("invalid value %s\n", text)
  108. continue
  109. }
  110. fmt.Printf("consuming %dMB\n", sizeMB)
  111. return sizeMB
  112. }
  113. fmt.Printf("error %v\n", err)
  114. }
  115. }
  116. func work() {
  117. fmt.Printf("Program periodically records following gauge metrics.\n")
  118. fmt.Printf(" 1. process_heap_alloc = the heap allocation (used + freed but not garbage collected)\n")
  119. fmt.Printf(" 2. process_idle_to_alloc_ratio = heap idle (unused) /allocation ratio\n")
  120. fmt.Printf("\nGo to file://%s to see the metrics. OR do `tail -f %s` in another terminal\n\n\n",
  121. metricsLogFile, metricsLogFile)
  122. fmt.Printf("Enter memory you would like to allocate in MB to change the value of above metrics.\n")
  123. // Do some work and record gauge metrics.
  124. for {
  125. sizeMB := getInput()
  126. doSomeWork(sizeMB)
  127. fmt.Printf("press CTRL+C to terminate the program\n")
  128. }
  129. }
  130. func main() {
  131. // Using log exporter to export metrics but you can choose any supported exporter.
  132. exporter, err := exporter.NewLogExporter(exporter.Options{
  133. ReportingInterval: time.Duration(10 * time.Second),
  134. MetricsLogFile: metricsLogFile,
  135. })
  136. if err != nil {
  137. log.Fatalf("Error creating log exporter: %v", err)
  138. }
  139. exporter.Start()
  140. defer exporter.Stop()
  141. defer exporter.Close()
  142. // Create metric registry and register it with global producer manager.
  143. // START reg
  144. r := metric.NewRegistry()
  145. metricproducer.GlobalManager().AddProducer(r)
  146. // END reg
  147. // Create Int64Gauge to report memory usage of a process.
  148. // START alloc
  149. allocGauge, err := r.AddInt64Gauge(
  150. "process_heap_alloc",
  151. metric.WithDescription("Process heap allocation"),
  152. metric.WithUnit(metricdata.UnitBytes))
  153. if err != nil {
  154. log.Fatalf("error creating heap allocation gauge, error %v\n", err)
  155. }
  156. // END alloc
  157. // START entryAlloc
  158. allocEntry, err = allocGauge.GetEntry()
  159. if err != nil {
  160. log.Fatalf("error getting heap allocation gauge entry, error %v\n", err)
  161. }
  162. // END entryAlloc
  163. // Create Float64Gauge to report fractional cpu consumed by Garbage Collection.
  164. // START idle
  165. ratioGauge, err := r.AddFloat64Gauge(
  166. "process_heap_idle_to_alloc_ratio",
  167. metric.WithDescription("process heap idle to allocate ratio"),
  168. metric.WithUnit(metricdata.UnitDimensionless))
  169. if err != nil {
  170. log.Fatalf("error creating process heap idle to allocate ratio gauge, error %v\n", err)
  171. }
  172. // END idle
  173. // START entryIdle
  174. ratioEntry, err = ratioGauge.GetEntry()
  175. if err != nil {
  176. log.Fatalf("error getting process heap idle to allocate ratio gauge entry, error %v\n", err)
  177. }
  178. // END entryIdle
  179. // record gauge metrics every 5 seconds. This example records the gauges periodically. However,
  180. // depending on the application it can be non-periodic and can be recorded at any time.
  181. done := make(chan int)
  182. defer close(done)
  183. go recordMetrics(1, done)
  184. // do your work.
  185. work()
  186. }
  187. // END entire