k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/instrumentation/find_stable_metric.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "fmt" 21 "go/ast" 22 23 "k8s.io/component-base/metrics" 24 ) 25 26 var metricsOptionStructuresNames = []string{ 27 "KubeOpts", 28 "CounterOpts", 29 "GaugeOpts", 30 "HistogramOpts", 31 "SummaryOpts", 32 "TimingHistogramOpts", 33 } 34 35 func findStableMetricDeclaration(tree ast.Node, metricsImportName string) ([]*ast.CallExpr, []error) { 36 v := stableMetricFinder{ 37 metricsImportName: metricsImportName, 38 stableMetricsFunctionCalls: []*ast.CallExpr{}, 39 errors: []error{}, 40 } 41 ast.Walk(&v, tree) 42 return v.stableMetricsFunctionCalls, v.errors 43 } 44 45 // Implements visitor pattern for ast.Node that collects all stable metric expressions 46 type stableMetricFinder struct { 47 metricsImportName string 48 currentFunctionCall *ast.CallExpr 49 stableMetricsFunctionCalls []*ast.CallExpr 50 errors []error 51 } 52 53 var _ ast.Visitor = (*stableMetricFinder)(nil) 54 55 func contains(v metrics.StabilityLevel, a []metrics.StabilityLevel) bool { 56 for _, i := range a { 57 if i == v { 58 return true 59 } 60 } 61 return false 62 } 63 64 func (f *stableMetricFinder) Visit(node ast.Node) (w ast.Visitor) { 65 switch opts := node.(type) { 66 case *ast.CallExpr: 67 if se, ok := opts.Fun.(*ast.SelectorExpr); ok { 68 if se.Sel.Name == "NewDesc" { 69 sl, _ := decodeStabilityLevel(opts.Args[4], f.metricsImportName) 70 if sl != nil { 71 classes := []metrics.StabilityLevel{metrics.STABLE, metrics.BETA} 72 if ALL_STABILITY_CLASSES { 73 classes = append(classes, metrics.ALPHA) 74 } 75 switch { 76 case contains(*sl, classes): 77 f.stableMetricsFunctionCalls = append(f.stableMetricsFunctionCalls, opts) 78 f.currentFunctionCall = nil 79 default: 80 return nil 81 } 82 } 83 } else { 84 f.currentFunctionCall = opts 85 } 86 87 } else { 88 f.currentFunctionCall = opts 89 } 90 case *ast.CompositeLit: 91 se, ok := opts.Type.(*ast.SelectorExpr) 92 if !ok { 93 return f 94 } 95 if !isMetricOps(se.Sel.Name) { 96 return f 97 } 98 id, ok := se.X.(*ast.Ident) 99 if !ok { 100 return f 101 } 102 if id.Name != f.metricsImportName { 103 return f 104 } 105 stabilityLevel, err := getStabilityLevel(opts, f.metricsImportName) 106 if err != nil { 107 f.errors = append(f.errors, err) 108 return nil 109 } 110 classes := []metrics.StabilityLevel{metrics.STABLE, metrics.BETA} 111 if ALL_STABILITY_CLASSES { 112 classes = append(classes, metrics.ALPHA) 113 } 114 switch { 115 case contains(*stabilityLevel, classes): 116 if f.currentFunctionCall == nil { 117 f.errors = append(f.errors, newDecodeErrorf(opts, errNotDirectCall)) 118 return nil 119 } 120 f.stableMetricsFunctionCalls = append(f.stableMetricsFunctionCalls, f.currentFunctionCall) 121 f.currentFunctionCall = nil 122 default: 123 return nil 124 } 125 default: 126 if f.currentFunctionCall == nil || node == nil || node.Pos() < f.currentFunctionCall.Rparen { 127 return f 128 } 129 f.currentFunctionCall = nil 130 } 131 return f 132 } 133 134 func isMetricOps(name string) bool { 135 var found = false 136 for _, optsName := range metricsOptionStructuresNames { 137 if name == optsName { 138 found = true 139 break 140 } 141 } 142 return found 143 } 144 145 func getStabilityLevel(opts *ast.CompositeLit, metricsFrameworkImportName string) (*metrics.StabilityLevel, error) { 146 for _, expr := range opts.Elts { 147 kv, ok := expr.(*ast.KeyValueExpr) 148 if !ok { 149 return nil, newDecodeErrorf(expr, errPositionalArguments) 150 } 151 key := fmt.Sprintf("%v", kv.Key) 152 if key != "StabilityLevel" { 153 continue 154 } 155 return decodeStabilityLevel(kv.Value, metricsFrameworkImportName) 156 } 157 stability := metrics.ALPHA 158 return &stability, nil 159 }