decode_metric.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. Copyright 2019 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package main
  14. import (
  15. "fmt"
  16. "go/ast"
  17. "go/token"
  18. "sort"
  19. "strconv"
  20. "strings"
  21. "k8s.io/component-base/metrics"
  22. )
  23. func decodeMetricCalls(fs []*ast.CallExpr, metricsImportName string, variables map[string]ast.Expr) ([]metric, []error) {
  24. finder := metricDecoder{
  25. kubeMetricsImportName: metricsImportName,
  26. variables: variables,
  27. }
  28. ms := make([]metric, 0, len(fs))
  29. errors := []error{}
  30. for _, f := range fs {
  31. m, err := finder.decodeNewMetricCall(f)
  32. if err != nil {
  33. errors = append(errors, err)
  34. continue
  35. }
  36. ms = append(ms, m)
  37. }
  38. return ms, errors
  39. }
  40. type metricDecoder struct {
  41. kubeMetricsImportName string
  42. variables map[string]ast.Expr
  43. }
  44. func (c *metricDecoder) decodeNewMetricCall(fc *ast.CallExpr) (metric, error) {
  45. var m metric
  46. var err error
  47. se, ok := fc.Fun.(*ast.SelectorExpr)
  48. if !ok {
  49. return m, newDecodeErrorf(fc, errNotDirectCall)
  50. }
  51. functionName := se.Sel.String()
  52. functionImport, ok := se.X.(*ast.Ident)
  53. if !ok {
  54. return m, newDecodeErrorf(fc, errNotDirectCall)
  55. }
  56. if functionImport.String() != c.kubeMetricsImportName {
  57. return m, newDecodeErrorf(fc, errNotDirectCall)
  58. }
  59. switch functionName {
  60. case "NewCounter", "NewGauge", "NewHistogram":
  61. m, err = c.decodeMetric(fc)
  62. case "NewCounterVec", "NewGaugeVec", "NewHistogramVec":
  63. m, err = c.decodeMetricVec(fc)
  64. case "NewSummary", "NewSummaryVec":
  65. return m, newDecodeErrorf(fc, errStableSummary)
  66. default:
  67. return m, newDecodeErrorf(fc, errNotDirectCall)
  68. }
  69. if err != nil {
  70. return m, err
  71. }
  72. m.Type = getMetricType(functionName)
  73. return m, nil
  74. }
  75. func getMetricType(functionName string) string {
  76. switch functionName {
  77. case "NewCounter", "NewCounterVec":
  78. return counterMetricType
  79. case "NewGauge", "NewGaugeVec":
  80. return gaugeMetricType
  81. case "NewHistogram", "NewHistogramVec":
  82. return histogramMetricType
  83. default:
  84. panic("getMetricType expects correct function name")
  85. }
  86. }
  87. func (c *metricDecoder) decodeMetric(call *ast.CallExpr) (metric, error) {
  88. if len(call.Args) != 1 {
  89. return metric{}, newDecodeErrorf(call, errInvalidNewMetricCall)
  90. }
  91. return c.decodeOpts(call.Args[0])
  92. }
  93. func (c *metricDecoder) decodeMetricVec(call *ast.CallExpr) (metric, error) {
  94. if len(call.Args) != 2 {
  95. return metric{}, newDecodeErrorf(call, errInvalidNewMetricCall)
  96. }
  97. m, err := c.decodeOpts(call.Args[0])
  98. if err != nil {
  99. return m, err
  100. }
  101. labels, err := decodeLabels(call.Args[1])
  102. if err != nil {
  103. return m, err
  104. }
  105. sort.Strings(labels)
  106. m.Labels = labels
  107. return m, nil
  108. }
  109. func decodeLabels(expr ast.Expr) ([]string, error) {
  110. cl, ok := expr.(*ast.CompositeLit)
  111. if !ok {
  112. return nil, newDecodeErrorf(expr, errInvalidNewMetricCall)
  113. }
  114. labels := make([]string, len(cl.Elts))
  115. for i, el := range cl.Elts {
  116. bl, ok := el.(*ast.BasicLit)
  117. if !ok {
  118. return nil, newDecodeErrorf(bl, errLabels)
  119. }
  120. value, err := stringValue(bl)
  121. if err != nil {
  122. return nil, err
  123. }
  124. labels[i] = value
  125. }
  126. return labels, nil
  127. }
  128. func (c *metricDecoder) decodeOpts(expr ast.Expr) (metric, error) {
  129. m := metric{
  130. Labels: []string{},
  131. }
  132. ue, ok := expr.(*ast.UnaryExpr)
  133. if !ok {
  134. return m, newDecodeErrorf(expr, errInvalidNewMetricCall)
  135. }
  136. cl, ok := ue.X.(*ast.CompositeLit)
  137. if !ok {
  138. return m, newDecodeErrorf(expr, errInvalidNewMetricCall)
  139. }
  140. for _, expr := range cl.Elts {
  141. kv, ok := expr.(*ast.KeyValueExpr)
  142. if !ok {
  143. return m, newDecodeErrorf(expr, errPositionalArguments)
  144. }
  145. key := fmt.Sprintf("%v", kv.Key)
  146. switch key {
  147. case "Namespace", "Subsystem", "Name", "Help", "DeprecatedVersion":
  148. var value string
  149. var err error
  150. switch v := kv.Value.(type) {
  151. case *ast.BasicLit:
  152. value, err = stringValue(v)
  153. if err != nil {
  154. return m, err
  155. }
  156. case *ast.Ident:
  157. variableExpr, found := c.variables[v.Name]
  158. if !found {
  159. return m, newDecodeErrorf(expr, errBadVariableAttribute)
  160. }
  161. bl, ok := variableExpr.(*ast.BasicLit)
  162. if !ok {
  163. return m, newDecodeErrorf(expr, errNonStringAttribute)
  164. }
  165. value, err = stringValue(bl)
  166. if err != nil {
  167. return m, err
  168. }
  169. default:
  170. return m, newDecodeErrorf(expr, errNonStringAttribute)
  171. }
  172. switch key {
  173. case "Namespace":
  174. m.Namespace = value
  175. case "Subsystem":
  176. m.Subsystem = value
  177. case "Name":
  178. m.Name = value
  179. case "DeprecatedVersion":
  180. m.DeprecatedVersion = value
  181. case "Help":
  182. m.Help = value
  183. }
  184. case "Buckets":
  185. buckets, err := c.decodeBuckets(kv.Value)
  186. if err != nil {
  187. return m, err
  188. }
  189. sort.Float64s(buckets)
  190. m.Buckets = buckets
  191. case "StabilityLevel":
  192. level, err := decodeStabilityLevel(kv.Value, c.kubeMetricsImportName)
  193. if err != nil {
  194. return m, err
  195. }
  196. m.StabilityLevel = string(*level)
  197. default:
  198. return m, newDecodeErrorf(expr, errFieldNotSupported, key)
  199. }
  200. }
  201. return m, nil
  202. }
  203. func stringValue(bl *ast.BasicLit) (string, error) {
  204. if bl.Kind != token.STRING {
  205. return "", newDecodeErrorf(bl, errNonStringAttribute)
  206. }
  207. return strings.Trim(bl.Value, `"`), nil
  208. }
  209. func (c *metricDecoder) decodeBuckets(expr ast.Expr) ([]float64, error) {
  210. switch v := expr.(type) {
  211. case *ast.CompositeLit:
  212. return decodeListOfFloats(v.Elts)
  213. case *ast.SelectorExpr:
  214. variableName := v.Sel.String()
  215. importName, ok := v.X.(*ast.Ident)
  216. if ok && importName.String() == c.kubeMetricsImportName && variableName == "DefBuckets" {
  217. return metrics.DefBuckets, nil
  218. }
  219. case *ast.CallExpr:
  220. se, ok := v.Fun.(*ast.SelectorExpr)
  221. if !ok {
  222. return nil, newDecodeErrorf(v, errBuckets)
  223. }
  224. functionName := se.Sel.String()
  225. functionImport, ok := se.X.(*ast.Ident)
  226. if !ok {
  227. return nil, newDecodeErrorf(v, errBuckets)
  228. }
  229. if functionImport.String() != c.kubeMetricsImportName {
  230. return nil, newDecodeErrorf(v, errBuckets)
  231. }
  232. firstArg, secondArg, thirdArg, err := decodeBucketArguments(v)
  233. if err != nil {
  234. return nil, err
  235. }
  236. switch functionName {
  237. case "LinearBuckets":
  238. return metrics.LinearBuckets(firstArg, secondArg, thirdArg), nil
  239. case "ExponentialBuckets":
  240. return metrics.ExponentialBuckets(firstArg, secondArg, thirdArg), nil
  241. }
  242. }
  243. return nil, newDecodeErrorf(expr, errBuckets)
  244. }
  245. func decodeListOfFloats(exprs []ast.Expr) ([]float64, error) {
  246. buckets := make([]float64, len(exprs))
  247. for i, elt := range exprs {
  248. bl, ok := elt.(*ast.BasicLit)
  249. if !ok {
  250. return nil, newDecodeErrorf(bl, errBuckets)
  251. }
  252. if bl.Kind != token.FLOAT && bl.Kind != token.INT {
  253. return nil, newDecodeErrorf(bl, errBuckets)
  254. }
  255. value, err := strconv.ParseFloat(bl.Value, 64)
  256. if err != nil {
  257. return nil, err
  258. }
  259. buckets[i] = value
  260. }
  261. return buckets, nil
  262. }
  263. func decodeBucketArguments(fc *ast.CallExpr) (float64, float64, int, error) {
  264. if len(fc.Args) != 3 {
  265. return 0, 0, 0, newDecodeErrorf(fc, errBuckets)
  266. }
  267. strArgs := make([]string, len(fc.Args))
  268. for i, elt := range fc.Args {
  269. bl, ok := elt.(*ast.BasicLit)
  270. if !ok {
  271. return 0, 0, 0, newDecodeErrorf(bl, errBuckets)
  272. }
  273. if bl.Kind != token.FLOAT && bl.Kind != token.INT {
  274. return 0, 0, 0, newDecodeErrorf(bl, errBuckets)
  275. }
  276. strArgs[i] = bl.Value
  277. }
  278. firstArg, err := strconv.ParseFloat(strArgs[0], 64)
  279. if err != nil {
  280. return 0, 0, 0, newDecodeErrorf(fc.Args[0], errBuckets)
  281. }
  282. secondArg, err := strconv.ParseFloat(strArgs[1], 64)
  283. if err != nil {
  284. return 0, 0, 0, newDecodeErrorf(fc.Args[1], errBuckets)
  285. }
  286. thirdArg, err := strconv.ParseInt(strArgs[2], 10, 64)
  287. if err != nil {
  288. return 0, 0, 0, newDecodeErrorf(fc.Args[2], errBuckets)
  289. }
  290. return firstArg, secondArg, int(thirdArg), nil
  291. }
  292. func decodeStabilityLevel(expr ast.Expr, metricsFrameworkImportName string) (*metrics.StabilityLevel, error) {
  293. se, ok := expr.(*ast.SelectorExpr)
  294. if !ok {
  295. return nil, newDecodeErrorf(expr, errStabilityLevel)
  296. }
  297. s, ok := se.X.(*ast.Ident)
  298. if !ok {
  299. return nil, newDecodeErrorf(expr, errStabilityLevel)
  300. }
  301. if s.String() != metricsFrameworkImportName {
  302. return nil, newDecodeErrorf(expr, errStabilityLevel)
  303. }
  304. if se.Sel.Name != "ALPHA" && se.Sel.Name != "STABLE" {
  305. return nil, newDecodeErrorf(expr, errStabilityLevel)
  306. }
  307. stability := metrics.StabilityLevel(se.Sel.Name)
  308. return &stability, nil
  309. }