diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go index d3f155c11f..a72a9bc4ac 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/metrics/metrics.go @@ -18,12 +18,12 @@ package metrics import ( "bufio" - //"fmt" "net" "net/http" "regexp" "strconv" "strings" + "sync" "time" utilnet "k8s.io/apimachinery/pkg/util/net" @@ -33,6 +33,13 @@ import ( "github.com/prometheus/client_golang/prometheus" ) +// resettableCollector is the interface implemented by prometheus.MetricVec +// that can be used by Prometheus to collect metrics and reset their values. +type resettableCollector interface { + prometheus.Collector + Reset() +} + var ( // TODO(a-robinson): Add unit tests for the handling of these metrics once // the upstream library supports it. @@ -96,6 +103,16 @@ var ( []string{"requestKind"}, ) kubectlExeRegexp = regexp.MustCompile(`^.*((?i:kubectl\.exe))`) + + metrics = []resettableCollector{ + requestCounter, + longRunningRequestGauge, + requestLatencies, + requestLatenciesSummary, + responseSizes, + DroppedRequests, + currentInflightRequests, + } ) const ( @@ -105,15 +122,22 @@ const ( MutatingKind = "mutating" ) -func init() { - // Register all metrics. - prometheus.MustRegister(requestCounter) - prometheus.MustRegister(longRunningRequestGauge) - prometheus.MustRegister(requestLatencies) - prometheus.MustRegister(requestLatenciesSummary) - prometheus.MustRegister(responseSizes) - prometheus.MustRegister(DroppedRequests) - prometheus.MustRegister(currentInflightRequests) +var registerMetrics sync.Once + +// Register all metrics. +func Register() { + registerMetrics.Do(func() { + for _, metric := range metrics { + prometheus.MustRegister(metric) + } + }) +} + +// Reset all metrics. +func Reset() { + for _, metric := range metrics { + metric.Reset() + } } func UpdateInflightRequestMetrics(nonmutating, mutating int) { @@ -170,13 +194,6 @@ func MonitorRequest(req *http.Request, verb, resource, subresource, scope, conte } } -func Reset() { - requestCounter.Reset() - requestLatencies.Reset() - requestLatenciesSummary.Reset() - responseSizes.Reset() -} - // InstrumentRouteFunc works like Prometheus' InstrumentHandlerFunc but wraps // the go-restful RouteFunction instead of a HandlerFunc plus some Kubernetes endpoint specific information. func InstrumentRouteFunc(verb, resource, subresource, scope string, routeFunc restful.RouteFunction) restful.RouteFunction { diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/metrics.go b/staging/src/k8s.io/apiserver/pkg/server/routes/metrics.go index 6d4e56edcb..ee158c2045 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/metrics.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/metrics.go @@ -32,6 +32,7 @@ type DefaultMetrics struct{} // Install adds the DefaultMetrics handler func (m DefaultMetrics) Install(c *mux.PathRecorderMux) { + register() c.Handle("/metrics", prometheus.Handler()) } @@ -41,6 +42,7 @@ type MetricsWithReset struct{} // Install adds the MetricsWithReset handler func (m MetricsWithReset) Install(c *mux.PathRecorderMux) { + register() defaultMetricsHandler := prometheus.Handler().ServeHTTP c.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) { if req.Method == "DELETE" { @@ -52,3 +54,9 @@ func (m MetricsWithReset) Install(c *mux.PathRecorderMux) { defaultMetricsHandler(w, req) }) } + +// register apiserver and etcd metrics +func register() { + apimetrics.Register() + etcdmetrics.Register() +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/etcd/etcd_helper.go b/staging/src/k8s.io/apiserver/pkg/storage/etcd/etcd_helper.go index 939e99fc51..3a34841f91 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/etcd/etcd_helper.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/etcd/etcd_helper.go @@ -101,10 +101,6 @@ type etcdHelper struct { cache utilcache.Cache } -func init() { - metrics.Register() -} - // Implements storage.Interface. func (h *etcdHelper) Versioner() storage.Versioner { return h.versioner