func (r *Reporter) listTagKeys(tags metrics.Tags) (labelKeys []string) {
	for key := range tags {
		labelKeys = append(labelKeys, key)
	}
	return
}
listTagKeys returns a list of tag keys (we need to provide this to the Prometheus client):
package prometheus
import (
	"net/http"
	"strings"
	log "github.com/micro/micro/v3/service/logger"
	"github.com/micro/micro/v3/service/metrics"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
	quantileThresholds = map[float64]float64{0.0: 0, 0.5: 0.05, 0.75: 0.04, 0.90: 0.03, 0.95: 0.02, 0.98: 0.001, 0.99: 0.001, 1: 0}
)
type Reporter struct {
	options            metrics.Options
	prometheusRegistry *prometheus.Registry
	metrics            metricFamily
}
func New(opts ...metrics.Option) (*Reporter, error) {
	options := metrics.NewOptions(opts...)
	prometheusRegistry := prometheus.NewRegistry()
	prometheusRegistry.Register(prometheus.NewGoCollector())
	prometheusRegistry.Register(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{Namespace: "goruntime"}))
	newReporter := &Reporter{
		options:            options,
		prometheusRegistry: prometheusRegistry,
	}
	newReporter.metrics = newReporter.newMetricFamily()
	log.Infof("Metrics/Prometheus [http] Listening on %s%s", options.Address, options.Path)
	http.Handle(options.Path, promhttp.HandlerFor(prometheusRegistry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError}))
	go http.ListenAndServe(options.Address, nil)
	return newReporter, nil
}
func (r *Reporter) convertTags(tags metrics.Tags) prometheus.Labels {
	labels := prometheus.Labels{}
	for key, value := range tags {
		labels[key] = r.stripUnsupportedCharacters(value)
	}
	return labels
}