func (mm *MetricsManager) MinerSolveTimes() []time.Duration {
	mm.minerSolveTimesLock.RLock()
	defer mm.minerSolveTimesLock.RUnlock()
	var solveTimes []time.Duration
	for _, s := range mm.minerSolveTimesCache {
		solveTimes = append(solveTimes, *s)
	}
	return solveTimes
}
MinerSolveTimes returns the solve times cache
package metrics
import (
	"sync"
	"sync/atomic"
	"time"
)
const (
	maxCachedMetrics = 5000
)
type Config struct {
	MinerSolveCount *chan struct{}
	MinerSolveHashes *chan string
	MinerSolveTimes *chan time.Duration
}
type MetricsManager struct {
	started        int32
	shutdown       int32
	minerSolveCount		*chan struct{}
	solveCount int64
	solveCountLock sync.RWMutex
	minerSolveHashes	*chan string
	minerSolveHashesCache []string
	minerSolveHashesLock sync.RWMutex
	minerSolveTimes		*chan time.Duration
	minerSolveTimesCache []*time.Duration
	minerSolveTimesLock sync.RWMutex
	wg sync.WaitGroup
	quit	chan struct{}
}
func (mm *MetricsManager) cacheSolveHash(h string) {
	mm.minerSolveHashesLock.Lock()
	defer mm.minerSolveHashesLock.Unlock()
	mm.minerSolveHashesCache = append(mm.minerSolveHashesCache, h)
}
func (mm *MetricsManager) cacheSolveTime(s time.Duration) {
	mm.minerSolveTimesLock.Lock()
	defer mm.minerSolveTimesLock.Unlock()
	mm.minerSolveTimesCache = append(mm.minerSolveTimesCache, &s)
	for (len(mm.minerSolveTimesCache)) > maxCachedMetrics {
		mm.minerSolveTimesCache = mm.minerSolveTimesCache[1:]
	}
}
func (mm *MetricsManager) incSolveCount() {
	mm.solveCountLock.Lock()
	defer mm.solveCountLock.Unlock()
	mm.solveCount++
}
func (mm *MetricsManager) metricsHandler() {
	defer mm.wg.Done()
	for {
		select {
			case <-*mm.minerSolveCount:
				mm.incSolveCount()
			case h := <-*mm.minerSolveHashes:
				mm.cacheSolveHash(h)
			case m := <-*mm.minerSolveTimes:
				mm.cacheSolveTime(m)
			case <-mm.quit:
				return
		}
	}
}
func New(config *Config) (*MetricsManager, error) {
	mm := MetricsManager{
		minerSolveCount: config.MinerSolveCount,
		minerSolveHashes: config.MinerSolveHashes,
		minerSolveTimes: config.MinerSolveTimes,
		quit: make(chan struct{}),
	}
	return &mm, nil
}
func (mm *MetricsManager) Start() {
	if atomic.AddInt32(&mm.started, 1) != 1 {
		return
	}
	log.Info("Starting metrics manager")
	mm.wg.Add(1)
	go mm.metricsHandler()
}
func (mm *MetricsManager) Stop() {
	if atomic.AddInt32(&mm.shutdown, 1) != 1 {
		log.Warn("Metrics manager is already in the process of stopping")
		return
	}
	log.Info("Metrics manager stopping")
	close(mm.quit)
	mm.wg.Wait()
	log.Info("Metrics manager stopped")
}
func (mm *MetricsManager) MinerSolveCount() int64 {
	mm.solveCountLock.RLock()
	defer mm.solveCountLock.RUnlock()
	return mm.solveCount
}
func (mm *MetricsManager) MinerSolveHashes() []string {
	mm.minerSolveHashesLock.RLock()
	defer mm.minerSolveHashesLock.RUnlock()
	return mm.minerSolveHashesCache
}