You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: go_collector_latest.go
    path of file: ./repos/trickster/vendor/github.com/prometheus/client_golang/prometheus
    
    the code of the file until where you have to start completion: // Copyright 2021 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.

//go:build go1.17
// +build go1.17

package prometheus

import (
	"math"
	"runtime"
	"runtime/metrics"
	"strings"
	"sync"

	"github.com/prometheus/client_golang/prometheus/internal"

	dto "github.com/prometheus/client_model/go"
	"google.golang.org/protobuf/proto"
)

const (
	// constants for strings referenced more than once.
	goGCHeapTinyAllocsObjects               = "/gc/heap/tiny/allocs:objects"
	goGCHeapAllocsObjects                   = "/gc/heap/allocs:objects"
	goGCHeapFreesObjects                    = "/gc/heap/frees:objects"
	goGCHeapFreesBytes                      = "/gc/heap/frees:bytes"
	goGCHeapAllocsBytes                     = "/gc/heap/allocs:bytes"
	goGCHeapObjects                         = "/gc/heap/objects:objects"
	goGCHeapGoalBytes                       = "/gc/heap/goal:bytes"
	goMemoryClassesTotalBytes               = "/memory/classes/total:bytes"
	goMemoryClassesHeapObjectsBytes         = "/memory/classes/heap/objects:bytes"
	goMemoryClassesHeapUnusedBytes          = "/memory/classes/heap/unused:bytes"
	goMemoryClassesHeapReleasedBytes        = "/memory/classes/heap/released:bytes"
	goMemoryClassesHeapFreeBytes            = "/memory/classes/heap/free:bytes"
	goMemoryClassesHeapStacksBytes          = "/memory/classes/heap/stacks:bytes"
	goMemoryClassesOSStacksBytes            = "/memory/classes/os-stacks:bytes"
	goMemoryClassesMetadataMSpanInuseBytes  = "/memory/classes/metadata/mspan/inuse:bytes"
	goMemoryClassesMetadataMSPanFreeBytes   = "/memory/classes/metadata/mspan/free:bytes"
	goMemoryClassesMetadataMCacheInuseBytes = "/memory/classes/metadata/mcache/inuse:bytes"
	goMemoryClassesMetadataMCacheFreeBytes  = "/memory/classes/metadata/mcache/free:bytes"
	goMemoryClassesProfilingBucketsBytes    = "/memory/classes/profiling/buckets:bytes"
	goMemoryClassesMetadataOtherBytes       = "/memory/classes/metadata/other:bytes"
	goMemoryClassesOtherBytes               = "/memory/classes/other:bytes"
)

// rmNamesForMemStatsMetrics represents runtime/metrics names required to populate goRuntimeMemStats from like logic.
var rmNamesForMemStatsMetrics = []string{
	goGCHeapTinyAllocsObjects,
	goGCHeapAllocsObjects,
	goGCHeapFreesObjects,
	goGCHeapAllocsBytes,
	goGCHeapObjects,
	goGCHeapGoalBytes,
	goMemoryClassesTotalBytes,
	goMemoryClassesHeapObjectsBytes,
	goMemoryClassesHeapUnusedBytes,
	goMemoryClassesHeapReleasedBytes,
	goMemoryClassesHeapFreeBytes,
	goMemoryClassesHeapStacksBytes,
	goMemoryClassesOSStacksBytes,
	goMemoryClassesMetadataMSpanInuseBytes,
	goMemoryClassesMetadataMSPanFreeBytes,
	goMemoryClassesMetadataMCacheInuseBytes,
	goMemoryClassesMetadataMCacheFreeBytes,
	goMemoryClassesProfilingBucketsBytes,
	goMemoryClassesMetadataOtherBytes,
	goMemoryClassesOtherBytes,
}

func bestEffortLookupRM(lookup []string) []metrics.Description {
	ret := make([]metrics.Description, 0, len(lookup))
	for _, rm := range metrics.All() {
		for _, m := range lookup {
			if m == rm.Name {
    
func NewGoCollector(opts ...func(o *internal.GoCollectorOptions)) Collector {
	opt := defaultGoCollectorOptions()
	for _, o := range opts {
		o(&opt)
	}

	exposedDescriptions := matchRuntimeMetricsRules(opt.RuntimeMetricRules)

	// Collect all histogram samples so that we can get their buckets.
	// The API guarantees that the buckets are always fixed for the lifetime
	// of the process.
	var histograms []metrics.Sample
	for _, d := range exposedDescriptions {
		if d.Kind == metrics.KindFloat64Histogram {
			histograms = append(histograms, metrics.Sample{Name: d.Name})
		}
	}

	if len(histograms) > 0 {
		metrics.Read(histograms)
	}

	bucketsMap := make(map[string][]float64)
	for i := range histograms {
		bucketsMap[histograms[i].Name] = histograms[i].Value.Float64Histogram().Buckets
	}

	// Generate a collector for each exposed runtime/metrics metric.
	metricSet := make([]collectorMetric, 0, len(exposedDescriptions))
	// SampleBuf is used for reading from runtime/metrics.
	// We are assuming the largest case to have stable pointers for sampleMap purposes.
	sampleBuf := make([]metrics.Sample, 0, len(exposedDescriptions)+len(opt.RuntimeMetricSumForHist)+len(rmNamesForMemStatsMetrics))
	sampleMap := make(map[string]*metrics.Sample, len(exposedDescriptions))
	for _, d := range exposedDescriptions {
		namespace, subsystem, name, ok := internal.RuntimeMetricsToProm(&d.Description)
		if !ok {
			// Just ignore this metric; we can't do anything with it here.
			// If a user decides to use the latest version of Go, we don't want
			// to fail here. This condition is tested in TestExpectedRuntimeMetrics.
			continue
		}

		sampleBuf = append(sampleBuf, metrics.Sample{Name: d.Name})
		sampleMap[d.Name] = &sampleBuf[len(sampleBuf)-1]

		var m collectorMetric
		if d.Kind == metrics.KindFloat64Histogram {
			_, hasSum := opt.RuntimeMetricSumForHist[d.Name]
			unit := d.Name[strings.IndexRune(d.Name, ':')+1:]
			m = newBatchHistogram(
				NewDesc(
					BuildFQName(namespace, subsystem, name),
					d.Description.Description,
					nil,
					nil,
				),
				internal.RuntimeMetricsBucketsForUnit(bucketsMap[d.Name], unit),
				hasSum,
			)
		} else if d.Cumulative {
			m = NewCounter(CounterOpts{
				Namespace: namespace,
				Subsystem: subsystem,
				Name:      name,
				Help:      d.Description.Description,
			},
			)
		} else {
			m = NewGauge(GaugeOpts{
				Namespace: namespace,
				Subsystem: subsystem,
				Name:      name,
				Help:      d.Description.Description,
			})
		}
		metricSet = append(metricSet, m)
	}

	// Add exact sum metrics to sampleBuf if not added before.
	for _, h := range histograms {
		sumMetric, ok := opt.RuntimeMetricSumForHist[h.Name]
		if !ok {
			continue
		}

		if _, ok := sampleMap[sumMetric]; ok {
			continue
		}
		sampleBuf = append(sampleBuf, metrics.Sample{Name: sumMetric})
		sampleMap[sumMetric] = &sampleBuf[len(sampleBuf)-1]
	}

	var (
		msMetrics      memStatsMetrics
		msDescriptions []metrics.Description
	)

	if !opt.DisableMemStatsLikeMetrics {
		msMetrics = goRuntimeMemStats()
		msDescriptions = bestEffortLookupRM(rmNamesForMemStatsMetrics)

		// Check if metric was not exposed before and if not, add to sampleBuf.
		for _, mdDesc := range msDescriptions {
			if _, ok := sampleMap[mdDesc.Name]; ok {
				continue
			}
			sampleBuf = append(sampleBuf, metrics.Sample{Name: mdDesc.Name})
			sampleMap[mdDesc.Name] = &sampleBuf[len(sampleBuf)-1]
		}
	}

	return &goCollector{
		base:                 newBaseGoCollector(),
		sampleBuf:            sampleBuf,
		sampleMap:            sampleMap,
		rmExposedMetrics:     metricSet,
		rmExactSumMapForHist: opt.RuntimeMetricSumForHist,
		msMetrics:            msMetrics,
		msMetricsEnabled:     !opt.DisableMemStatsLikeMetrics,
	}
}