Skip to content

Commit a53b25a

Browse files
authored
Merge pull request kubernetes#87923 from ingvagabund/move-direct-prometheus-metrics-under-component-base-metrics
Collect some of scheduling metrics and scheduling throughput (vol. 2)
2 parents 958c254 + 7b55340 commit a53b25a

File tree

6 files changed

+616
-4
lines changed

6 files changed

+616
-4
lines changed

staging/src/k8s.io/component-base/metrics/testutil/BUILD

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ go_library(
1313
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
1414
"//staging/src/k8s.io/component-base/metrics:go_default_library",
1515
"//vendor/github.com/prometheus/client_golang/prometheus/testutil:go_default_library",
16+
"//vendor/github.com/prometheus/client_model/go:go_default_library",
1617
"//vendor/github.com/prometheus/common/expfmt:go_default_library",
1718
"//vendor/github.com/prometheus/common/model:go_default_library",
1819
],
@@ -34,7 +35,14 @@ filegroup(
3435

3536
go_test(
3637
name = "go_default_test",
37-
srcs = ["testutil_test.go"],
38+
srcs = [
39+
"metrics_test.go",
40+
"testutil_test.go",
41+
],
3842
embed = [":go_default_library"],
39-
deps = ["//staging/src/k8s.io/component-base/metrics:go_default_library"],
43+
deps = [
44+
"//staging/src/k8s.io/component-base/metrics:go_default_library",
45+
"//vendor/github.com/prometheus/client_model/go:go_default_library",
46+
"//vendor/k8s.io/utils/pointer:go_default_library",
47+
],
4048
)

staging/src/k8s.io/component-base/metrics/testutil/metrics.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,16 @@ package testutil
1919
import (
2020
"fmt"
2121
"io"
22+
"math"
2223
"reflect"
24+
"sort"
2325
"strings"
2426

27+
dto "github.com/prometheus/client_model/go"
2528
"github.com/prometheus/common/expfmt"
2629
"github.com/prometheus/common/model"
30+
31+
"k8s.io/component-base/metrics"
2732
)
2833

2934
var (
@@ -178,3 +183,140 @@ func ValidateMetrics(metrics Metrics, metricName string, expectedLabels ...strin
178183
}
179184
return nil
180185
}
186+
187+
// Histogram wraps prometheus histogram DTO (data transfer object)
188+
type Histogram struct {
189+
*dto.Histogram
190+
}
191+
192+
// GetHistogramFromGatherer collects a metric from a gatherer implementing k8s.io/component-base/metrics.Gatherer interface.
193+
// Used only for testing purposes where we need to gather metrics directly from a running binary (without metrics endpoint).
194+
func GetHistogramFromGatherer(gatherer metrics.Gatherer, metricName string) (Histogram, error) {
195+
var metricFamily *dto.MetricFamily
196+
m, err := gatherer.Gather()
197+
if err != nil {
198+
return Histogram{}, err
199+
}
200+
for _, mFamily := range m {
201+
if mFamily.Name != nil && *mFamily.Name == metricName {
202+
metricFamily = mFamily
203+
break
204+
}
205+
}
206+
207+
if metricFamily == nil {
208+
return Histogram{}, fmt.Errorf("Metric %q not found", metricName)
209+
}
210+
211+
if metricFamily.GetMetric() == nil {
212+
return Histogram{}, fmt.Errorf("Metric %q is empty", metricName)
213+
}
214+
215+
if len(metricFamily.GetMetric()) == 0 {
216+
return Histogram{}, fmt.Errorf("Metric %q is empty", metricName)
217+
}
218+
219+
return Histogram{
220+
// Histograms are stored under the first index (based on observation).
221+
// Given there's only one histogram registered per each metric name, accessing
222+
// the first index is sufficient.
223+
metricFamily.GetMetric()[0].GetHistogram(),
224+
}, nil
225+
}
226+
227+
func uint64Ptr(u uint64) *uint64 {
228+
return &u
229+
}
230+
231+
// Bucket of a histogram
232+
type bucket struct {
233+
upperBound float64
234+
count float64
235+
}
236+
237+
func bucketQuantile(q float64, buckets []bucket) float64 {
238+
if q < 0 {
239+
return math.Inf(-1)
240+
}
241+
if q > 1 {
242+
return math.Inf(+1)
243+
}
244+
245+
if len(buckets) < 2 {
246+
return math.NaN()
247+
}
248+
249+
rank := q * buckets[len(buckets)-1].count
250+
b := sort.Search(len(buckets)-1, func(i int) bool { return buckets[i].count >= rank })
251+
252+
if b == 0 {
253+
return buckets[0].upperBound * (rank / buckets[0].count)
254+
}
255+
256+
// linear approximation of b-th bucket
257+
brank := rank - buckets[b-1].count
258+
bSize := buckets[b].upperBound - buckets[b-1].upperBound
259+
bCount := buckets[b].count - buckets[b-1].count
260+
261+
return buckets[b-1].upperBound + bSize*(brank/bCount)
262+
}
263+
264+
// Quantile computes q-th quantile of a cumulative histogram.
265+
// It's expected the histogram is valid (by calling Validate)
266+
func (hist *Histogram) Quantile(q float64) float64 {
267+
buckets := []bucket{}
268+
269+
for _, bckt := range hist.Bucket {
270+
buckets = append(buckets, bucket{
271+
count: float64(*bckt.CumulativeCount),
272+
upperBound: *bckt.UpperBound,
273+
})
274+
}
275+
276+
// bucketQuantile expects the upper bound of the last bucket to be +inf
277+
// buckets[len(buckets)-1].upperBound = math.Inf(+1)
278+
279+
return bucketQuantile(q, buckets)
280+
}
281+
282+
// Average computes histogram's average value
283+
func (hist *Histogram) Average() float64 {
284+
return *hist.SampleSum / float64(*hist.SampleCount)
285+
}
286+
287+
// Clear clears all fields of the wrapped histogram
288+
func (hist *Histogram) Clear() {
289+
if hist.SampleCount != nil {
290+
*hist.SampleCount = 0
291+
}
292+
if hist.SampleSum != nil {
293+
*hist.SampleSum = 0
294+
}
295+
for _, b := range hist.Bucket {
296+
if b.CumulativeCount != nil {
297+
*b.CumulativeCount = 0
298+
}
299+
}
300+
}
301+
302+
// Validate makes sure the wrapped histogram has all necessary fields set and with valid values.
303+
func (hist *Histogram) Validate() error {
304+
if hist.SampleCount == nil || *hist.SampleCount == 0 {
305+
return fmt.Errorf("nil or empty histogram SampleCount")
306+
}
307+
308+
if hist.SampleSum == nil || *hist.SampleSum == 0 {
309+
return fmt.Errorf("nil or empty histogram SampleSum")
310+
}
311+
312+
for _, bckt := range hist.Bucket {
313+
if bckt == nil {
314+
return fmt.Errorf("empty histogram bucket")
315+
}
316+
if bckt.UpperBound == nil || *bckt.UpperBound < 0 {
317+
return fmt.Errorf("nil or negative histogram bucket UpperBound")
318+
}
319+
}
320+
321+
return nil
322+
}

0 commit comments

Comments
 (0)