metrics.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. package metrics
  2. import (
  3. "runtime"
  4. "time"
  5. )
  6. func (m *Metrics) SetGauge(key []string, val float32) {
  7. if m.HostName != "" && m.EnableHostname {
  8. key = insert(0, m.HostName, key)
  9. }
  10. if m.EnableTypePrefix {
  11. key = insert(0, "gauge", key)
  12. }
  13. if m.ServiceName != "" {
  14. key = insert(0, m.ServiceName, key)
  15. }
  16. m.sink.SetGauge(key, val)
  17. }
  18. func (m *Metrics) EmitKey(key []string, val float32) {
  19. if m.EnableTypePrefix {
  20. key = insert(0, "kv", key)
  21. }
  22. if m.ServiceName != "" {
  23. key = insert(0, m.ServiceName, key)
  24. }
  25. m.sink.EmitKey(key, val)
  26. }
  27. func (m *Metrics) IncrCounter(key []string, val float32) {
  28. if m.EnableTypePrefix {
  29. key = insert(0, "counter", key)
  30. }
  31. if m.ServiceName != "" {
  32. key = insert(0, m.ServiceName, key)
  33. }
  34. m.sink.IncrCounter(key, val)
  35. }
  36. func (m *Metrics) AddSample(key []string, val float32) {
  37. if m.EnableTypePrefix {
  38. key = insert(0, "sample", key)
  39. }
  40. if m.ServiceName != "" {
  41. key = insert(0, m.ServiceName, key)
  42. }
  43. m.sink.AddSample(key, val)
  44. }
  45. func (m *Metrics) MeasureSince(key []string, start time.Time) {
  46. if m.EnableTypePrefix {
  47. key = insert(0, "timer", key)
  48. }
  49. if m.ServiceName != "" {
  50. key = insert(0, m.ServiceName, key)
  51. }
  52. now := time.Now()
  53. elapsed := now.Sub(start)
  54. msec := float32(elapsed.Nanoseconds()) / float32(m.TimerGranularity)
  55. m.sink.AddSample(key, msec)
  56. }
  57. // Periodically collects runtime stats to publish
  58. func (m *Metrics) collectStats() {
  59. for {
  60. time.Sleep(m.ProfileInterval)
  61. m.emitRuntimeStats()
  62. }
  63. }
  64. // Emits various runtime statsitics
  65. func (m *Metrics) emitRuntimeStats() {
  66. // Export number of Goroutines
  67. numRoutines := runtime.NumGoroutine()
  68. m.SetGauge([]string{"runtime", "num_goroutines"}, float32(numRoutines))
  69. // Export memory stats
  70. var stats runtime.MemStats
  71. runtime.ReadMemStats(&stats)
  72. m.SetGauge([]string{"runtime", "alloc_bytes"}, float32(stats.Alloc))
  73. m.SetGauge([]string{"runtime", "sys_bytes"}, float32(stats.Sys))
  74. m.SetGauge([]string{"runtime", "malloc_count"}, float32(stats.Mallocs))
  75. m.SetGauge([]string{"runtime", "free_count"}, float32(stats.Frees))
  76. m.SetGauge([]string{"runtime", "heap_objects"}, float32(stats.HeapObjects))
  77. m.SetGauge([]string{"runtime", "total_gc_pause_ns"}, float32(stats.PauseTotalNs))
  78. m.SetGauge([]string{"runtime", "total_gc_runs"}, float32(stats.NumGC))
  79. // Export info about the last few GC runs
  80. num := stats.NumGC
  81. // Handle wrap around
  82. if num < m.lastNumGC {
  83. m.lastNumGC = 0
  84. }
  85. // Ensure we don't scan more than 256
  86. if num-m.lastNumGC >= 256 {
  87. m.lastNumGC = num - 255
  88. }
  89. for i := m.lastNumGC; i < num; i++ {
  90. pause := stats.PauseNs[i%256]
  91. m.AddSample([]string{"runtime", "gc_pause_ns"}, float32(pause))
  92. }
  93. m.lastNumGC = num
  94. }
  95. // Inserts a string value at an index into the slice
  96. func insert(i int, v string, s []string) []string {
  97. s = append(s, "")
  98. copy(s[i+1:], s[i:])
  99. s[i] = v
  100. return s
  101. }