github.com/luckypickle/go-ethereum-vet@v1.14.2/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 // NewMeter constructs a new StandardMeter and launches a goroutine. 33 // Be sure to call Stop() once the meter is of no use to allow for garbage collection. 34 func NewMeter() Meter { 35 if !Enabled { 36 return NilMeter{} 37 } 38 m := newStandardMeter() 39 arbiter.Lock() 40 defer arbiter.Unlock() 41 arbiter.meters[m] = struct{}{} 42 if !arbiter.started { 43 arbiter.started = true 44 go arbiter.tick() 45 } 46 return m 47 } 48 49 // NewMeter constructs and registers a new StandardMeter and launches a 50 // goroutine. 51 // Be sure to unregister the meter from the registry once it is of no use to 52 // allow for garbage collection. 53 func NewRegisteredMeter(name string, r Registry) Meter { 54 c := NewMeter() 55 if nil == r { 56 r = DefaultRegistry 57 } 58 r.Register(name, c) 59 return c 60 } 61 62 // MeterSnapshot is a read-only copy of another Meter. 63 type MeterSnapshot struct { 64 count int64 65 rate1, rate5, rate15, rateMean float64 66 } 67 68 // Count returns the count of events at the time the snapshot was taken. 69 func (m *MeterSnapshot) Count() int64 { return m.count } 70 71 // Mark panics. 72 func (*MeterSnapshot) Mark(n int64) { 73 panic("Mark called on a MeterSnapshot") 74 } 75 76 // Rate1 returns the one-minute moving average rate of events per second at the 77 // time the snapshot was taken. 78 func (m *MeterSnapshot) Rate1() float64 { return m.rate1 } 79 80 // Rate5 returns the five-minute moving average rate of events per second at 81 // the time the snapshot was taken. 82 func (m *MeterSnapshot) Rate5() float64 { return m.rate5 } 83 84 // Rate15 returns the fifteen-minute moving average rate of events per second 85 // at the time the snapshot was taken. 86 func (m *MeterSnapshot) Rate15() float64 { return m.rate15 } 87 88 // RateMean returns the meter's mean rate of events per second at the time the 89 // snapshot was taken. 90 func (m *MeterSnapshot) RateMean() float64 { return m.rateMean } 91 92 // Snapshot returns the snapshot. 93 func (m *MeterSnapshot) Snapshot() Meter { return m } 94 95 // Stop is a no-op. 96 func (m *MeterSnapshot) Stop() {} 97 98 // NilMeter is a no-op Meter. 99 type NilMeter struct{} 100 101 // Count is a no-op. 102 func (NilMeter) Count() int64 { return 0 } 103 104 // Mark is a no-op. 105 func (NilMeter) Mark(n int64) {} 106 107 // Rate1 is a no-op. 108 func (NilMeter) Rate1() float64 { return 0.0 } 109 110 // Rate5 is a no-op. 111 func (NilMeter) Rate5() float64 { return 0.0 } 112 113 // Rate15is a no-op. 114 func (NilMeter) Rate15() float64 { return 0.0 } 115 116 // RateMean is a no-op. 117 func (NilMeter) RateMean() float64 { return 0.0 } 118 119 // Snapshot is a no-op. 120 func (NilMeter) Snapshot() Meter { return NilMeter{} } 121 122 // Stop is a no-op. 123 func (NilMeter) Stop() {} 124 125 // StandardMeter is the standard implementation of a Meter. 126 type StandardMeter struct { 127 lock sync.RWMutex 128 snapshot *MeterSnapshot 129 a1, a5, a15 EWMA 130 startTime time.Time 131 stopped bool 132 } 133 134 func newStandardMeter() *StandardMeter { 135 return &StandardMeter{ 136 snapshot: &MeterSnapshot{}, 137 a1: NewEWMA1(), 138 a5: NewEWMA5(), 139 a15: NewEWMA15(), 140 startTime: time.Now(), 141 } 142 } 143 144 // Stop stops the meter, Mark() will be a no-op if you use it after being stopped. 145 func (m *StandardMeter) Stop() { 146 m.lock.Lock() 147 stopped := m.stopped 148 m.stopped = true 149 m.lock.Unlock() 150 if !stopped { 151 arbiter.Lock() 152 delete(arbiter.meters, m) 153 arbiter.Unlock() 154 } 155 } 156 157 // Count returns the number of events recorded. 158 func (m *StandardMeter) Count() int64 { 159 m.lock.RLock() 160 count := m.snapshot.count 161 m.lock.RUnlock() 162 return count 163 } 164 165 // Mark records the occurrence of n events. 166 func (m *StandardMeter) Mark(n int64) { 167 m.lock.Lock() 168 defer m.lock.Unlock() 169 if m.stopped { 170 return 171 } 172 m.snapshot.count += n 173 m.a1.Update(n) 174 m.a5.Update(n) 175 m.a15.Update(n) 176 m.updateSnapshot() 177 } 178 179 // Rate1 returns the one-minute moving average rate of events per second. 180 func (m *StandardMeter) Rate1() float64 { 181 m.lock.RLock() 182 rate1 := m.snapshot.rate1 183 m.lock.RUnlock() 184 return rate1 185 } 186 187 // Rate5 returns the five-minute moving average rate of events per second. 188 func (m *StandardMeter) Rate5() float64 { 189 m.lock.RLock() 190 rate5 := m.snapshot.rate5 191 m.lock.RUnlock() 192 return rate5 193 } 194 195 // Rate15 returns the fifteen-minute moving average rate of events per second. 196 func (m *StandardMeter) Rate15() float64 { 197 m.lock.RLock() 198 rate15 := m.snapshot.rate15 199 m.lock.RUnlock() 200 return rate15 201 } 202 203 // RateMean returns the meter's mean rate of events per second. 204 func (m *StandardMeter) RateMean() float64 { 205 m.lock.RLock() 206 rateMean := m.snapshot.rateMean 207 m.lock.RUnlock() 208 return rateMean 209 } 210 211 // Snapshot returns a read-only copy of the meter. 212 func (m *StandardMeter) Snapshot() Meter { 213 m.lock.RLock() 214 snapshot := *m.snapshot 215 m.lock.RUnlock() 216 return &snapshot 217 } 218 219 func (m *StandardMeter) updateSnapshot() { 220 // should run with write lock held on m.lock 221 snapshot := m.snapshot 222 snapshot.rate1 = m.a1.Rate() 223 snapshot.rate5 = m.a5.Rate() 224 snapshot.rate15 = m.a15.Rate() 225 snapshot.rateMean = float64(snapshot.count) / time.Since(m.startTime).Seconds() 226 } 227 228 func (m *StandardMeter) tick() { 229 m.lock.Lock() 230 defer m.lock.Unlock() 231 m.a1.Tick() 232 m.a5.Tick() 233 m.a15.Tick() 234 m.updateSnapshot() 235 } 236 237 // meterArbiter ticks meters every 5s from a single goroutine. 238 // meters are references in a set for future stopping. 239 type meterArbiter struct { 240 sync.RWMutex 241 started bool 242 meters map[*StandardMeter]struct{} 243 ticker *time.Ticker 244 } 245 246 var arbiter = meterArbiter{ticker: time.NewTicker(5e9), meters: make(map[*StandardMeter]struct{})} 247 248 // Ticks meters on the scheduled interval 249 func (ma *meterArbiter) tick() { 250 for range ma.ticker.C { 251 ma.tickMeters() 252 } 253 } 254 255 func (ma *meterArbiter) tickMeters() { 256 ma.RLock() 257 defer ma.RUnlock() 258 for meter := range ma.meters { 259 meter.tick() 260 } 261 }