diff --git a/hack/verify-prometheus-imports.sh b/hack/verify-prometheus-imports.sh index 2ec5eb1204c..36ab12937ef 100755 --- a/hack/verify-prometheus-imports.sh +++ b/hack/verify-prometheus-imports.sh @@ -43,6 +43,7 @@ allowed_prometheus_importers=( ./staging/src/k8s.io/component-base/metrics/prometheusextension/weighted_histogram.go ./staging/src/k8s.io/component-base/metrics/prometheusextension/weighted_histogram_test.go ./staging/src/k8s.io/component-base/metrics/prometheusextension/weighted_histogram_vec.go + ./staging/src/k8s.io/component-base/metrics/buckets.go ./staging/src/k8s.io/component-base/metrics/collector.go ./staging/src/k8s.io/component-base/metrics/collector_test.go ./staging/src/k8s.io/component-base/metrics/counter.go diff --git a/staging/src/k8s.io/component-base/metrics/buckets.go b/staging/src/k8s.io/component-base/metrics/buckets.go new file mode 100644 index 00000000000..48d3093e0cd --- /dev/null +++ b/staging/src/k8s.io/component-base/metrics/buckets.go @@ -0,0 +1,43 @@ +/* +Copyright 2022 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 metrics + +import ( + "github.com/prometheus/client_golang/prometheus" +) + +// DefBuckets is a wrapper for prometheus.DefBuckets +var DefBuckets = prometheus.DefBuckets + +// LinearBuckets is a wrapper for prometheus.LinearBuckets. +func LinearBuckets(start, width float64, count int) []float64 { + return prometheus.LinearBuckets(start, width, count) +} + +// ExponentialBuckets is a wrapper for prometheus.ExponentialBuckets. +func ExponentialBuckets(start, factor float64, count int) []float64 { + return prometheus.ExponentialBuckets(start, factor, count) +} + +// MergeBuckets merges buckets together +func MergeBuckets(buckets ...[]float64) []float64 { + result := make([]float64, 1) + for _, s := range buckets { + result = append(result, s...) + } + return result +} diff --git a/staging/src/k8s.io/component-base/metrics/histogram.go b/staging/src/k8s.io/component-base/metrics/histogram.go index 1bf8ba887e0..e6884f35c6f 100644 --- a/staging/src/k8s.io/component-base/metrics/histogram.go +++ b/staging/src/k8s.io/component-base/metrics/histogram.go @@ -23,19 +23,6 @@ import ( "github.com/prometheus/client_golang/prometheus" ) -// DefBuckets is a wrapper for prometheus.DefBuckets -var DefBuckets = prometheus.DefBuckets - -// LinearBuckets is a wrapper for prometheus.LinearBuckets. -func LinearBuckets(start, width float64, count int) []float64 { - return prometheus.LinearBuckets(start, width, count) -} - -// ExponentialBuckets is a wrapper for prometheus.ExponentialBuckets. -func ExponentialBuckets(start, factor float64, count int) []float64 { - return prometheus.ExponentialBuckets(start, factor, count) -} - // Histogram is our internal representation for our wrapping struct around prometheus // histograms. Summary implements both kubeCollector and ObserverMetric type Histogram struct { diff --git a/test/instrumentation/decode_metric.go b/test/instrumentation/decode_metric.go index df9323e7ee3..0e2d913483d 100644 --- a/test/instrumentation/decode_metric.go +++ b/test/instrumentation/decode_metric.go @@ -480,15 +480,54 @@ func (c *metricDecoder) decodeBucketFunctionCall(v *ast.CallExpr) ([]float64, er if functionImport.String() != c.kubeMetricsImportName { return nil, newDecodeErrorf(v, errBuckets), true } - firstArg, secondArg, thirdArg, err := decodeBucketArguments(v) - if err != nil { - return nil, err, true - } switch functionName { case "LinearBuckets": + firstArg, secondArg, thirdArg, err := decodeBucketArguments(v) + if err != nil { + return nil, err, true + } return metrics.LinearBuckets(firstArg, secondArg, thirdArg), nil, true case "ExponentialBuckets": + firstArg, secondArg, thirdArg, err := decodeBucketArguments(v) + if err != nil { + return nil, err, true + } return metrics.ExponentialBuckets(firstArg, secondArg, thirdArg), nil, true + case "MergeBuckets": + merged := []float64{} + for _, arg := range v.Args { + switch argExpr := arg.(type) { + case *ast.CompositeLit: + fs, err := decodeListOfFloats(argExpr, argExpr.Elts) + if err != nil { + return nil, err, true + } + merged = append(merged, fs...) + case *ast.CallExpr: + se, ok = argExpr.Fun.(*ast.SelectorExpr) + if ok { + functionName := se.Sel.String() + functionImport, ok := se.X.(*ast.Ident) + if !ok { + return nil, newDecodeErrorf(v, errBuckets), true + } + if functionImport.String() != c.kubeMetricsImportName { + return nil, newDecodeErrorf(v, errBuckets), true + } + firstArg, secondArg, thirdArg, err := decodeBucketArguments(argExpr) + if err != nil { + return nil, err, true + } + switch functionName { + case "LinearBuckets": + merged = append(merged, metrics.LinearBuckets(firstArg, secondArg, thirdArg)...) + case "ExponentialBuckets": + merged = append(merged, metrics.LinearBuckets(firstArg, secondArg, thirdArg)...) + } + } + } + } + return merged, nil, true } return nil, nil, false } diff --git a/test/instrumentation/testdata/pkg/kubelet/metrics/metrics.go b/test/instrumentation/testdata/pkg/kubelet/metrics/metrics.go index cb998ad11ab..47da0b3721f 100644 --- a/test/instrumentation/testdata/pkg/kubelet/metrics/metrics.go +++ b/test/instrumentation/testdata/pkg/kubelet/metrics/metrics.go @@ -488,6 +488,21 @@ var ( StabilityLevel: metrics.BETA, }, ) + + NetworkProgrammingLatency2 = metrics.NewHistogram( + &metrics.HistogramOpts{ + Subsystem: "kube_proxy", + Name: "network_programming_duration_seconds2", + Help: "In Cluster Network Programming Latency in seconds", + Buckets: metrics.MergeBuckets( + metrics.LinearBuckets(0.25, 0.25, 2), // 0.25s, 0.50s + []float64{1, 5, 10, 59}, // 1s, 2s, 3s, ... 59s + metrics.LinearBuckets(60, 5, 12), // 60s, 65s, 70s, ... 115s + metrics.LinearBuckets(120, 30, 7), // 2min, 2.5min, 3min, ..., 5min + ), + StabilityLevel: metrics.BETA, + }, + ) ) var registerMetrics sync.Once diff --git a/test/instrumentation/testdata/test-stable-metrics-list.yaml b/test/instrumentation/testdata/test-stable-metrics-list.yaml index 3682bab139c..ea0955f57cf 100644 --- a/test/instrumentation/testdata/test-stable-metrics-list.yaml +++ b/test/instrumentation/testdata/test-stable-metrics-list.yaml @@ -84,6 +84,37 @@ - 240 - 270 - 300 +- name: network_programming_duration_seconds2 + subsystem: kube_proxy + help: In Cluster Network Programming Latency in seconds + type: Histogram + stabilityLevel: BETA + buckets: + - 0.25 + - 0.5 + - 1 + - 5 + - 10 + - 59 + - 60 + - 65 + - 70 + - 75 + - 80 + - 85 + - 90 + - 95 + - 100 + - 105 + - 110 + - 115 + - 120 + - 150 + - 180 + - 210 + - 240 + - 270 + - 300 - name: certificate_manager_client_ttl_seconds subsystem: kubelet help: Gauge of the TTL (time-to-live) of the Kubelet's client certificate. The value