954ede931f
License: MIT Signed-off-by: Hector Sanjuan <code@hector.link>
98 lines
2.2 KiB
Go
98 lines
2.2 KiB
Go
// Package metrics provides common functionality for working with metrics,
|
|
// particulary useful for monitoring components. It includes types to store,
|
|
// check and filter metrics.
|
|
package metrics
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
|
|
"github.com/ipfs/ipfs-cluster/api"
|
|
)
|
|
|
|
// DefaultWindowCap sets the amount of metrics to store per peer.
|
|
var DefaultWindowCap = 25
|
|
|
|
// ErrNoMetrics is returned when there are no metrics in a Window.
|
|
var ErrNoMetrics = errors.New("no metrics have been added to this window")
|
|
|
|
// Window implements a circular queue to store metrics.
|
|
type Window struct {
|
|
last int
|
|
|
|
safe bool
|
|
windowLock sync.RWMutex
|
|
window []api.Metric
|
|
}
|
|
|
|
// NewWindow creates an instance with the given
|
|
// window capacity. The safe indicates whether we use a lock
|
|
// for concurrent operations.
|
|
func NewWindow(windowCap int, safe bool) *Window {
|
|
if windowCap <= 0 {
|
|
panic("invalid windowCap")
|
|
}
|
|
|
|
w := make([]api.Metric, 0, windowCap)
|
|
return &Window{
|
|
last: 0,
|
|
safe: safe,
|
|
window: w,
|
|
}
|
|
}
|
|
|
|
// Add adds a new metric to the window. If the window capacity
|
|
// has been reached, the oldest metric (by the time it was added),
|
|
// will be discarded.
|
|
func (mw *Window) Add(m api.Metric) {
|
|
if mw.safe {
|
|
mw.windowLock.Lock()
|
|
defer mw.windowLock.Unlock()
|
|
}
|
|
if len(mw.window) < cap(mw.window) {
|
|
mw.window = append(mw.window, m)
|
|
mw.last = len(mw.window) - 1
|
|
return
|
|
}
|
|
|
|
// len == cap
|
|
mw.last = (mw.last + 1) % cap(mw.window)
|
|
mw.window[mw.last] = m
|
|
return
|
|
}
|
|
|
|
// Latest returns the last metric added. It returns an error
|
|
// if no metrics were added.
|
|
func (mw *Window) Latest() (api.Metric, error) {
|
|
if mw.safe {
|
|
mw.windowLock.Lock()
|
|
defer mw.windowLock.Unlock()
|
|
}
|
|
if len(mw.window) == 0 {
|
|
return api.Metric{}, ErrNoMetrics
|
|
}
|
|
return mw.window[mw.last], nil
|
|
}
|
|
|
|
// All returns all the metrics in the window, in the inverse order
|
|
// they were Added. That is, result[0] will be the last added
|
|
// metric.
|
|
func (mw *Window) All() []api.Metric {
|
|
if mw.safe {
|
|
mw.windowLock.Lock()
|
|
defer mw.windowLock.Unlock()
|
|
}
|
|
wlen := len(mw.window)
|
|
res := make([]api.Metric, 0, wlen)
|
|
if wlen == 0 {
|
|
return res
|
|
}
|
|
for i := mw.last; i >= 0; i-- {
|
|
res = append(res, mw.window[i])
|
|
}
|
|
for i := wlen - 1; i > mw.last; i-- {
|
|
res = append(res, mw.window[i])
|
|
}
|
|
return res
|
|
}
|