metrics.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. package statsd
  2. import (
  3. "math"
  4. "sync"
  5. "sync/atomic"
  6. )
  7. /*
  8. Those are metrics type that can be aggregated on the client side:
  9. - Gauge
  10. - Count
  11. - Set
  12. */
  13. type countMetric struct {
  14. value int64
  15. name string
  16. tags []string
  17. }
  18. func newCountMetric(name string, value int64, tags []string) *countMetric {
  19. return &countMetric{
  20. value: value,
  21. name: name,
  22. tags: tags,
  23. }
  24. }
  25. func (c *countMetric) sample(v int64) {
  26. atomic.AddInt64(&c.value, v)
  27. }
  28. func (c *countMetric) flushUnsafe() metric {
  29. return metric{
  30. metricType: count,
  31. name: c.name,
  32. tags: c.tags,
  33. rate: 1,
  34. ivalue: c.value,
  35. }
  36. }
  37. // Gauge
  38. type gaugeMetric struct {
  39. value uint64
  40. name string
  41. tags []string
  42. }
  43. func newGaugeMetric(name string, value float64, tags []string) *gaugeMetric {
  44. return &gaugeMetric{
  45. value: math.Float64bits(value),
  46. name: name,
  47. tags: tags,
  48. }
  49. }
  50. func (g *gaugeMetric) sample(v float64) {
  51. atomic.StoreUint64(&g.value, math.Float64bits(v))
  52. }
  53. func (g *gaugeMetric) flushUnsafe() metric {
  54. return metric{
  55. metricType: gauge,
  56. name: g.name,
  57. tags: g.tags,
  58. rate: 1,
  59. fvalue: math.Float64frombits(g.value),
  60. }
  61. }
  62. // Set
  63. type setMetric struct {
  64. data map[string]struct{}
  65. name string
  66. tags []string
  67. sync.Mutex
  68. }
  69. func newSetMetric(name string, value string, tags []string) *setMetric {
  70. set := &setMetric{
  71. data: map[string]struct{}{},
  72. name: name,
  73. tags: tags,
  74. }
  75. set.data[value] = struct{}{}
  76. return set
  77. }
  78. func (s *setMetric) sample(v string) {
  79. s.Lock()
  80. defer s.Unlock()
  81. s.data[v] = struct{}{}
  82. }
  83. // Sets are aggregated on the agent side too. We flush the keys so a set from
  84. // multiple application can be correctly aggregated on the agent side.
  85. func (s *setMetric) flushUnsafe() []metric {
  86. if len(s.data) == 0 {
  87. return nil
  88. }
  89. metrics := make([]metric, len(s.data))
  90. i := 0
  91. for value := range s.data {
  92. metrics[i] = metric{
  93. metricType: set,
  94. name: s.name,
  95. tags: s.tags,
  96. rate: 1,
  97. svalue: value,
  98. }
  99. i++
  100. }
  101. return metrics
  102. }
  103. // Histograms, Distributions and Timings
  104. type bufferedMetric struct {
  105. sync.Mutex
  106. data []float64
  107. name string
  108. // Histograms and Distributions store tags as one string since we need
  109. // to compute its size multiple time when serializing.
  110. tags string
  111. mtype metricType
  112. }
  113. func (s *bufferedMetric) sample(v float64) {
  114. s.Lock()
  115. defer s.Unlock()
  116. s.data = append(s.data, v)
  117. }
  118. func (s *bufferedMetric) flushUnsafe() metric {
  119. return metric{
  120. metricType: s.mtype,
  121. name: s.name,
  122. stags: s.tags,
  123. rate: 1,
  124. fvalues: s.data,
  125. }
  126. }
  127. type histogramMetric = bufferedMetric
  128. func newHistogramMetric(name string, value float64, stringTags string) *histogramMetric {
  129. return &histogramMetric{
  130. data: []float64{value},
  131. name: name,
  132. tags: stringTags,
  133. mtype: histogramAggregated,
  134. }
  135. }
  136. type distributionMetric = bufferedMetric
  137. func newDistributionMetric(name string, value float64, stringTags string) *distributionMetric {
  138. return &distributionMetric{
  139. data: []float64{value},
  140. name: name,
  141. tags: stringTags,
  142. mtype: distributionAggregated,
  143. }
  144. }
  145. type timingMetric = bufferedMetric
  146. func newTimingMetric(name string, value float64, stringTags string) *timingMetric {
  147. return &timingMetric{
  148. data: []float64{value},
  149. name: name,
  150. tags: stringTags,
  151. mtype: timingAggregated,
  152. }
  153. }