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  }