// isValidCandidate returns true if the candidate is acceptable for use.  In the
// event of any apparent incorrect use it will report the problem, invalidate
// the candidate, or outright abort.
func (r *Registry) isValidCandidate(name string, baseLabels map[string]string) (signature string, err error) {
	if len(name) == 0 {
		err = fmt.Errorf("unnamed metric named with baseLabels %s is invalid", baseLabels)

		if abortOnMisuse {
			panic(err)
		} else if debugRegistration {
			log.Println(err)
		}
	}

	if _, contains := baseLabels[nameLabel]; contains {
		err = fmt.Errorf("metric named %s with baseLabels %s contains reserved label name %s in baseLabels", name, baseLabels, nameLabel)

		if abortOnMisuse {
			panic(err)
		} else if debugRegistration {
			log.Println(err)
		}

		return
	}

	baseLabels[nameLabel] = name
	signature = utility.LabelsToSignature(baseLabels)

	if _, contains := r.signatureContainers[signature]; contains {
		err = fmt.Errorf("metric named %s with baseLabels %s is already registered", name, baseLabels)
		if abortOnMisuse {
			panic(err)
		} else if debugRegistration {
			log.Println(err)
		}

		return
	}

	if useAggressiveSanityChecks {
		for _, container := range r.signatureContainers {
			if container.name == name {
				err = fmt.Errorf("metric named %s with baseLabels %s is already registered as %s and risks causing confusion", name, baseLabels, container.baseLabels)
				if abortOnMisuse {
					panic(err)
				} else if debugRegistration {
					log.Println(err)
				}

				return
			}
		}
	}

	return
}
func (metric *counter) IncrementBy(labels map[string]string, value float64) float64 {
	metric.mutex.Lock()
	defer metric.mutex.Unlock()

	if labels == nil {
		labels = map[string]string{}
	}

	signature := utility.LabelsToSignature(labels)
	if original, ok := metric.values[signature]; ok {
		original.value += value
	} else {
		metric.values[signature] = &counterValue{
			labels: labels,
			value:  value,
		}
	}

	return value
}
func (metric *gauge) Set(labels map[string]string, value float64) float64 {
	metric.mutex.Lock()
	defer metric.mutex.Unlock()

	if labels == nil {
		labels = map[string]string{}
	}

	signature := utility.LabelsToSignature(labels)

	if original, ok := metric.values[signature]; ok {
		original.value = value
	} else {
		metric.values[signature] = &gaugeValue{
			labels: labels,
			value:  value,
		}
	}

	return value
}
func (h *histogram) Add(labels map[string]string, value float64) {
	h.mutex.Lock()
	defer h.mutex.Unlock()

	if labels == nil {
		labels = map[string]string{}
	}

	signature := utility.LabelsToSignature(labels)
	var histogram *histogramValue = nil
	if original, ok := h.values[signature]; ok {
		histogram = original
	} else {
		bucketCount := len(h.bucketStarts)
		histogram = &histogramValue{
			buckets: make([]Bucket, bucketCount),
			labels:  labels,
		}
		for i := 0; i < bucketCount; i++ {
			histogram.buckets[i] = h.bucketMaker()
		}
		h.values[signature] = histogram
	}

	lastIndex := 0

	for i, bucketStart := range h.bucketStarts {
		if value < bucketStart {
			break
		}

		lastIndex = i
	}

	histogram.buckets[lastIndex].Add(value)
}