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 (
"os"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
)
func main() {

View File

@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/cmd/kube-apiserver/app"
"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/logs"
"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/options"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/healthz"
"k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/logs"

View File

@ -20,6 +20,7 @@ import (
"github.com/spf13/pflag"
"k8s.io/kubernetes/cmd/kube-dns/app"
"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/logs"
"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/options"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/healthz"
"k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/logs"

View File

@ -19,6 +19,7 @@ package app
import (
"os"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/kubectl/cmd"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"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/options"
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
"k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/logs"
"k8s.io/kubernetes/pkg/version/verflag"

View File

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

View File

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

View File

@ -74,6 +74,8 @@ pkg/apis/imagepolicy/install
pkg/api/v1
pkg/auth/authenticator
pkg/auth/authorizer/union
pkg/client/metrics
pkg/client/metrics/prometheus
pkg/client/testing/core
pkg/client/unversioned
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.
*/
// Package metrics provides utilities for registering client metrics to Prometheus.
// Package metrics provides abstractions for registering which metrics
// to record.
package metrics
import (
"net/url"
"sync"
"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
// Register registers all metrics to Prometheus with
// respect to the RequestLatency.
func Register() {
// Register the metrics.
// LatencyMetric observes client latency partitioned by verb and url.
type LatencyMetric interface {
Observe(verb string, u url.URL, latency time.Duration)
}
// 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() {
prometheus.MustRegister(RequestLatency)
prometheus.MustRegister(RequestResult)
RequestLatency = lm
RequestResult = rm
})
}
// Calculates the time since the specified start in microseconds.
func SinceInMicroseconds(start time.Time) float64 {
return float64(time.Since(start).Nanoseconds() / time.Microsecond.Nanoseconds())
}
type noopLatency struct{}
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
)
func init() {
metrics.Register()
}
// HTTPClient is an interface for testing a request object.
type HTTPClient interface {
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
// selectors in use) will be lost.
// TODO: preserve field selector keys
func (r Request) finalURLTemplate() string {
func (r Request) finalURLTemplate() url.URL {
if len(r.resourceName) != 0 {
r.resourceName = "{name}"
}
@ -622,7 +618,8 @@ func (r Request) finalURLTemplate() string {
newParams[k] = v
}
r.params = newParams
return r.URL().String()
url := r.URL()
return *url
}
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 err != nil {
metrics.RequestResult.WithLabelValues(err.Error(), req.verb, url).Inc()
metrics.RequestResult.Increment(err.Error(), req.verb, url)
} else {
//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
start := time.Now()
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 {

View File

@ -331,7 +331,8 @@ func TestURLTemplate(t *testing.T) {
if full.String() != "http://localhost/pre1/namespaces/ns/r1/nm?p0=v0" {
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"
if actual != expected {
t.Errorf("unexpected URL template: %s %s", actual, expected)