func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *Desc {
	d := &Desc{
		fqName:         fqName,
		help:           help,
		variableLabels: variableLabels,
	}
	if help == "" {
		d.err = errors.New("empty help string")
		return d
	}
	if !metricNameRE.MatchString(fqName) {
		d.err = fmt.Errorf("%q is not a valid metric name", fqName)
		return d
	}
	labelValues := make([]string, 1, len(constLabels)+1)
	labelValues[0] = fqName
	labelNames := make([]string, 0, len(constLabels)+len(variableLabels))
	labelNameSet := map[string]struct{}{}
	for labelName := range constLabels {
		if !checkLabelName(labelName) {
			d.err = fmt.Errorf("%q is not a valid label name", labelName)
			return d
		}
		labelNames = append(labelNames, labelName)
		labelNameSet[labelName] = struct{}{}
	}
	sort.Strings(labelNames)
	for _, labelName := range labelNames {
		labelValues = append(labelValues, constLabels[labelName])
	}
	for _, labelName := range variableLabels {
		if !checkLabelName(labelName) {
			d.err = fmt.Errorf("%q is not a valid label name", labelName)
			return d
		}
		labelNames = append(labelNames, "$"+labelName)
		labelNameSet[labelName] = struct{}{}
	}
	if len(labelNames) != len(labelNameSet) {
		d.err = errors.New("duplicate label names")
		return d
	}
	h := fnv.New64a()
	var b bytes.Buffer  
	for _, val := range labelValues {
		b.Reset()
		b.WriteString(val)
		b.WriteByte(model.SeparatorByte)
		h.Write(b.Bytes())
	}
	d.id = h.Sum64()
	sort.Strings(labelNames)
	h.Reset()
	b.Reset()
	b.WriteString(help)
	b.WriteByte(model.SeparatorByte)
	h.Write(b.Bytes())
	for _, labelName := range labelNames {
		b.Reset()
		b.WriteString(labelName)
		b.WriteByte(model.SeparatorByte)
		h.Write(b.Bytes())
	}
	d.dimHash = h.Sum64()
	d.constLabelPairs = make([]*dto.LabelPair, 0, len(constLabels))
	for n, v := range constLabels {
		d.constLabelPairs = append(d.constLabelPairs, &dto.LabelPair{
			Name:  proto.String(n),
			Value: proto.String(v),
		})
	}
	sort.Sort(LabelPairSorter(d.constLabelPairs))
	return d
}
NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc
and will be reported on registration time. variableLabels and constLabels can
be nil if no such labels should be set. fqName and help must not be empty.

variableLabels only contain the label names. Their label values are variable
and therefore not part of the Desc. (They are managed within the Metric.)

For constLabels, the label values are constant. Therefore, they are fully
specified in the Desc. See the Opts documentation for the implications of
constant labels.
package prometheus
import (
	"bytes"
	"errors"
	"fmt"
	"hash/fnv"
	"regexp"
	"sort"
	"strings"
	"github.com/prometheus/client_golang/model"
	dto "github.com/prometheus/client_model/go"
	"code.google.com/p/goprotobuf/proto"
)
var (
	metricNameRE = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_:]*$`)
	labelNameRE  = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
)
type Labels map[string]string
type Desc struct {
	fqName string
	help string
	constLabelPairs []*dto.LabelPair
	variableLabels []string
	id uint64
	dimHash uint64
	err error
}