func (m *Metric) EmitLabelSets(c chan *LabelSet) {
	for _, lv := range m.LabelValues {
		ls := &LabelSet{zip(m.Keys, lv.Labels), lv.Value}
		c <- ls
	}
	close(c)
}
EmitLabelSets enumerates the LabelSets corresponding to the LabelValues of a
Metric.  It emits them onto the provided channel, then closes the channel to
signal completion.
package metrics
import (
	"encoding/json"
	"fmt"
	"math/rand"
	"reflect"
	"strings"
	"sync"
	"time"
	"github.com/google/mtail/internal/metrics/datum"
	"github.com/pkg/errors"
)
type Kind int
const (
	_ Kind = iota
	Counter
	Gauge
	Timer
	Text
	Histogram
	endKind  
)
func (m Kind) String() string {
	switch m {
	case Counter:
		return "Counter"
	case Gauge:
		return "Gauge"
	case Timer:
		return "Timer"
	case Text:
		return "Text"
	case Histogram:
		return "Histogram"
	}
	return "Unknown"
}
func (Kind) Generate(rand *rand.Rand, size int) reflect.Value {
	return reflect.ValueOf(Kind(rand.Intn(int(endKind))))
}
type LabelValue struct {
	Labels []string `json:",omitempty"`
	Value  datum.Datum
	Expiry time.Duration `json:",omitempty"`
}
type Metric struct {
	sync.RWMutex
	Name           string  
	Program        string  
	Kind           Kind
	Type           Type
	Hidden         bool          `json:",omitempty"`
	Keys           []string      `json:",omitempty"`
	LabelValues    []*LabelValue `json:",omitempty"`
	labelValuesMap map[string]*LabelValue
	Source         string        `json:",omitempty"`
	Buckets        []datum.Range `json:",omitempty"`
}
func NewMetric(name string, prog string, kind Kind, typ Type, keys ...string) *Metric {
	m := newMetric(len(keys))
	m.Name = name
	m.Program = prog
	m.Kind = kind
	m.Type = typ
	copy(m.Keys, keys)
	return m
}
func newMetric(keyLen int) *Metric {
	return &Metric{
		Keys:           make([]string, keyLen),
		LabelValues:    make([]*LabelValue, 0),
		labelValuesMap: make(map[string]*LabelValue),
	}
}
func buildLabelValueKey(labels []string) string {
	var buf strings.Builder
	for i := 0; i < len(labels); i++ {
		rs := strings.ReplaceAll(labels[i], "-", "\\-")
		buf.WriteString(rs)
		buf.WriteString("-")
	}
	return buf.String()
}
func (m *Metric) AppendLabelValue(lv *LabelValue) error {
	if len(lv.Labels) != len(m.Keys) {
		return errors.Errorf("Label values requested (%q) not same length as keys for metric %v", lv.Labels, m)
	}
	m.LabelValues = append(m.LabelValues, lv)
	k := buildLabelValueKey(lv.Labels)
	m.labelValuesMap[k] = lv
	return nil
}
func (m *Metric) FindLabelValueOrNil(labelvalues []string) *LabelValue {
	k := buildLabelValueKey(labelvalues)
	lv, ok := m.labelValuesMap[k]
	if ok {
		return lv
	}
	return nil
}
func (m *Metric) GetDatum(labelvalues ...string) (d datum.Datum, err error) {
	if len(labelvalues) != len(m.Keys) {
		return nil, errors.Errorf("Label values requested (%q) not same length as keys for metric %v", labelvalues, m)
	}
	m.Lock()
	defer m.Unlock()
	if lv := m.FindLabelValueOrNil(labelvalues); lv != nil {
		d = lv.Value
	} else {
		switch m.Type {
		case Int:
			d = datum.NewInt()
		case Float:
			d = datum.NewFloat()
		case String:
			d = datum.NewString()
		case Buckets:
			buckets := m.Buckets
			if buckets == nil {
				buckets = make([]datum.Range, 0)
			}
			d = datum.NewBuckets(buckets)
		}
		lv := &LabelValue{Labels: labelvalues, Value: d}
		if err := m.AppendLabelValue(lv); err != nil {
			return nil, err
		}
	}
	return d, nil
}
func (m *Metric) RemoveDatum(labelvalues ...string) error {
	if len(labelvalues) != len(m.Keys) {
		return errors.Errorf("Label values requested (%q) not same length as keys for metric %v", labelvalues, m)
	}
	m.Lock()
	defer m.Unlock()
	k := buildLabelValueKey(labelvalues)
	olv, ok := m.labelValuesMap[k]
	if ok {
		for i, lv := range m.LabelValues {
			if lv == olv {
				m.LabelValues = append(m.LabelValues[:i], m.LabelValues[i+1:]...)
				delete(m.labelValuesMap, k)
				break
			}
		}
	}
	return nil
}
func (m *Metric) ExpireDatum(expiry time.Duration, labelvalues ...string) error {
	if len(labelvalues) != len(m.Keys) {
		return errors.Errorf("Label values requested (%q) not same length as keys for metric %v", labelvalues, m)
	}
	m.Lock()
	defer m.Unlock()
	if lv := m.FindLabelValueOrNil(labelvalues); lv != nil {
		lv.Expiry = expiry
		return nil
	}
	return errors.Errorf("No datum for given labelvalues %q", labelvalues)
}
type LabelSet struct {
	Labels map[string]string
	Datum  datum.Datum
}
func zip(keys []string, values []string) map[string]string {
	r := make(map[string]string)
	for i, v := range values {
		r[keys[i]] = v
	}
	return r
}