func (m *logCounter) Name() string {
	return m.name
}
Name returns the metric's name.
package metrics
import (
	"context"
	"fmt"
	"strconv"
	"sync"
	"time"
	"bitbucket.org/creachadair/stringset"
	"github.com/sirupsen/logrus"
)
type Valuer interface {
	Metric
	Values() map[string]map[string]interface{}
}
type Reporter []Valuer
func (r *Reporter) Report(ctx context.Context, log logrus.FieldLogger, freq time.Duration) error {
	if log == nil {
		log = logrus.New()
	}
	ticker := time.NewTicker(freq)
	defer ticker.Stop()
	names := stringset.NewSize(len(*r))
	metricMap := make(map[string]int, len(*r))
	for i, m := range *r {
		name := m.Name()
		names.Add(name)
		metricMap[name] = i
	}
	for {
		select {
		case <-ticker.C:
		case <-ctx.Done():
			return ctx.Err()
		}
		for _, name := range names.Elements() {
			i := metricMap[name]
			metric := (*r)[i]
			log := log.WithField("metric", metric.Name())
			for field, values := range metric.Values() {
				log := log.WithField("field", field)
				for value, measurement := range values {
					log = log.WithField(value, measurement)
				}
				log.Info("Current status")
			}
		}
	}
}
func (r *Reporter) Int64(name, desc string, log logrus.FieldLogger, fields ...string) Int64 {
	current := make([]map[string][]int64, len(fields))
	for i := range fields {
		current[i] = make(map[string][]int64, 1)
	}
	out := &logInt64{
		name:    name,
		desc:    desc,
		log:     log,
		fields:  fields,
		current: current,
	}
	*r = append(*r, out)
	return out
}
func (r *Reporter) Counter(name, desc string, log logrus.FieldLogger, fields ...string) Counter {
	current := make([]map[string]int64, len(fields))
	previous := make([]map[string]int64, len(fields))
	for i := range fields {
		current[i] = make(map[string]int64, 1)
		previous[i] = make(map[string]int64, 1)
	}
	out := &logCounter{
		name:     name,
		desc:     desc,
		log:      log,
		fields:   fields,
		current:  current,
		previous: previous,
		last:     time.Now(),
	}
	*r = append(*r, out)
	return out
}
type logInt64 struct {
	name    string
	desc    string
	fields  []string
	log     logrus.FieldLogger
	current []map[string][]int64
	lock    sync.Mutex
}
func (m *logInt64) Name() string {
	return m.name
}
func (m *logInt64) Set(n int64, fields ...string) {
	m.lock.Lock()
	defer m.lock.Unlock()
	if len(fields) != len(m.fields) {
		m.log.WithFields(logrus.Fields{
			"want": m.fields,
			"got":  fields,
		}).Fatal("Wrong number of fields")
	}
	for i, fieldValue := range fields {
		m.current[i][fieldValue] = append(m.current[i][fieldValue], n)
	}
}
func (m *logInt64) Values() map[string]map[string]interface{} {
	m.lock.Lock()
	defer m.lock.Unlock()
	trend := make(map[string]map[string]interface{}, len(m.current))
	for i, field := range m.fields {
		current := m.current[i]
		if len(current) == 0 {
			continue
		}
		trend[field] = make(map[string]interface{}, len(current))
		for fieldValue, measurements := range current {
			trend[field][fieldValue] = mean{measurements}
			delete(current, fieldValue)
		}
	}
	return trend
}
type mean struct {
	values []int64
}
func (m mean) String() string {
	tot := len(m.values)
	switch tot {
	case 0:
		return "0 values"
	case 1:
		return strconv.FormatInt(m.values[0], 10)
	}
	var val float64
	n := float64(tot)
	for _, v := range m.values {
		val += (float64(v) / n)
	}
	return fmt.Sprintf("%s average (%d values)", strconv.FormatFloat(val, 'g', 3, 64), tot)
}
type logCounter struct {
	name     string
	desc     string
	fields   []string
	log      logrus.FieldLogger
	current  []map[string]int64
	previous []map[string]int64
	last     time.Time
	lock     sync.Mutex
}