Remove implicit Prometheus metrics from client

pull/6/head
Kris 2016-08-15 11:31:44 -07:00
parent ea805efa4f
commit 8d6ce0dcc6
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)