hunk.code_window:         "SyncIntervalMinutes": 60,
           "SkipCertificateVerification": false,
           "QueryTimeout": 60,
           "MaxPageSize": 0,
           "LoginFieldName": ""
       },
       "ComplianceSettings": {
           "Enable": false,
  
hunk.labels: keep keep keep keep replace keep keep keep
hunk.after_edit:         "LoginFieldName": "",
           "LoginButtonColor": "",
           "LoginButtonBorderColor": "",
           "LoginButtonTextColor": ""
  
hunk.file_path: config/default.json
hunk.type: replace
file: // Copyright 2014 The Prometheus Authors
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  // http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  package prometheus
  
  import (
  	"bytes"
  	"errors"
  	"fmt"
  	"os"
  	"sort"
  	"sync"
  
  	"github.com/golang/protobuf/proto"
  
  	dto "github.com/prometheus/client_model/go"
  )
  
  const (
  	// Capacity for the channel to collect metrics and descriptors.
  	capMetricChan = 1000
  	capDescChan   = 10
  )
  
  // DefaultRegisterer and DefaultGatherer are the implementations of the
  // Registerer and Gatherer interface a number of convenience functions in this
  // package act on. Initially, both variables point to the same Registry, which
  // has a process collector (see NewProcessCollector) and a Go collector (see
  // NewGoCollector) already registered. This approach to keep default instances
  // as global state mirrors the approach of other packages in the Go standard
  // library. Note that there are caveats. Change the variables with caution and
  // only if you understand the consequences. Users who want to avoid global state
  // altogether should not use the convenience function and act on custom
  // instances instead.
  var (
  	defaultRegistry              = NewRegistry()
  	DefaultRegisterer Registerer = defaultRegistry
  	DefaultGatherer   Gatherer   = defaultRegistry
  )
  
  func init() {
  	MustRegister(NewProcessCollector(os.Getpid(), ""))
  	MustRegister(NewGoCollector())
  }
  
  // NewRegistry creates a new vanilla Registry without any Collectors
  // pre-registered.
  func NewRegistry() *Registry {
  	return &Registry{
  		collectorsByID:  map[uint64]Collector{},
  		descIDs:         map[uint64]struct{}{},
  		dimHashesByName: map[string]uint64{},
  	}
  }
  
  // NewPedanticRegistry returns a registry that checks during collection if each
  // collected Metric is consistent with its reported Desc, and if the Desc has
  // actually been registered with the registry.
  //
  // Usually, a Registry will be happy as long as the union of all collected
  // Metrics is consistent and valid even if some metrics are not consistent with
  // their own Desc or a Desc provided by their registered Collector. Well-behaved
  // Collectors and Metrics will only provide consistent Descs. This Registry is
  // useful to test the implementation of Collectors and Metrics.
  func NewPedanticRegistry() *Registry {
  	r := NewRegistry()
  	r.pedanticChecksEnabled = true
  	return r
  }
  
  // Registerer is the interface for the part of a registry in charge of
  // registering and unregistering. Users of custom registries should use
  // Registerer as type for registration purposes (rather then the Registry type
  // directly). In that way, they are free to use custom Registerer implementation
  // (e.g. for testing purposes).
  type Registerer interface {
  	// Register registers a new Collector to be included in metrics
  	// collection. It returns an error if the descriptors provided by the
  	// Collector are invalid or if they — in combination with descriptors of
  	// already registered Collectors — do not fulfill the consistency and
  	// uniqueness criteria described in the documentation of metric.Desc.
  	//
  	// If the provided Collector is equal to a Collector already registered
  	// (which includes the case of re-registering the same Collector), the
  	// returned error is an instance of AlreadyRegisteredError, which
  	// contains the previously registered Collector.
  	//
  	// It is in general not safe to register the same Collector multiple
  	// times concurrently.
  	Register(Collector) error
  	// MustRegister works like Register but registers any number of
  	// Collectors and panics upon the first registration that causes an
  	// error.
  	MustRegister(...Collector)
  	// Unregister unregisters the Collector that equals the Collector passed
  	// in as an argument.  (Two Collectors are considered equal if their
  	// Describe method yields the same set of descriptors.) The function
  	// returns whether a Collector was unregistered.
  	//
  	// Note that even after unregistering, it will not be possible to
  	// register a new Collector that is inconsistent with the unregistered
  	// Collector, e.g. a Collector collecting metrics with the same name but
  	// a different help string. The rationale here is that the same registry
  	// instance must only collect consistent metrics throughout its
  	// lifetime.
  	Unregister(Collector) bool
  }
  
  // Gatherer is the interface for the part of a registry in charge of gathering
  // the collected metrics into a number of MetricFamilies. The Gatherer interface
  // comes with the same general implication as described for the Registerer
  // interface.
  type Gatherer interface {
  	// Gather calls the Collect method of the registered Collectors and then
  	// gathers the collected metrics into a lexicographically sorted slice
  	// of MetricFamily protobufs. Even if an error occurs, Gather attempts
  	// to gather as many metrics as possible. Hence, if a non-nil error is
  	// returned, the returned MetricFamily slice could be nil (in case of a
  	// fatal error that prevented any meaningful metric collection) or
  	// contain a number of MetricFamily protobufs, some of which might be
  	// incomplete, and some might be missing altogether. The returned error
  	// (which might be a MultiError) explains the details. In scenarios
  	// where complete collection is critical, the returned MetricFamily
  	// protobufs should be disregarded if the returned error is non-nil.
  	Gather() ([]*dto.MetricFamily, error)
  }
  
  // Register registers the provided Collector with the DefaultRegisterer.
  //
  // Register is a shortcut for DefaultRegisterer.Register(c). See there for more
  // details.
  func Register(c Collector) error {
  	return DefaultRegisterer.Register(c)
  }
  
  // MustRegister registers the provided Collectors with the DefaultRegisterer and
  // panics if any error occurs.
  //
  // MustRegister is a shortcut for DefaultRegisterer.MustRegister(cs...). See
  // there for more details.
  func MustRegister(cs ...Collector) {
  	DefaultRegisterer.MustRegister(cs...)
  }
  
  // RegisterOrGet registers the provided Collector with the DefaultRegisterer and
  // returns the Collector, unless an equal Collector was registered before, in
  // which case that Collector is returned.
  //
  // Deprecated: RegisterOrGet is merely a convenience function for the
  // implementation as described in the documentation for
  // AlreadyRegisteredError. As the use case is relatively rare, this function
  // will be removed in a future version of this package to clean up the
  // namespace.
  func RegisterOrGet(c Collector) (Collector, error) {
  	if err := Register(c); err != nil {
  		if are, ok := err.(AlreadyRegisteredError); ok {
  			return are.ExistingCollector, nil
  		}
  		return nil, err
  	}
  	return c, nil
  }
  
  // MustRegisterOrGet behaves like RegisterOrGet but panics instead of returning
  // an error.
  //
  // Deprecated: This is deprecated for the same reason RegisterOrGet is. See
  // there for details.
  func MustRegisterOrGet(c Collector) Collector {
  	c, err := RegisterOrGet(c)
  	if err != nil {
  		panic(err)
  	}
  	return c
  }
  
  // Unregister removes the registration of the provided Collector from the
  // DefaultRegisterer.
  //
  // Unregister is a shortcut for DefaultRegisterer.Unregister(c). See there for
  // more details.
  func Unregister(c Collector) bool {
  	return DefaultRegisterer.Unregister(c)
  }
  
  // GathererFunc turns a function into a Gatherer.
  type GathererFunc func() ([]*dto.MetricFamily, error)
  
  // Gather implements Gatherer.
  func (gf GathererFunc) Gather() ([]*dto.MetricFamily, error) {
  	return gf()
  }
  
  // SetMetricFamilyInjectionHook replaces the DefaultGatherer with one that
  // gathers from the previous DefaultGatherers but then merges the MetricFamily
  // protobufs returned from the provided hook function with the MetricFamily
  // protobufs returned from the original DefaultGatherer.
  //
  // Deprecated: This function manipulates the DefaultGatherer variable. Consider
  // the implications, i.e. don't do this concurrently with any uses of the
  // DefaultGatherer. In the rare cases where you need to inject MetricFamily
  // protobufs directly, it is recommended to use a custom Registry and combine it
  // with a custom Gatherer using the Gatherers type (see
  // there). SetMetricFamilyInjectionHook only exists for compatibility reasons
  // with previous versions of this package.
  func SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily) {
  	DefaultGatherer = Gatherers{
  		DefaultGatherer,
  		GathererFunc(func() ([]*dto.MetricFamily, error) { return hook(), nil }),
  	}
  }
  
  // AlreadyRegisteredError is returned by the Register method if the Collector to
  // be registered has already been registered before, or a different Collector
  // that collects the same metrics has been registered before. Registration fails
  // in that case, but you can detect from the kind of error what has
  // happened. The error contains fields for the existing Collector and the
  // (rejected) new Collector that equals the existing one. This can be used to
  // find out if an equal Collector has been registered before and switch over to
  // using the old one, as demonstrated in the example.
  type AlreadyRegisteredError struct {
  	ExistingCollector, NewCollector Collector
  }
  
  func (err AlreadyRegisteredError) Error() string {
  	return "duplicate metrics collector registration attempted"
  }
  
  // MultiError is a slice of errors implementing the error interface. It is used
  // by a Gatherer to report multiple errors during MetricFamily gathering.
  type MultiError []error
  
  func (errs MultiError) Error() string {
  	if len(errs) == 0 {
  		return ""
  	}
  	buf := &bytes.Buffer{}
  	fmt.Fprintf(buf, "%d error(s) occurred:", len(errs))
  	for _, err := range errs {
  		fmt.Fprintf(buf, "\n* %s", err)
  	}
  	return buf.String()
  }
  
  // MaybeUnwrap returns nil if len(errs) is 0. It returns the first and only
  // contained error as error if len(errs is 1). In all other cases, it returns
  // the MultiError directly. This is helpful for returning a MultiError in a way
  // that only uses the MultiError if needed.
  func (errs MultiError) MaybeUnwrap() error {
  	switch len(errs) {
  	case 0:
  		return nil
  	case 1:
  		return errs[0]
  	default:
  		return errs
  	}
  }
  
  // Registry registers Prometheus collectors, collects their metrics, and gathers
  // them into MetricFamilies for exposition. It implements both Registerer and
  // Gatherer. The zero value is not usable. Create instances with NewRegistry or
  // NewPedanticRegistry.
  type Registry struct {
  	mtx                   sync.RWMutex
  	collectorsByID        map[uint64]Collector // ID is a hash of the descIDs.
  	descIDs               map[uint64]struct{}
  	dimHashesByName       map[string]uint64
  	pedanticChecksEnabled bool
  }
  
  // Register implements Registerer.
  func (r *Registry) Register(c Collector) error {
  	var (
  		descChan           = make(chan *Desc, capDescChan)
  		newDescIDs         = map[uint64]struct{}{}
  		newDimHashesByName = map[string]uint64{}
  		collectorID        uint64 // Just a sum of all desc IDs.
  		duplicateDescErr   error
  	)
  	go func() {
  		c.Describe(descChan)
  		close(descChan)
  	}()
  	r.mtx.Lock()
  	defer r.mtx.Unlock()
  	// Coduct various tests...
  	for desc := range descChan {
  
  		// Is the descriptor valid at all?
  		if desc.err != nil {
  			return fmt.Errorf("descriptor %s is invalid: %s", desc, desc.err)
  		}
  
  		// Is the descID unique?
  		// (In other words: Is the fqName + constLabel combination unique?)
  		if _, exists := r.descIDs[desc.id]; exists {
  			duplicateDescErr = fmt.Errorf("descriptor %s already exists with the same fully-qualified name and const label values", desc)
  		}
  		// If it is not a duplicate desc in this collector, add it to
  		// the collectorID.  (We allow duplicate descs within the same
  		// collector, but their existence must be a no-op.)
  		if _, exists := newDescIDs[desc.id]; !exists {
  			newDescIDs[desc.id] = struct{}{}
  			collectorID += desc.id
  		}
  
  		// Are all the label names and the help string consistent with
  		// previous descriptors of the same name?
  		// First check existing descriptors...
  		if dimHash, exists := r.dimHashesByName[desc.fqName]; exists {
  			if dimHash != desc.dimHash {
  				return fmt.Errorf("a previously registered descriptor with the same fully-qualified name as %s has different label names or a different help string", desc)
  			}
  		} else {
  			// ...then check the new descriptors already seen.
  			if dimHash, exists := newDimHashesByName[desc.fqName]; exists {
  				if dimHash != desc.dimHash {
  					return fmt.Errorf("descriptors reported by collector have inconsistent label names or help strings for the same fully-qualified name, offender is %s", desc)
  				}
  			} else {
  				newDimHashesByName[desc.fqName] = desc.dimHash
  			}
  		}
  	}
  	// Did anything happen at all?
  	if len(newDescIDs) == 0 {
  		return errors.New("collector has no descriptors")
  	}
  	if existing, exists := r.collectorsByID[collectorID]; exists {
  		return AlreadyRegisteredError{
  			ExistingCollector: existing,
  			NewCollector:      c,
  		}
  	}
  	// If the collectorID is new, but at least one of the descs existed
  	// before, we are in trouble.
  	if duplicateDescErr != nil {
  		return duplicateDescErr
  	}
  
  	// Only after all tests have passed, actually register.
  	r.collectorsByID[collectorID] = c
  	for hash := range newDescIDs {
  		r.descIDs[hash] = struct{}{}
  	}
  	for name, dimHash := range newDimHashesByName {
  		r.dimHashesByName[name] = dimHash
  	}
  	return nil
  }
  
  // Unregister implements Registerer.
  func (r *Registry) Unregister(c Collector) bool {
  	var (
  		descChan    = make(chan *Desc, capDescChan)
  		descIDs     = map[uint64]struct{}{}
  		collectorID uint64 // Just a sum of the desc IDs.
  	)
  	go func() {
  		c.Describe(descChan)
  		close(descChan)
  	}()
  	for desc := range descChan {
  		if _, exists := descIDs[desc.id]; !exists {
  			collectorID += desc.id
  			descIDs[desc.id] = struct{}{}
  		}
  	}
  
  	r.mtx.RLock()
  	if _, exists := r.collectorsByID[collectorID]; !exists {
  		r.mtx.RUnlock()
  		return false
  	}
  	r.mtx.RUnlock()
  
  	r.mtx.Lock()
  	defer r.mtx.Unlock()
  
  	delete(r.collectorsByID, collectorID)
  	for id := range descIDs {
  		delete(r.descIDs, id)
  	}
  	// dimHashesByName is left untouched as those must be consistent
  	// throughout the lifetime of a program.
  	return true
  }
  
  // MustRegister implements Registerer.
  func (r *Registry) MustRegister(cs ...Collector) {
  	for _, c := range cs {
  		if err := r.Register(c); err != nil {
  			panic(err)
  		}
  	}
  }
  
  // Gather implements Gatherer.
  func (r *Registry) Gather() ([]*dto.MetricFamily, error) {
  	var (
  		metricChan        = make(chan Metric, capMetricChan)
  		metricHashes      = map[uint64]struct{}{}
  		dimHashes         = map[string]uint64{}
  		wg                sync.WaitGroup
  		errs              MultiError          // The collected errors to return in the end.
  		registeredDescIDs map[uint64]struct{} // Only used for pedantic checks
  	)
  
  	r.mtx.RLock()
  	metricFamiliesByName := make(map[string]*dto.MetricFamily, len(r.dimHashesByName))
  
  	// Scatter.
  	// (Collectors could be complex and slow, so we call them all at once.)
  	wg.Add(len(r.collectorsByID))
  	go func() {
  		wg.Wait()
  		close(metricChan)
  	}()
  	for _, collector := range r.collectorsByID {
  		go func(collector Collector) {
  			defer wg.Done()
  			collector.Collect(metricChan)
  		}(collector)
  	}
  
  	// In case pedantic checks are enabled, we have to copy the map before
  	// giving up the RLock.
  	if r.pedanticChecksEnabled {
  		registeredDescIDs = make(map[uint64]struct{}, len(r.descIDs))
  		for id := range r.descIDs {
  			registeredDescIDs[id] = struct{}{}
  		}
  	}
  
  	r.mtx.RUnlock()
  
  	// Drain metricChan in case of premature return.
  	defer func() {
  		for _ = range metricChan {
  		}
  	}()
  
  	// Gather.
  	for metric := range metricChan {
  		// This could be done concurrently, too, but it required locking
  		// of metricFamiliesByName (and of metricHashes if checks are
  		// enabled). Most likely not worth it.
  		desc := metric.Desc()
  		dtoMetric := &dto.Metric{}
  		if err := metric.Write(dtoMetric); err != nil {
  			errs = append(errs, fmt.Errorf(
  				"error collecting metric %v: %s", desc, err,
  			))
  			continue
  		}
  		metricFamily, ok := metricFamiliesByName[desc.fqName]
  		if ok {
  			if metricFamily.GetHelp() != desc.help {
  				errs = append(errs, fmt.Errorf(
  					"collected metric %s %s has help %q but should have %q",
  					desc.fqName, dtoMetric, desc.help, metricFamily.GetHelp(),
  				))
  				continue
  			}
  			// TODO(beorn7): Simplify switch once Desc has type.
  			switch metricFamily.GetType() {
  			case dto.MetricType_COUNTER:
  				if dtoMetric.Counter == nil {
  					errs = append(errs, fmt.Errorf(
  						"collected metric %s %s should be a Counter",
  						desc.fqName, dtoMetric,
  					))
  					continue
  				}
  			case dto.MetricType_GAUGE:
  				if dtoMetric.Gauge == nil {
  					errs = append(errs, fmt.Errorf(
  						"collected metric %s %s should be a Gauge",
  						desc.fqName, dtoMetric,
  					))
  					continue
  				}
  			case dto.MetricType_SUMMARY:
  				if dtoMetric.Summary == nil {
  					errs = append(errs, fmt.Errorf(
  						"collected metric %s %s should be a Summary",
  						desc.fqName, dtoMetric,
  					))
  					continue
  				}
  			case dto.MetricType_UNTYPED:
  				if dtoMetric.Untyped == nil {
  					errs = append(errs, fmt.Errorf(
  						"collected metric %s %s should be Untyped",
  						desc.fqName, dtoMetric,
  					))
  					continue
  				}
  			case dto.MetricType_HISTOGRAM:
  				if dtoMetric.Histogram == nil {
  					errs = append(errs, fmt.Errorf(
  						"collected metric %s %s should be a Histogram",
  						desc.fqName, dtoMetric,
  					))
  					continue
  				}
  			default:
  				panic("encountered MetricFamily with invalid type")
  			}
  		} else {
  			metricFamily = &dto.MetricFamily{}
  			metricFamily.Name = proto.String(desc.fqName)
  			metricFamily.Help = proto.String(desc.help)
  			// TODO(beorn7): Simplify switch once Desc has type.
  			switch {
  			case dtoMetric.Gauge != nil:
  				metricFamily.Type = dto.MetricType_GAUGE.Enum()
  			case dtoMetric.Counter != nil:
  				metricFamily.Type = dto.MetricType_COUNTER.Enum()
  			case dtoMetric.Summary != nil:
  				metricFamily.Type = dto.MetricType_SUMMARY.Enum()
  			case dtoMetric.Untyped != nil:
  				metricFamily.Type = dto.MetricType_UNTYPED.Enum()
  			case dtoMetric.Histogram != nil:
  				metricFamily.Type = dto.MetricType_HISTOGRAM.Enum()
  			default:
  				errs = append(errs, fmt.Errorf(
  					"empty metric collected: %s", dtoMetric,
  				))
  				continue
  			}
  			metricFamiliesByName[desc.fqName] = metricFamily
  		}
  		if err := checkMetricConsistency(metricFamily, dtoMetric, metricHashes, dimHashes); err != nil {
  			errs = append(errs, err)
  			continue
  		}
  		if r.pedanticChecksEnabled {
  			// Is the desc registered at all?
  			if _, exist := registeredDescIDs[desc.id]; !exist {
  				errs = append(errs, fmt.Errorf(
  					"collected metric %s %s with unregistered descriptor %s",
  					metricFamily.GetName(), dtoMetric, desc,
  				))
  				continue
  			}
  			if err := checkDescConsistency(metricFamily, dtoMetric, desc); err != nil {
  				errs = append(errs, err)
  				continue
  			}
  		}
  		metricFamily.Metric = append(metricFamily.Metric, dtoMetric)
  	}
  	return normalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap()
  }
  
  // Gatherers is a slice of Gatherer instances that implements the Gatherer
  // interface itself. Its Gather method calls Gather on all Gatherers in the
  // slice in order and returns the merged results. Errors returned from the
  // Gather calles are all returned in a flattened MultiError. Duplicate and
  // inconsistent Metrics are skipped (first occurrence in slice order wins) and
  // reported in the returned error.
  //
  // Gatherers can be used to merge the Gather results from multiple
  // Registries. It also provides a way to directly inject existing MetricFamily
  // protobufs into the gathering by creating a custom Gatherer with a Gather
  // method that simply returns the existing MetricFamily protobufs. Note that no
  // registration is involved (in contrast to Collector registration), so
  // obviously registration-time checks cannot happen. Any inconsistencies between
  // the gathered MetricFamilies are reported as errors by the Gather method, and
  // inconsistent Metrics are dropped. Invalid parts of the MetricFamilies
  // (e.g. syntactically invalid metric or label names) will go undetected.
  type Gatherers []Gatherer
  
  // Gather implements Gatherer.
  func (gs Gatherers) Gather() ([]*dto.MetricFamily, error) {
  	var (
  		metricFamiliesByName = map[string]*dto.MetricFamily{}
  		metricHashes         = map[uint64]struct{}{}
  		dimHashes            = map[string]uint64{}
  		errs                 MultiError // The collected errors to return in the end.
  	)
  
  	for i, g := range gs {
  		mfs, err := g.Gather()
  		if err != nil {
  			if multiErr, ok := err.(MultiError); ok {
  				for _, err := range multiErr {
  					errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err))
  				}
  			} else {
  				errs = append(errs, fmt.Errorf("[from Gatherer #%d] %s", i+1, err))
  			}
  		}
  		for _, mf := range mfs {
  			existingMF, exists := metricFamiliesByName[mf.GetName()]
  			if exists {
  				if existingMF.GetHelp() != mf.GetHelp() {
  					errs = append(errs, fmt.Errorf(
  						"gathered metric family %s has help %q but should have %q",
  						mf.GetName(), mf.GetHelp(), existingMF.GetHelp(),
  					))
  					continue
  				}
  				if existingMF.GetType() != mf.GetType() {
  					errs = append(errs, fmt.Errorf(
  						"gathered metric family %s has type %s but should have %s",
  						mf.GetName(), mf.GetType(), existingMF.GetType(),
  					))
  					continue
  				}
  			} else {
  				existingMF = &dto.MetricFamily{}
  				existingMF.Name = mf.Name
  				existingMF.Help = mf.Help
  				existingMF.Type = mf.Type
  				metricFamiliesByName[mf.GetName()] = existingMF
  			}
  			for _, m := range mf.Metric {
  				if err := checkMetricConsistency(existingMF, m, metricHashes, dimHashes); err != nil {
  					errs = append(errs, err)
  					continue
  				}
  				existingMF.Metric = append(existingMF.Metric, m)
  			}
  		}
  	}
  	return normalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap()
  }
  
  // metricSorter is a sortable slice of *dto.Metric.
  type metricSorter []*dto.Metric
  
  func (s metricSorter) Len() int {
  	return len(s)
  }
  
  func (s metricSorter) Swap(i, j int) {
  	s[i], s[j] = s[j], s[i]
  }
  
  func (s metricSorter) Less(i, j int) bool {
  	if len(s[i].Label) != len(s[j].Label) {
  		// This should not happen. The metrics are
  		// inconsistent. However, we have to deal with the fact, as
  		// people might use custom collectors or metric family injection
  		// to create inconsistent metrics. So let's simply compare the
  		// number of labels in this case. That will still yield
  		// reproducible sorting.
  		return len(s[i].Label) < len(s[j].Label)
  	}
  	for n, lp := range s[i].Label {
  		vi := lp.GetValue()
  		vj := s[j].Label[n].GetValue()
  		if vi != vj {
  			return vi < vj
  		}
  	}
  
  	// We should never arrive here. Multiple metrics with the same
  	// label set in the same scrape will lead to undefined ingestion
  	// behavior. However, as above, we have to provide stable sorting
  	// here, even for inconsistent metrics. So sort equal metrics
  	// by their timestamp, with missing timestamps (implying "now")
  	// coming last.
  	if s[i].TimestampMs == nil {
  		return false
  	}
  	if s[j].TimestampMs == nil {
  		return true
  	}
  	return s[i].GetTimestampMs() < s[j].GetTimestampMs()
  }
  
  // normalizeMetricFamilies returns a MetricFamily slice whith empty
  // MetricFamilies pruned and the remaining MetricFamilies sorted by name within
  // the slice, with the contained Metrics sorted within each MetricFamily.
  func normalizeMetricFamilies(metricFamiliesByName map[string]*dto.MetricFamily) []*dto.MetricFamily {
  	for _, mf := range metricFamiliesByName {
  		sort.Sort(metricSorter(mf.Metric))
  	}
  	names := make([]string, 0, len(metricFamiliesByName))
  	for name, mf := range metricFamiliesByName {
  		if len(mf.Metric) > 0 {
  			names = append(names, name)
  		}
  	}
  	sort.Strings(names)
  	result := make([]*dto.MetricFamily, 0, len(names))
  	for _, name := range names {
  		result = append(result, metricFamiliesByName[name])
  	}
  	return result
  }
  
  // checkMetricConsistency checks if the provided Metric is consistent with the
  // provided MetricFamily. It also hashed the Metric labels and the MetricFamily
  // name. If the resulting hash is alread in the provided metricHashes, an error
  // is returned. If not, it is added to metricHashes. The provided dimHashes maps
  // MetricFamily names to their dimHash (hashed sorted label names). If dimHashes
  // doesn't yet contain a hash for the provided MetricFamily, it is
  // added. Otherwise, an error is returned if the existing dimHashes in not equal
  // the calculated dimHash.
  func checkMetricConsistency(
  	metricFamily *dto.MetricFamily,
  	dtoMetric *dto.Metric,
  	metricHashes map[uint64]struct{},
  	dimHashes map[string]uint64,
  ) error {
  	// Type consistency with metric family.
  	if metricFamily.GetType() == dto.MetricType_GAUGE && dtoMetric.Gauge == nil ||
  		metricFamily.GetType() == dto.MetricType_COUNTER && dtoMetric.Counter == nil ||
  		metricFamily.GetType() == dto.MetricType_SUMMARY && dtoMetric.Summary == nil ||
  		metricFamily.GetType() == dto.MetricType_HISTOGRAM && dtoMetric.Histogram == nil ||
  		metricFamily.GetType() == dto.MetricType_UNTYPED && dtoMetric.Untyped == nil {
  		return fmt.Errorf(
  			"collected metric %s %s is not a %s",
  			metricFamily.GetName(), dtoMetric, metricFamily.GetType(),
  		)
  	}
  
  	// Is the metric unique (i.e. no other metric with the same name and the same label values)?
  	h := hashNew()
  	h = hashAdd(h, metricFamily.GetName())
  	h = hashAddByte(h, separatorByte)
  	dh := hashNew()
  	// Make sure label pairs are sorted. We depend on it for the consistency
  	// check.
  	sort.Sort(LabelPairSorter(dtoMetric.Label))
  	for _, lp := range dtoMetric.Label {
  		h = hashAdd(h, lp.GetValue())
  		h = hashAddByte(h, separatorByte)
  		dh = hashAdd(dh, lp.GetName())
  		dh = hashAddByte(dh, separatorByte)
  	}
  	if _, exists := metricHashes[h]; exists {
  		return fmt.Errorf(
  			"collected metric %s %s was collected before with the same name and label values",
  			metricFamily.GetName(), dtoMetric,
  		)
  	}
  	if dimHash, ok := dimHashes[metricFamily.GetName()]; ok {
  		if dimHash != dh {
  			return fmt.Errorf(
  				"collected metric %s %s has label dimensions inconsistent with previously collected metrics in the same metric family",
  				metricFamily.GetName(), dtoMetric,
  			)
  		}
  	} else {
  		dimHashes[metricFamily.GetName()] = dh
  	}
  	metricHashes[h] = struct{}{}
  	return nil
  }
  
  func checkDescConsistency(
  	metricFamily *dto.MetricFamily,
  	dtoMetric *dto.Metric,
  	desc *Desc,
  ) error {
  	// Desc help consistency with metric family help.
  	if metricFamily.GetHelp() != desc.help {
  		return fmt.Errorf(
  			"collected metric %s %s has help %q but should have %q",
  			metricFamily.GetName(), dtoMetric, metricFamily.GetHelp(), desc.help,
  		)
  	}
  
  	// Is the desc consistent with the content of the metric?
  	lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label))
  	lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...)
  	for _, l := range desc.variableLabels {
  		lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{
  			Name: proto.String(l),
  		})
  	}
  	if len(lpsFromDesc) != len(dtoMetric.Label) {
  		return fmt.Errorf(
  			"labels in collected metric %s %s are inconsistent with descriptor %s",
  			metricFamily.GetName(), dtoMetric, desc,
  		)
  	}
  	sort.Sort(LabelPairSorter(lpsFromDesc))
  	for i, lpFromDesc := range lpsFromDesc {
  		lpFromMetric := dtoMetric.Label[i]
  		if lpFromDesc.GetName() != lpFromMetric.GetName() ||
  			lpFromDesc.Value != nil && lpFromDesc.GetValue() != lpFromMetric.GetValue() {
  			return fmt.Errorf(
  				"labels in collected metric %s %s are inconsistent with descriptor %s",
  				metricFamily.GetName(), dtoMetric, desc,
  			)
  		}
  	}
  	return nil
  }
  