github.com/sunblockterminal/go-sunblocktediuma@v0.0.0-20210616083421-160a35ed7cfa/metrics/meter.go (about) 1 package metrics 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 // Meters count events to produce exponentially-weighted moving average rates 9 // at one-, five-, and fifteen-minutes and a mean rate. 10 type Meter interface { 11 Count() int64 12 Mark(int64) 13 Rate1() float64 14 Rate5() float64 15 Rate15() float64 16 RateMean() float64 17 Snapshot() Meter 18 Stop() 19 } 20 21 // GetOrRegisterMeter returns an existing Meter or constructs and registers a 22 // new StandardMeter. 23 // Be sure to unregister the meter from the registry once it is of no use to 24 // allow for garbage collection. 25 func GetOrRegisterMeter(name string, r Registry) Meter { 26 if nil == r { 27 r = DefaultRegistry 28 } 29 return r.GetOrRegister(name, NewMeter).(Meter) 30 } 31 32 // GetOrRegisterMeterForced returns an existing Meter or constructs and registers a 33 // new StandardMeter no matter the global switch is enabled or not. 34 // Be sure to unregister the meter from the registry once it is of no use to 35 // allow for garbage collection. 36 func GetOrRegisterMeterForced(name string, r Registry) Meter { 37 if nil == r { 38 r = DefaultRegistry 39 } 40 return r.GetOrRegister(name, NewMeterForced).(Meter) 41 } 42 43 // NewMeter constructs a new StandardMeter and launches a goroutine. 44 // Be sure to call Stop() once the meter is of no use to allow for garbage collection. 45 func NewMeter() Meter { 46 if !Enabled { 47 return NilMeter{} 48 } 49 m := newStandardMeter() 50 arbiter.Lock() 51 defer arbiter.Unlock() 52 arbiter.meters[m] = struct{}{} 53 if !arbiter.started { 54 arbiter.started = true 55 go arbiter.tick() 56 } 57 return m 58 } 59 60 // NewMeterForced constructs a new StandardMeter and launches a goroutine no matter 61 // the global switch is enabled or not. 62 // Be sure to call Stop() once the meter is of no use to allow for garbage collection. 63 func NewMeterForced() Meter { 64 m := newStandardMeter() 65 arbiter.Lock() 66 defer arbiter.Unlock() 67 arbiter.meters[m] = struct{}{} 68 if !arbiter.started { 69 arbiter.started = true 70 go arbiter.tick() 71 } 72 return m 73 } 74 75 // NewRegisteredMeter constructs and registers a new StandardMeter 76 // and launches a goroutine. 77 // Be sure to unregister the meter from the registry once it is of no use to 78 // allow for garbage collection. 79 func NewRegisteredMeter(name string, r Registry) Meter { 80 c := NewMeter() 81 if nil == r { 82 r = DefaultRegistry 83 } 84 r.Register(name, c) 85 return c 86 } 87 88 // NewRegisteredMeterForced constructs and registers a new StandardMeter 89 // and launches a goroutine no matter the global switch is enabled or not. 90 // Be sure to unregister the meter from the registry once it is of no use to 91 // allow for garbage collection. 92 func NewRegisteredMeterForced(name string, r Registry) Meter { 93 c := NewMeterForced() 94 if nil == r { 95 r = DefaultRegistry 96 } 97 r.Register(name, c) 98 return c 99 } 100 101 // MeterSnapshot is a read-only copy of another Meter. 102 type MeterSnapshot struct { 103 count int64 104 rate1, rate5, rate15, rateMean float64 105 } 106 107 // Count returns the count of events at the time the snapshot was taken. 108 func (m *MeterSnapshot) Count() int64 { return m.count } 109 110 // Mark panics. 111 func (*MeterSnapshot) Mark(n int64) { 112 panic("Mark called on a MeterSnapshot") 113 } 114 115 // Rate1 returns the one-minute moving average rate of events per second at the 116 // time the snapshot was taken. 117 func (m *MeterSnapshot) Rate1() float64 { return m.rate1 } 118 119 // Rate5 returns the five-minute moving average rate of events per second at 120 // the time the snapshot was taken. 121 func (m *MeterSnapshot) Rate5() float64 { return m.rate5 } 122 123 // Rate15 returns the fifteen-minute moving average rate of events per second 124 // at the time the snapshot was taken. 125 func (m *MeterSnapshot) Rate15() float64 { return m.rate15 } 126 127 // RateMean returns the meter's mean rate of events per second at the time the 128 // snapshot was taken. 129 func (m *MeterSnapshot) RateMean() float64 { return m.rateMean } 130 131 // Snapshot returns the snapshot. 132 func (m *MeterSnapshot) Snapshot() Meter { return m } 133 134 // Stop is a no-op. 135 func (m *MeterSnapshot) Stop() {} 136 137 // NilMeter is a no-op Meter. 138 type NilMeter struct{} 139 140 // Count is a no-op. 141 func (NilMeter) Count() int64 { return 0 } 142 143 // Mark is a no-op. 144 func (NilMeter) Mark(n int64) {} 145 146 // Rate1 is a no-op. 147 func (NilMeter) Rate1() float64 { return 0.0 } 148 149 // Rate5 is a no-op. 150 func (NilMeter) Rate5() float64 { return 0.0 } 151 152 // Rate15is a no-op. 153 func (NilMeter) Rate15() float64 { return 0.0 } 154 155 // RateMean is a no-op. 156 func (NilMeter) RateMean() float64 { return 0.0 } 157 158 // Snapshot is a no-op. 159 func (NilMeter) Snapshot() Meter { return NilMeter{} } 160 161 // Stop is a no-op. 162 func (NilMeter) Stop() {} 163 164 // StandardMeter is the standard implementation of a Meter. 165 type StandardMeter struct { 166 lock sync.RWMutex 167 snapshot *MeterSnapshot 168 a1, a5, a15 EWMA 169 startTime time.Time 170 stopped bool 171 } 172 173 func newStandardMeter() *StandardMeter { 174 return &StandardMeter{ 175 snapshot: &MeterSnapshot{}, 176 a1: NewEWMA1(), 177 a5: NewEWMA5(), 178 a15: NewEWMA15(), 179 startTime: time.Now(), 180 } 181 } 182 183 // Stop stops the meter, Mark() will be a no-op if you use it after being stopped. 184 func (m *StandardMeter) Stop() { 185 m.lock.Lock() 186 stopped := m.stopped 187 m.stopped = true 188 m.lock.Unlock() 189 if !stopped { 190 arbiter.Lock() 191 delete(arbiter.meters, m) 192 arbiter.Unlock() 193 } 194 } 195 196 // Count returns the number of events recorded. 197 func (m *StandardMeter) Count() int64 { 198 m.lock.RLock() 199 count := m.snapshot.count 200 m.lock.RUnlock() 201 return count 202 } 203 204 // Mark records the occurrence of n events. 205 func (m *StandardMeter) Mark(n int64) { 206 m.lock.Lock() 207 defer m.lock.Unlock() 208 if m.stopped { 209 return 210 } 211 m.snapshot.count += n 212 m.a1.Update(n) 213 m.a5.Update(n) 214 m.a15.Update(n) 215 m.updateSnapshot() 216 } 217 218 // Rate1 returns the one-minute moving average rate of events per second. 219 func (m *StandardMeter) Rate1() float64 { 220 m.lock.RLock() 221 rate1 := m.snapshot.rate1 222 m.lock.RUnlock() 223 return rate1 224 } 225 226 // Rate5 returns the five-minute moving average rate of events per second. 227 func (m *StandardMeter) Rate5() float64 { 228 m.lock.RLock() 229 rate5 := m.snapshot.rate5 230 m.lock.RUnlock() 231 return rate5 232 } 233 234 // Rate15 returns the fifteen-minute moving average rate of events per second. 235 func (m *StandardMeter) Rate15() float64 { 236 m.lock.RLock() 237 rate15 := m.snapshot.rate15 238 m.lock.RUnlock() 239 return rate15 240 } 241 242 // RateMean returns the meter's mean rate of events per second. 243 func (m *StandardMeter) RateMean() float64 { 244 m.lock.RLock() 245 rateMean := m.snapshot.rateMean 246 m.lock.RUnlock() 247 return rateMean 248 } 249 250 // Snapshot returns a read-only copy of the meter. 251 func (m *StandardMeter) Snapshot() Meter { 252 m.lock.RLock() 253 snapshot := *m.snapshot 254 m.lock.RUnlock() 255 return &snapshot 256 } 257 258 func (m *StandardMeter) updateSnapshot() { 259 // should run with write lock held on m.lock 260 snapshot := m.snapshot 261 snapshot.rate1 = m.a1.Rate() 262 snapshot.rate5 = m.a5.Rate() 263 snapshot.rate15 = m.a15.Rate() 264 snapshot.rateMean = float64(snapshot.count) / time.Since(m.startTime).Seconds() 265 } 266 267 func (m *StandardMeter) tick() { 268 m.lock.Lock() 269 defer m.lock.Unlock() 270 m.a1.Tick() 271 m.a5.Tick() 272 m.a15.Tick() 273 m.updateSnapshot() 274 } 275 276 // meterArbiter ticks meters every 5s from a single goroutine. 277 // meters are references in a set for future stopping. 278 type meterArbiter struct { 279 sync.RWMutex 280 started bool 281 meters map[*StandardMeter]struct{} 282 ticker *time.Ticker 283 } 284 285 var arbiter = meterArbiter{ticker: time.NewTicker(5e9), meters: make(map[*StandardMeter]struct{})} 286 287 // Ticks meters on the scheduled interval 288 func (ma *meterArbiter) tick() { 289 for range ma.ticker.C { 290 ma.tickMeters() 291 } 292 } 293 294 func (ma *meterArbiter) tickMeters() { 295 ma.RLock() 296 defer ma.RUnlock() 297 for meter := range ma.meters { 298 meter.tick() 299 } 300 }