Merge pull request #30638 from krousey/metrics_registration

Automatic merge from submit-queue

Remove implicit Prometheus metrics from client

**What this PR does / why we need it**: This PR starts to cut away at dependencies that the client has.

**Release note**:
<!--  Steps to write your release note:
1. Use the release-note-* labels to set the release note state (if you have access) 
2. Enter your extended release note in the below block; leaving it blank means using the PR title as the release note. If no release note is required, just write `NONE`. 
-->
```release-note
The implicit registration of Prometheus metrics for request count and latency have been removed, and a plug-able interface was added. If you were using our client libraries in your own binaries and want these metrics, add the following to your imports in the main package: "k8s.io/pkg/client/metrics/prometheus". 
```

cc: @kubernetes/sig-api-machinery @kubernetes/sig-instrumentation @fgrzadkowski  @wojtek-t
This commit is contained in:
Kubernetes Submit Queue 2016-08-21 16:47:05 -07:00 committed by GitHub
commit b51d5c3cc0
14 changed files with 129 additions and 48 deletions

View File

@ -23,6 +23,8 @@ package main
import ( import (
"os" "os"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
) )
func main() { func main() {

View File

@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/cmd/kube-apiserver/app" "k8s.io/kubernetes/cmd/kube-apiserver/app"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options" "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/util/flag" "k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/logs" "k8s.io/kubernetes/pkg/util/logs"
"k8s.io/kubernetes/pkg/version/verflag" "k8s.io/kubernetes/pkg/version/verflag"

View File

@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/cmd/kube-controller-manager/app" "k8s.io/kubernetes/cmd/kube-controller-manager/app"
"k8s.io/kubernetes/cmd/kube-controller-manager/app/options" "k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/healthz" "k8s.io/kubernetes/pkg/healthz"
"k8s.io/kubernetes/pkg/util/flag" "k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/logs" "k8s.io/kubernetes/pkg/util/logs"

View File

@ -20,6 +20,7 @@ import (
"github.com/spf13/pflag" "github.com/spf13/pflag"
"k8s.io/kubernetes/cmd/kube-dns/app" "k8s.io/kubernetes/cmd/kube-dns/app"
"k8s.io/kubernetes/cmd/kube-dns/app/options" "k8s.io/kubernetes/cmd/kube-dns/app/options"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/util/flag" "k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/logs" "k8s.io/kubernetes/pkg/util/logs"
"k8s.io/kubernetes/pkg/version/verflag" "k8s.io/kubernetes/pkg/version/verflag"

View File

@ -22,6 +22,7 @@ import (
"k8s.io/kubernetes/cmd/kube-proxy/app" "k8s.io/kubernetes/cmd/kube-proxy/app"
"k8s.io/kubernetes/cmd/kube-proxy/app/options" "k8s.io/kubernetes/cmd/kube-proxy/app/options"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/healthz" "k8s.io/kubernetes/pkg/healthz"
"k8s.io/kubernetes/pkg/util/flag" "k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/logs" "k8s.io/kubernetes/pkg/util/logs"

View File

@ -19,6 +19,7 @@ package app
import ( import (
"os" "os"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/kubectl/cmd" "k8s.io/kubernetes/pkg/kubectl/cmd"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/util/logs" "k8s.io/kubernetes/pkg/util/logs"

View File

@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/cmd/kubelet/app" "k8s.io/kubernetes/cmd/kubelet/app"
"k8s.io/kubernetes/cmd/kubelet/app/options" "k8s.io/kubernetes/cmd/kubelet/app/options"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/util/flag" "k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/logs" "k8s.io/kubernetes/pkg/util/logs"
"k8s.io/kubernetes/pkg/version/verflag" "k8s.io/kubernetes/pkg/version/verflag"

View File

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/client/record" "k8s.io/kubernetes/pkg/client/record"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
clientset "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset" clientset "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset"

View File

@ -19,6 +19,8 @@ package main
import ( import (
"os" "os"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
) )
func main() { func main() {

View File

@ -74,6 +74,8 @@ pkg/apis/imagepolicy/install
pkg/api/v1 pkg/api/v1
pkg/auth/authenticator pkg/auth/authenticator
pkg/auth/authorizer/union pkg/auth/authorizer/union
pkg/client/metrics
pkg/client/metrics/prometheus
pkg/client/testing/core pkg/client/testing/core
pkg/client/unversioned pkg/client/unversioned
pkg/client/unversioned/adapters/internalclientset pkg/client/unversioned/adapters/internalclientset

View File

@ -14,54 +14,48 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
// Package metrics provides utilities for registering client metrics to Prometheus. // Package metrics provides abstractions for registering which metrics
// to record.
package metrics package metrics
import ( import (
"net/url"
"sync" "sync"
"time" "time"
"github.com/prometheus/client_golang/prometheus"
)
const restClientSubsystem = "rest_client"
var (
// RequestLatency is a Prometheus Summary metric type partitioned by
// "verb" and "url" labels. It is used for the rest client latency metrics.
RequestLatency = prometheus.NewSummaryVec(
prometheus.SummaryOpts{
Subsystem: restClientSubsystem,
Name: "request_latency_microseconds",
Help: "Request latency in microseconds. Broken down by verb and URL",
MaxAge: time.Hour,
},
[]string{"verb", "url"},
)
RequestResult = prometheus.NewCounterVec(
prometheus.CounterOpts{
Subsystem: restClientSubsystem,
Name: "request_status_codes",
Help: "Number of http requests, partitioned by metadata",
},
[]string{"code", "method", "host"},
)
) )
var registerMetrics sync.Once var registerMetrics sync.Once
// Register registers all metrics to Prometheus with // LatencyMetric observes client latency partitioned by verb and url.
// respect to the RequestLatency. type LatencyMetric interface {
func Register() { Observe(verb string, u url.URL, latency time.Duration)
// Register the metrics. }
// ResultMetric counts response codes partitioned by method and host.
type ResultMetric interface {
Increment(code string, method string, host string)
}
var (
// RequestLatency is the latency metric that rest clients will update.
RequestLatency LatencyMetric = noopLatency{}
// RequestResult is the result metric that rest clients will update.
RequestResult ResultMetric = noopResult{}
)
// Register registers metrics for the rest client to use. This can
// only be called once.
func Register(lm LatencyMetric, rm ResultMetric) {
registerMetrics.Do(func() { registerMetrics.Do(func() {
prometheus.MustRegister(RequestLatency) RequestLatency = lm
prometheus.MustRegister(RequestResult) RequestResult = rm
}) })
} }
// Calculates the time since the specified start in microseconds. type noopLatency struct{}
func SinceInMicroseconds(start time.Time) float64 {
return float64(time.Since(start).Nanoseconds() / time.Microsecond.Nanoseconds()) func (noopLatency) Observe(string, url.URL, time.Duration) {}
}
type noopResult struct{}
func (noopResult) Increment(string, string, string) {}

View File

@ -0,0 +1,76 @@
/*
Copyright 2016 The Kubernetes 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 creates and registers prometheus metrics with
// rest clients. To use this package, you just have to import it.
package prometheus
import (
"net/url"
"time"
"k8s.io/kubernetes/pkg/client/metrics"
"github.com/prometheus/client_golang/prometheus"
)
const restClientSubsystem = "rest_client"
var (
// requestLatency is a Prometheus Summary metric type partitioned by
// "verb" and "url" labels. It is used for the rest client latency metrics.
requestLatency = prometheus.NewSummaryVec(
prometheus.SummaryOpts{
Subsystem: restClientSubsystem,
Name: "request_latency_microseconds",
Help: "Request latency in microseconds. Broken down by verb and URL",
MaxAge: time.Hour,
},
[]string{"verb", "url"},
)
requestResult = prometheus.NewCounterVec(
prometheus.CounterOpts{
Subsystem: restClientSubsystem,
Name: "request_status_codes",
Help: "Number of http requests, partitioned by metadata",
},
[]string{"code", "method", "host"},
)
)
func init() {
prometheus.MustRegister(requestLatency)
prometheus.MustRegister(requestResult)
metrics.Register(&latencyAdapter{requestLatency}, &resultAdapter{requestResult})
}
type latencyAdapter struct {
m *prometheus.SummaryVec
}
func (l *latencyAdapter) Observe(verb string, u url.URL, latency time.Duration) {
microseconds := float64(latency) / float64(time.Microsecond)
l.m.WithLabelValues(verb, u.String()).Observe(microseconds)
}
type resultAdapter struct {
m *prometheus.CounterVec
}
func (r *resultAdapter) Increment(code, method, host string) {
r.m.WithLabelValues(code, method, host).Inc()
}

View File

@ -58,10 +58,6 @@ var (
longThrottleLatency = 50 * time.Millisecond longThrottleLatency = 50 * time.Millisecond
) )
func init() {
metrics.Register()
}
// HTTPClient is an interface for testing a request object. // HTTPClient is an interface for testing a request object.
type HTTPClient interface { type HTTPClient interface {
Do(req *http.Request) (*http.Response, error) Do(req *http.Request) (*http.Response, error)
@ -609,7 +605,7 @@ func (r *Request) URL() *url.URL {
// underyling object. This means some useful request info (like the types of field // underyling object. This means some useful request info (like the types of field
// selectors in use) will be lost. // selectors in use) will be lost.
// TODO: preserve field selector keys // TODO: preserve field selector keys
func (r Request) finalURLTemplate() string { func (r Request) finalURLTemplate() url.URL {
if len(r.resourceName) != 0 { if len(r.resourceName) != 0 {
r.resourceName = "{name}" r.resourceName = "{name}"
} }
@ -622,7 +618,8 @@ func (r Request) finalURLTemplate() string {
newParams[k] = v newParams[k] = v
} }
r.params = newParams r.params = newParams
return r.URL().String() url := r.URL()
return *url
} }
func (r *Request) tryThrottle() { func (r *Request) tryThrottle() {
@ -697,10 +694,10 @@ func updateURLMetrics(req *Request, resp *http.Response, err error) {
// If we have an error (i.e. apiserver down) we report that as a metric label. // If we have an error (i.e. apiserver down) we report that as a metric label.
if err != nil { if err != nil {
metrics.RequestResult.WithLabelValues(err.Error(), req.verb, url).Inc() metrics.RequestResult.Increment(err.Error(), req.verb, url)
} else { } else {
//Metrics for failure codes //Metrics for failure codes
metrics.RequestResult.WithLabelValues(strconv.Itoa(resp.StatusCode), req.verb, url).Inc() metrics.RequestResult.Increment(strconv.Itoa(resp.StatusCode), req.verb, url)
} }
} }
@ -775,7 +772,7 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
//Metrics for total request latency //Metrics for total request latency
start := time.Now() start := time.Now()
defer func() { defer func() {
metrics.RequestLatency.WithLabelValues(r.verb, r.finalURLTemplate()).Observe(metrics.SinceInMicroseconds(start)) metrics.RequestLatency.Observe(r.verb, r.finalURLTemplate(), time.Since(start))
}() }()
if r.err != nil { if r.err != nil {

View File

@ -331,7 +331,8 @@ func TestURLTemplate(t *testing.T) {
if full.String() != "http://localhost/pre1/namespaces/ns/r1/nm?p0=v0" { if full.String() != "http://localhost/pre1/namespaces/ns/r1/nm?p0=v0" {
t.Errorf("unexpected initial URL: %s", full) t.Errorf("unexpected initial URL: %s", full)
} }
actual := r.finalURLTemplate() actualURL := r.finalURLTemplate()
actual := actualURL.String()
expected := "http://localhost/pre1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D?p0=%7Bvalue%7D" expected := "http://localhost/pre1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D?p0=%7Bvalue%7D"
if actual != expected { if actual != expected {
t.Errorf("unexpected URL template: %s %s", actual, expected) t.Errorf("unexpected URL template: %s %s", actual, expected)