diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index dc8f9db1125..738639eb257 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -23,6 +23,7 @@ import ( "io/ioutil" "net/http" "path" + "strconv" "strings" "time" @@ -42,17 +43,34 @@ import ( ) var ( - apiserverLatencies = prometheus.NewSummaryVec( + // TODO(a-robinson): Add unit tests for the handling of these metrics once + // the upstream library supports it. + requestCounter = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "apiserver_request_count", + Help: "Counter of apiserver requests broken out for each request handler, verb, API resource, and HTTP response code.", + }, + []string{"handler", "verb", "resource", "code"}, + ) + requestLatencies = prometheus.NewSummaryVec( prometheus.SummaryOpts{ Name: "apiserver_request_latencies", - Help: "Response latency summary in microseconds for each request handler, verb, and HTTP response code.", + Help: "Response latency summary in microseconds for each request handler and verb.", }, - []string{"handler", "verb", "code"}, + []string{"handler", "verb"}, ) ) func init() { - prometheus.MustRegister(apiserverLatencies) + prometheus.MustRegister(requestCounter) + prometheus.MustRegister(requestLatencies) +} + +// monitor is a helper function for each HTTP request handler to use for +// instrumenting basic request counter and latency metrics. +func monitor(handler, verb, resource string, httpCode int, reqStart time.Time) { + requestCounter.WithLabelValues(handler, verb, resource, strconv.Itoa(httpCode)).Inc() + requestLatencies.WithLabelValues(handler, verb).Observe(float64((time.Since(reqStart)) / time.Microsecond)) } // mux is an object that can register http handlers. diff --git a/pkg/apiserver/redirect.go b/pkg/apiserver/redirect.go index 48717808b98..f484f9e7548 100644 --- a/pkg/apiserver/redirect.go +++ b/pkg/apiserver/redirect.go @@ -18,31 +18,14 @@ package apiserver import ( "net/http" - "strconv" "time" "github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" "github.com/GoogleCloudPlatform/kubernetes/pkg/httplog" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" - - "github.com/prometheus/client_golang/prometheus" ) -var ( - redirectCounter = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "apiserver_redirect_count", - Help: "Counter of redirect requests broken out by apiserver resource and HTTP response code.", - }, - []string{"resource", "code"}, - ) -) - -func init() { - prometheus.MustRegister(redirectCounter) -} - type RedirectHandler struct { storage map[string]RESTStorage codec runtime.Codec @@ -50,13 +33,11 @@ type RedirectHandler struct { } func (r *RedirectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - apiResource := "" + var verb string + var apiResource string var httpCode int reqStart := time.Now() - defer func() { - redirectCounter.WithLabelValues(apiResource, strconv.Itoa(httpCode)).Inc() - apiserverLatencies.WithLabelValues("redirect", "get", strconv.Itoa(httpCode)).Observe(float64((time.Since(reqStart)) / time.Microsecond)) - }() + defer func() { monitor("redirect", verb, apiResource, httpCode, reqStart) }() requestInfo, err := r.apiRequestInfoResolver.GetAPIRequestInfo(req) if err != nil { @@ -64,6 +45,7 @@ func (r *RedirectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { httpCode = http.StatusNotFound return } + verb = requestInfo.Verb resource, parts := requestInfo.Resource, requestInfo.Parts ctx := api.WithNamespace(api.NewContext(), requestInfo.Namespace) @@ -78,7 +60,6 @@ func (r *RedirectHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { if !ok { httplog.LogOf(req, w).Addf("'%v' has no storage object", resource) notFound(w, req) - apiResource = "invalidResource" httpCode = http.StatusNotFound return } diff --git a/pkg/apiserver/resthandler.go b/pkg/apiserver/resthandler.go index e5f50c44141..9a8a7a79194 100644 --- a/pkg/apiserver/resthandler.go +++ b/pkg/apiserver/resthandler.go @@ -19,7 +19,6 @@ package apiserver import ( "net/http" "path" - "strconv" "time" "github.com/GoogleCloudPlatform/kubernetes/pkg/admission" @@ -29,23 +28,8 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" "github.com/golang/glog" - "github.com/prometheus/client_golang/prometheus" ) -var ( - restCounter = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "apiserver_rest_count", - Help: "Counter of REST requests broken out for each verb, apiserver resource, and HTTP response code.", - }, - []string{"verb", "resource", "code"}, - ) -) - -func init() { - prometheus.MustRegister(restCounter) -} - // RESTHandler implements HTTP verbs on a set of RESTful resources identified by name. type RESTHandler struct { storage map[string]RESTStorage @@ -59,14 +43,11 @@ type RESTHandler struct { // ServeHTTP handles requests to all RESTStorage objects. func (h *RESTHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - verb := "" - apiResource := "" + var verb string + var apiResource string var httpCode int reqStart := time.Now() - defer func() { - restCounter.WithLabelValues(verb, apiResource, strconv.Itoa(httpCode)).Inc() - apiserverLatencies.WithLabelValues("rest", verb, strconv.Itoa(httpCode)).Observe(float64((time.Since(reqStart)) / time.Microsecond)) - }() + defer func() { monitor("rest", verb, apiResource, httpCode, reqStart) }() requestInfo, err := h.apiRequestInfoResolver.GetAPIRequestInfo(req) if err != nil {