github.com/deanMdreon/kafka-go@v0.4.32/stats.go (about) 1 package kafka 2 3 import ( 4 "sync/atomic" 5 "time" 6 ) 7 8 // SummaryStats is a data structure that carries a summary of observed values. 9 // The average, minimum, and maximum are reported. 10 type SummaryStats struct { 11 Avg int64 `metric:"avg" type:"gauge"` 12 Min int64 `metric:"min" type:"gauge"` 13 Max int64 `metric:"max" type:"gauge"` 14 } 15 16 // DurationStats is a data structure that carries a summary of observed duration 17 // values. The average, minimum, and maximum are reported. 18 type DurationStats struct { 19 Avg time.Duration `metric:"avg" type:"gauge"` 20 Min time.Duration `metric:"min" type:"gauge"` 21 Max time.Duration `metric:"max" type:"gauge"` 22 } 23 24 // counter is an atomic incrementing counter which gets reset on snapshot. 25 // 26 // Since atomic is used to mutate the statistic the value must be 64-bit aligned. 27 // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG 28 type counter int64 29 30 func (c *counter) ptr() *int64 { 31 return (*int64)(c) 32 } 33 34 func (c *counter) observe(v int64) { 35 atomic.AddInt64(c.ptr(), v) 36 } 37 38 func (c *counter) snapshot() int64 { 39 return atomic.SwapInt64(c.ptr(), 0) 40 } 41 42 // gauge is an atomic integer that may be set to any arbitrary value, the value 43 // does not change after a snapshot. 44 // 45 // Since atomic is used to mutate the statistic the value must be 64-bit aligned. 46 // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG 47 type gauge int64 48 49 func (g *gauge) ptr() *int64 { 50 return (*int64)(g) 51 } 52 53 func (g *gauge) observe(v int64) { 54 atomic.StoreInt64(g.ptr(), v) 55 } 56 57 func (g *gauge) snapshot() int64 { 58 return atomic.LoadInt64(g.ptr()) 59 } 60 61 // minimum is an atomic integral type that keeps track of the minimum of all 62 // values that it observed between snapshots. 63 // 64 // Since atomic is used to mutate the statistic the value must be 64-bit aligned. 65 // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG 66 type minimum int64 67 68 func (m *minimum) ptr() *int64 { 69 return (*int64)(m) 70 } 71 72 func (m *minimum) observe(v int64) { 73 for { 74 ptr := m.ptr() 75 min := atomic.LoadInt64(ptr) 76 77 if min >= 0 && min <= v { 78 break 79 } 80 81 if atomic.CompareAndSwapInt64(ptr, min, v) { 82 break 83 } 84 } 85 } 86 87 func (m *minimum) snapshot() int64 { 88 p := m.ptr() 89 v := atomic.LoadInt64(p) 90 atomic.CompareAndSwapInt64(p, v, -1) 91 if v < 0 { 92 v = 0 93 } 94 return v 95 } 96 97 // maximum is an atomic integral type that keeps track of the maximum of all 98 // values that it observed between snapshots. 99 // 100 // Since atomic is used to mutate the statistic the value must be 64-bit aligned. 101 // See https://golang.org/pkg/sync/atomic/#pkg-note-BUG 102 type maximum int64 103 104 func (m *maximum) ptr() *int64 { 105 return (*int64)(m) 106 } 107 108 func (m *maximum) observe(v int64) { 109 for { 110 ptr := m.ptr() 111 max := atomic.LoadInt64(ptr) 112 113 if max >= 0 && max >= v { 114 break 115 } 116 117 if atomic.CompareAndSwapInt64(ptr, max, v) { 118 break 119 } 120 } 121 } 122 123 func (m *maximum) snapshot() int64 { 124 p := m.ptr() 125 v := atomic.LoadInt64(p) 126 atomic.CompareAndSwapInt64(p, v, -1) 127 if v < 0 { 128 v = 0 129 } 130 return v 131 } 132 133 type summary struct { 134 min minimum 135 max maximum 136 sum counter 137 count counter 138 } 139 140 func makeSummary() summary { 141 return summary{ 142 min: -1, 143 max: -1, 144 } 145 } 146 147 func (s *summary) observe(v int64) { 148 s.min.observe(v) 149 s.max.observe(v) 150 s.sum.observe(v) 151 s.count.observe(1) 152 } 153 154 func (s *summary) observeDuration(v time.Duration) { 155 s.observe(int64(v)) 156 } 157 158 func (s *summary) snapshot() SummaryStats { 159 avg := int64(0) 160 min := s.min.snapshot() 161 max := s.max.snapshot() 162 sum := s.sum.snapshot() 163 count := s.count.snapshot() 164 165 if count != 0 { 166 avg = int64(float64(sum) / float64(count)) 167 } 168 169 return SummaryStats{ 170 Avg: avg, 171 Min: min, 172 Max: max, 173 } 174 } 175 176 func (s *summary) snapshotDuration() DurationStats { 177 summary := s.snapshot() 178 return DurationStats{ 179 Avg: time.Duration(summary.Avg), 180 Min: time.Duration(summary.Min), 181 Max: time.Duration(summary.Max), 182 } 183 }