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