* go-metrics: fork library and introduce ResettingTimer and InfluxDB reporter. * vendor: change nonsense/go-metrics to ethersphere/go-metrics * go-metrics: add tests. move ResettingTimer logic from reporter to type. * all, metrics: pull in metrics package in go-ethereum * metrics/test: make sure metrics are enabled for tests * metrics: apply gosimple rules * metrics/exp, internal/debug: init expvar endpoint when starting pprof server * internal/debug: tiny comment formatting fix
		
			
				
	
	
		
			262 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			262 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package metrics
 | 
						|
 | 
						|
import (
 | 
						|
	"sync"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
// Meters count events to produce exponentially-weighted moving average rates
 | 
						|
// at one-, five-, and fifteen-minutes and a mean rate.
 | 
						|
type Meter interface {
 | 
						|
	Count() int64
 | 
						|
	Mark(int64)
 | 
						|
	Rate1() float64
 | 
						|
	Rate5() float64
 | 
						|
	Rate15() float64
 | 
						|
	RateMean() float64
 | 
						|
	Snapshot() Meter
 | 
						|
	Stop()
 | 
						|
}
 | 
						|
 | 
						|
// GetOrRegisterMeter returns an existing Meter or constructs and registers a
 | 
						|
// new StandardMeter.
 | 
						|
// Be sure to unregister the meter from the registry once it is of no use to
 | 
						|
// allow for garbage collection.
 | 
						|
func GetOrRegisterMeter(name string, r Registry) Meter {
 | 
						|
	if nil == r {
 | 
						|
		r = DefaultRegistry
 | 
						|
	}
 | 
						|
	return r.GetOrRegister(name, NewMeter).(Meter)
 | 
						|
}
 | 
						|
 | 
						|
// NewMeter constructs a new StandardMeter and launches a goroutine.
 | 
						|
// Be sure to call Stop() once the meter is of no use to allow for garbage collection.
 | 
						|
func NewMeter() Meter {
 | 
						|
	if !Enabled {
 | 
						|
		return NilMeter{}
 | 
						|
	}
 | 
						|
	m := newStandardMeter()
 | 
						|
	arbiter.Lock()
 | 
						|
	defer arbiter.Unlock()
 | 
						|
	arbiter.meters[m] = struct{}{}
 | 
						|
	if !arbiter.started {
 | 
						|
		arbiter.started = true
 | 
						|
		go arbiter.tick()
 | 
						|
	}
 | 
						|
	return m
 | 
						|
}
 | 
						|
 | 
						|
// NewMeter constructs and registers a new StandardMeter and launches a
 | 
						|
// goroutine.
 | 
						|
// Be sure to unregister the meter from the registry once it is of no use to
 | 
						|
// allow for garbage collection.
 | 
						|
func NewRegisteredMeter(name string, r Registry) Meter {
 | 
						|
	c := NewMeter()
 | 
						|
	if nil == r {
 | 
						|
		r = DefaultRegistry
 | 
						|
	}
 | 
						|
	r.Register(name, c)
 | 
						|
	return c
 | 
						|
}
 | 
						|
 | 
						|
// MeterSnapshot is a read-only copy of another Meter.
 | 
						|
type MeterSnapshot struct {
 | 
						|
	count                          int64
 | 
						|
	rate1, rate5, rate15, rateMean float64
 | 
						|
}
 | 
						|
 | 
						|
// Count returns the count of events at the time the snapshot was taken.
 | 
						|
func (m *MeterSnapshot) Count() int64 { return m.count }
 | 
						|
 | 
						|
// Mark panics.
 | 
						|
func (*MeterSnapshot) Mark(n int64) {
 | 
						|
	panic("Mark called on a MeterSnapshot")
 | 
						|
}
 | 
						|
 | 
						|
// Rate1 returns the one-minute moving average rate of events per second at the
 | 
						|
// time the snapshot was taken.
 | 
						|
func (m *MeterSnapshot) Rate1() float64 { return m.rate1 }
 | 
						|
 | 
						|
// Rate5 returns the five-minute moving average rate of events per second at
 | 
						|
// the time the snapshot was taken.
 | 
						|
func (m *MeterSnapshot) Rate5() float64 { return m.rate5 }
 | 
						|
 | 
						|
// Rate15 returns the fifteen-minute moving average rate of events per second
 | 
						|
// at the time the snapshot was taken.
 | 
						|
func (m *MeterSnapshot) Rate15() float64 { return m.rate15 }
 | 
						|
 | 
						|
// RateMean returns the meter's mean rate of events per second at the time the
 | 
						|
// snapshot was taken.
 | 
						|
func (m *MeterSnapshot) RateMean() float64 { return m.rateMean }
 | 
						|
 | 
						|
// Snapshot returns the snapshot.
 | 
						|
func (m *MeterSnapshot) Snapshot() Meter { return m }
 | 
						|
 | 
						|
// Stop is a no-op.
 | 
						|
func (m *MeterSnapshot) Stop() {}
 | 
						|
 | 
						|
// NilMeter is a no-op Meter.
 | 
						|
type NilMeter struct{}
 | 
						|
 | 
						|
// Count is a no-op.
 | 
						|
func (NilMeter) Count() int64 { return 0 }
 | 
						|
 | 
						|
// Mark is a no-op.
 | 
						|
func (NilMeter) Mark(n int64) {}
 | 
						|
 | 
						|
// Rate1 is a no-op.
 | 
						|
func (NilMeter) Rate1() float64 { return 0.0 }
 | 
						|
 | 
						|
// Rate5 is a no-op.
 | 
						|
func (NilMeter) Rate5() float64 { return 0.0 }
 | 
						|
 | 
						|
// Rate15is a no-op.
 | 
						|
func (NilMeter) Rate15() float64 { return 0.0 }
 | 
						|
 | 
						|
// RateMean is a no-op.
 | 
						|
func (NilMeter) RateMean() float64 { return 0.0 }
 | 
						|
 | 
						|
// Snapshot is a no-op.
 | 
						|
func (NilMeter) Snapshot() Meter { return NilMeter{} }
 | 
						|
 | 
						|
// Stop is a no-op.
 | 
						|
func (NilMeter) Stop() {}
 | 
						|
 | 
						|
// StandardMeter is the standard implementation of a Meter.
 | 
						|
type StandardMeter struct {
 | 
						|
	lock        sync.RWMutex
 | 
						|
	snapshot    *MeterSnapshot
 | 
						|
	a1, a5, a15 EWMA
 | 
						|
	startTime   time.Time
 | 
						|
	stopped     bool
 | 
						|
}
 | 
						|
 | 
						|
func newStandardMeter() *StandardMeter {
 | 
						|
	return &StandardMeter{
 | 
						|
		snapshot:  &MeterSnapshot{},
 | 
						|
		a1:        NewEWMA1(),
 | 
						|
		a5:        NewEWMA5(),
 | 
						|
		a15:       NewEWMA15(),
 | 
						|
		startTime: time.Now(),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Stop stops the meter, Mark() will be a no-op if you use it after being stopped.
 | 
						|
func (m *StandardMeter) Stop() {
 | 
						|
	m.lock.Lock()
 | 
						|
	stopped := m.stopped
 | 
						|
	m.stopped = true
 | 
						|
	m.lock.Unlock()
 | 
						|
	if !stopped {
 | 
						|
		arbiter.Lock()
 | 
						|
		delete(arbiter.meters, m)
 | 
						|
		arbiter.Unlock()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Count returns the number of events recorded.
 | 
						|
func (m *StandardMeter) Count() int64 {
 | 
						|
	m.lock.RLock()
 | 
						|
	count := m.snapshot.count
 | 
						|
	m.lock.RUnlock()
 | 
						|
	return count
 | 
						|
}
 | 
						|
 | 
						|
// Mark records the occurrence of n events.
 | 
						|
func (m *StandardMeter) Mark(n int64) {
 | 
						|
	m.lock.Lock()
 | 
						|
	defer m.lock.Unlock()
 | 
						|
	if m.stopped {
 | 
						|
		return
 | 
						|
	}
 | 
						|
	m.snapshot.count += n
 | 
						|
	m.a1.Update(n)
 | 
						|
	m.a5.Update(n)
 | 
						|
	m.a15.Update(n)
 | 
						|
	m.updateSnapshot()
 | 
						|
}
 | 
						|
 | 
						|
// Rate1 returns the one-minute moving average rate of events per second.
 | 
						|
func (m *StandardMeter) Rate1() float64 {
 | 
						|
	m.lock.RLock()
 | 
						|
	rate1 := m.snapshot.rate1
 | 
						|
	m.lock.RUnlock()
 | 
						|
	return rate1
 | 
						|
}
 | 
						|
 | 
						|
// Rate5 returns the five-minute moving average rate of events per second.
 | 
						|
func (m *StandardMeter) Rate5() float64 {
 | 
						|
	m.lock.RLock()
 | 
						|
	rate5 := m.snapshot.rate5
 | 
						|
	m.lock.RUnlock()
 | 
						|
	return rate5
 | 
						|
}
 | 
						|
 | 
						|
// Rate15 returns the fifteen-minute moving average rate of events per second.
 | 
						|
func (m *StandardMeter) Rate15() float64 {
 | 
						|
	m.lock.RLock()
 | 
						|
	rate15 := m.snapshot.rate15
 | 
						|
	m.lock.RUnlock()
 | 
						|
	return rate15
 | 
						|
}
 | 
						|
 | 
						|
// RateMean returns the meter's mean rate of events per second.
 | 
						|
func (m *StandardMeter) RateMean() float64 {
 | 
						|
	m.lock.RLock()
 | 
						|
	rateMean := m.snapshot.rateMean
 | 
						|
	m.lock.RUnlock()
 | 
						|
	return rateMean
 | 
						|
}
 | 
						|
 | 
						|
// Snapshot returns a read-only copy of the meter.
 | 
						|
func (m *StandardMeter) Snapshot() Meter {
 | 
						|
	m.lock.RLock()
 | 
						|
	snapshot := *m.snapshot
 | 
						|
	m.lock.RUnlock()
 | 
						|
	return &snapshot
 | 
						|
}
 | 
						|
 | 
						|
func (m *StandardMeter) updateSnapshot() {
 | 
						|
	// should run with write lock held on m.lock
 | 
						|
	snapshot := m.snapshot
 | 
						|
	snapshot.rate1 = m.a1.Rate()
 | 
						|
	snapshot.rate5 = m.a5.Rate()
 | 
						|
	snapshot.rate15 = m.a15.Rate()
 | 
						|
	snapshot.rateMean = float64(snapshot.count) / time.Since(m.startTime).Seconds()
 | 
						|
}
 | 
						|
 | 
						|
func (m *StandardMeter) tick() {
 | 
						|
	m.lock.Lock()
 | 
						|
	defer m.lock.Unlock()
 | 
						|
	m.a1.Tick()
 | 
						|
	m.a5.Tick()
 | 
						|
	m.a15.Tick()
 | 
						|
	m.updateSnapshot()
 | 
						|
}
 | 
						|
 | 
						|
// meterArbiter ticks meters every 5s from a single goroutine.
 | 
						|
// meters are references in a set for future stopping.
 | 
						|
type meterArbiter struct {
 | 
						|
	sync.RWMutex
 | 
						|
	started bool
 | 
						|
	meters  map[*StandardMeter]struct{}
 | 
						|
	ticker  *time.Ticker
 | 
						|
}
 | 
						|
 | 
						|
var arbiter = meterArbiter{ticker: time.NewTicker(5e9), meters: make(map[*StandardMeter]struct{})}
 | 
						|
 | 
						|
// Ticks meters on the scheduled interval
 | 
						|
func (ma *meterArbiter) tick() {
 | 
						|
	for range ma.ticker.C {
 | 
						|
		ma.tickMeters()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (ma *meterArbiter) tickMeters() {
 | 
						|
	ma.RLock()
 | 
						|
	defer ma.RUnlock()
 | 
						|
	for meter := range ma.meters {
 | 
						|
		meter.tick()
 | 
						|
	}
 | 
						|
}
 |