From 52097bc02db9d4884dc0f89b4c4b2648d89f7f10 Mon Sep 17 00:00:00 2001 From: Han Kang Date: Tue, 11 Oct 2022 16:55:19 -0700 Subject: [PATCH] add support for timing histograms and const labels Change-Id: I8f77d5e16c01a403c7cfdccec464a81f4e3beba0 --- test/instrumentation/decode_metric.go | 52 ++++++++++++++++++- test/instrumentation/metric.go | 10 ++-- .../testdata/pkg/kubelet/metrics/metrics.go | 39 ++++++++++++++ .../testdata/test-stable-metrics-list.yaml | 51 ++++++++++++++++++ 4 files changed, 146 insertions(+), 6 deletions(-) diff --git a/test/instrumentation/decode_metric.go b/test/instrumentation/decode_metric.go index 8150e1f6336b..81bb878c4b32 100644 --- a/test/instrumentation/decode_metric.go +++ b/test/instrumentation/decode_metric.go @@ -70,9 +70,9 @@ func (c *metricDecoder) decodeNewMetricCall(fc *ast.CallExpr) (*metric, error) { return nil, nil } switch functionName { - case "NewCounter", "NewGauge", "NewHistogram", "NewSummary": + case "NewCounter", "NewGauge", "NewHistogram", "NewSummary", "NewTimingHistogram": m, err = c.decodeMetric(fc) - case "NewCounterVec", "NewGaugeVec", "NewHistogramVec", "NewSummaryVec": + case "NewCounterVec", "NewGaugeVec", "NewHistogramVec", "NewSummaryVec", "NewTimingHistogramVec": m, err = c.decodeMetricVec(fc) case "Labels", "HandlerOpts", "HandlerFor", "HandlerWithReset": return nil, nil @@ -96,6 +96,8 @@ func getMetricType(functionName string) string { return histogramMetricType case "NewSummary", "NewSummaryVec": return summaryMetricType + case "NewTimingHistogram", "NewTimingHistogramVec": + return timingRatioHistogram default: panic("getMetricType expects correct function name") } @@ -295,6 +297,12 @@ func (c *metricDecoder) decodeOpts(expr ast.Expr) (metric, error) { return m, err } m.StabilityLevel = string(*level) + case "ConstLabels": + labels, err := c.decodeConstLabels(kv.Value) + if err != nil { + return m, err + } + m.ConstLabels = labels case "AgeBuckets", "BufCap": uintVal, err := c.decodeUint32(kv.Value) if err != nil { @@ -558,3 +566,43 @@ func decodeStabilityLevel(expr ast.Expr, metricsFrameworkImportName string) (*me stability := metrics.StabilityLevel(se.Sel.Name) return &stability, nil } + +func (c *metricDecoder) decodeConstLabels(expr ast.Expr) (map[string]string, error) { + retval := map[string]string{} + switch v := expr.(type) { + case *ast.CompositeLit: + for _, e2 := range v.Elts { + kv := e2.(*ast.KeyValueExpr) + key := "" + switch k := kv.Key.(type) { + + case *ast.Ident: + variableExpr, found := c.variables[k.Name] + if !found { + return nil, newDecodeErrorf(expr, errBadVariableAttribute) + } + bl, ok := variableExpr.(*ast.BasicLit) + if !ok { + return nil, newDecodeErrorf(expr, errNonStringAttribute) + } + k2, err := stringValue(bl) + if err != nil { + return nil, err + } + key = k2 + case *ast.BasicLit: + k2, err := stringValue(k) + if err != nil { + return nil, err + } + key = k2 + } + val, err := stringValue(kv.Value.(*ast.BasicLit)) + if err != nil { + return nil, err + } + retval[key] = val + } + } + return retval, nil +} diff --git a/test/instrumentation/metric.go b/test/instrumentation/metric.go index 5e4e399f94b5..1b8030066104 100644 --- a/test/instrumentation/metric.go +++ b/test/instrumentation/metric.go @@ -21,10 +21,11 @@ import ( ) const ( - counterMetricType = "Counter" - gaugeMetricType = "Gauge" - histogramMetricType = "Histogram" - summaryMetricType = "Summary" + counterMetricType = "Counter" + gaugeMetricType = "Gauge" + histogramMetricType = "Histogram" + summaryMetricType = "Summary" + timingRatioHistogram = "TimingRatioHistogram" ) type metric struct { @@ -41,6 +42,7 @@ type metric struct { AgeBuckets uint32 `yaml:"ageBuckets,omitempty"` BufCap uint32 `yaml:"bufCap,omitempty"` MaxAge int64 `yaml:"maxAge,omitempty"` + ConstLabels map[string]string `yaml:"constLabels,omitempty"` } func (m metric) buildFQName() string { diff --git a/test/instrumentation/testdata/pkg/kubelet/metrics/metrics.go b/test/instrumentation/testdata/pkg/kubelet/metrics/metrics.go index 335e2961d624..45bbe0779385 100644 --- a/test/instrumentation/testdata/pkg/kubelet/metrics/metrics.go +++ b/test/instrumentation/testdata/pkg/kubelet/metrics/metrics.go @@ -63,6 +63,16 @@ const ( RunPodSandboxErrorsKey = "run_podsandbox_errors_total" ) +const ( + requestKind = "request_kind" + priorityLevel = "priority_level" + flowSchema = "flow_schema" + phase = "phase" + LabelNamePhase = "phase" + LabelValueWaiting = "waiting" + LabelValueExecuting = "executing" +) + var ( defObjectives = map[float64]float64{0.5: 0.5, 0.75: 0.75} testBuckets = []float64{0, 0.5, 1.0} @@ -131,6 +141,35 @@ var ( StabilityLevel: metrics.ALPHA, }, ) + // PriorityLevelExecutionSeatsGaugeVec creates observers of seats occupied throughout execution for priority levels + PriorityLevelExecutionSeatsGaugeVec = metrics.NewTimingHistogramVec( + &metrics.TimingHistogramOpts{ + Namespace: "namespace", + Subsystem: "subsystem", + Name: "priority_level_seat_utilization", + Help: "Observations, at the end of every nanosecond, of utilization of seats for any stage of execution (but only initial stage for WATCHes)", + // Buckets for both 0.99 and 1.0 mean PromQL's histogram_quantile will reveal saturation + Buckets: []float64{0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.99, 1}, + ConstLabels: map[string]string{phase: "executing"}, + StabilityLevel: metrics.BETA, + }, + []string{"priorityLevel"}, + ) + + // PriorityLevelExecutionSeatsGaugeVec creates observers of seats occupied throughout execution for priority levels + TestConstLabels = metrics.NewTimingHistogramVec( + &metrics.TimingHistogramOpts{ + Namespace: "test", + Subsystem: "const", + Name: "label", + Help: "Observations, at the end of every nanosecond, of utilization of seats for any stage of execution (but only initial stage for WATCHes)", + // Buckets for both 0.99 and 1.0 mean PromQL's histogram_quantile will reveal saturation + Buckets: []float64{0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.99, 1}, + ConstLabels: map[string]string{"somestring": "executing", phase: "blah"}, + StabilityLevel: metrics.BETA, + }, + []string{"priorityLevel"}, + ) // PLEGRelistDuration is a Histogram that tracks the duration (in seconds) it takes for relisting pods in the Kubelet's // Pod Lifecycle Event Generator (PLEG). PLEGRelistDuration = metrics.NewHistogram( diff --git a/test/instrumentation/testdata/test-stable-metrics-list.yaml b/test/instrumentation/testdata/test-stable-metrics-list.yaml index 94360c39c190..4fbe7ee07c15 100644 --- a/test/instrumentation/testdata/test-stable-metrics-list.yaml +++ b/test/instrumentation/testdata/test-stable-metrics-list.yaml @@ -85,3 +85,54 @@ - 2.5 - 5 - 10 +- name: priority_level_seat_utilization + subsystem: subsystem + namespace: namespace + help: Observations, at the end of every nanosecond, of utilization of seats for + any stage of execution (but only initial stage for WATCHes) + type: TimingRatioHistogram + stabilityLevel: BETA + labels: + - priorityLevel + buckets: + - 0 + - 0.1 + - 0.2 + - 0.3 + - 0.4 + - 0.5 + - 0.6 + - 0.7 + - 0.8 + - 0.9 + - 0.95 + - 0.99 + - 1 + constLabels: + phase: executing +- name: label + subsystem: const + namespace: test + help: Observations, at the end of every nanosecond, of utilization of seats for + any stage of execution (but only initial stage for WATCHes) + type: TimingRatioHistogram + stabilityLevel: BETA + labels: + - priorityLevel + buckets: + - 0 + - 0.1 + - 0.2 + - 0.3 + - 0.4 + - 0.5 + - 0.6 + - 0.7 + - 0.8 + - 0.9 + - 0.95 + - 0.99 + - 1 + constLabels: + phase: blah + somestring: executing