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