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