func NewAccumulator(ctx context.Context, storedSamples int, interval time.Duration) *Accumulator {
	acc := &Accumulator{
		ctx: ctx,
		RWMutex: sync.RWMutex{},
		Label:   "",
		Samples: make([]*Sample, 0, storedSamples),
		acc:     int64(0),
		storedSamples: storedSamples,
		interval: interval,
	}
	return acc
}
NewAccumulator creates an accumulator. This does not automatically call Run.
package accumulator
import (
	"context"
	"sync"
	"time"
)
type Accumulator struct {
	ctx context.Context
	sync.RWMutex
	Label   string  
	Samples []*Sample
	acc     int64
	total int64  
	storedSamples int
	interval time.Duration
}
type Sample struct {
	Value    int64     `json:"value"`
	StoredAt time.Time `json:"stored_at"`
}
func (ac *Accumulator) Sum() int64 {
	ac.RLock()
	defer ac.RUnlock()
	return ac.total
}
func (ac *Accumulator) Increment() {
	ac.IncrementBy(1)
}
func (ac *Accumulator) IncrementBy(acc int64) {
	ac.Lock()
	defer ac.Unlock()
	ac.acc += acc
}
func (ac *Accumulator) GetAllSamples() *SampleGroup {
	return &SampleGroup{
		Label:   ac.Label,
		Samples: ac.Samples,
	}
}
func (ac *Accumulator) GetLastSamples(n int) *SampleGroup {
	index := len(ac.Samples) - n
	if index < 0 {
		index = 0
	}
	ac.RLock()
	defer ac.RUnlock()
	return &SampleGroup{
		Label:   ac.Label,
		Samples: ac.Samples[index:],
	}
}
func (ac *Accumulator) GetSamplesSince(t time.Time) *SampleGroup {
	ac.RLock()
	defer ac.RUnlock()
	for index := range ac.Samples {
		if ac.Samples[len(ac.Samples)-index].StoredAt.After(t) {
			return &SampleGroup{
				Label:   ac.Label,
				Samples: ac.Samples[index:],
			}
		}
	}
	return &SampleGroup{
		Label:   ac.Label,
		Samples: ac.Samples,
	}
}
type SampleGroup struct {
	Label   string
	Samples []*Sample
}
func (sg *SampleGroup) Sum() int64 {
	acc := int64(0)
	for _, sample := range sg.Samples {
		acc += sample.Value
	}
	return acc
}
func (sg *SampleGroup) Avg() float64 {
	return float64(sg.Sum()) / float64(len(sg.Samples))
}
func (sg *SampleGroup) Since(t time.Time) *SampleGroup {
	for index := range sg.Samples {
		if sg.Samples[len(sg.Samples)-index].StoredAt.After(t) {
			sg.Samples = sg.Samples[index:]
		}
	}
	return &SampleGroup{
		Label:   "",
		Samples: sg.Samples,
	}
}
func (ac *Accumulator) RunOnce(t time.Time) {
	ac.Lock()
	ac.Samples = append(ac.Samples, &Sample{
		Value:    ac.acc,
		StoredAt: t,
	})
	ac.acc = 0
	if len(ac.Samples) > ac.storedSamples {
		ac.Samples = ac.Samples[len(ac.Samples)-ac.storedSamples:]
	}
	ac.Unlock()
}
func (ac *Accumulator) Run() {
	t := time.NewTicker(ac.interval)
	for {
		select {
		case <-ac.ctx.Done():
			return
		case <-t.C:
		}
		ac.RunOnce(time.Now().UTC())
	}
}