k8s.io/kubernetes@v1.29.3/test/instrumentation/decode_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 "go/token" 23 "sort" 24 "strconv" 25 "strings" 26 "time" 27 28 "k8s.io/component-base/metrics" 29 ) 30 31 func decodeMetricCalls(fs []*ast.CallExpr, metricsImportName string, variables map[string]ast.Expr) ([]metric, []error) { 32 finder := metricDecoder{ 33 kubeMetricsImportName: metricsImportName, 34 variables: variables, 35 } 36 ms := make([]metric, 0, len(fs)) 37 errors := []error{} 38 for _, f := range fs { 39 m, err := finder.decodeNewMetricCall(f) 40 if err != nil { 41 errors = append(errors, err) 42 continue 43 } 44 if m != nil { 45 ms = append(ms, *m) 46 } 47 } 48 return ms, errors 49 } 50 51 type metricDecoder struct { 52 kubeMetricsImportName string 53 variables map[string]ast.Expr 54 } 55 56 func (c *metricDecoder) decodeNewMetricCall(fc *ast.CallExpr) (*metric, error) { 57 var m metric 58 var err error 59 se, ok := fc.Fun.(*ast.SelectorExpr) 60 if !ok { 61 // account for timing ratio histogram functions 62 switch v := fc.Fun.(type) { 63 case *ast.Ident: 64 if v.Name == "NewTimingRatioHistogramVec" { 65 m, err = c.decodeMetricVecForTimingRatioHistogram(fc) 66 m.Type = timingRatioHistogram 67 return &m, err 68 } 69 } 70 return nil, newDecodeErrorf(fc, errNotDirectCall) 71 } 72 functionName := se.Sel.String() 73 functionImport, ok := se.X.(*ast.Ident) 74 if !ok { 75 return nil, newDecodeErrorf(fc, errNotDirectCall) 76 } 77 if functionImport.String() != c.kubeMetricsImportName { 78 return nil, nil 79 } 80 switch functionName { 81 case "NewCounter", "NewGauge", "NewHistogram", "NewSummary", "NewTimingHistogram", "NewGaugeFunc": 82 m, err = c.decodeMetric(fc) 83 case "NewCounterVec", "NewGaugeVec", "NewHistogramVec", "NewSummaryVec", "NewTimingHistogramVec": 84 m, err = c.decodeMetricVec(fc) 85 case "Labels", "HandlerOpts", "HandlerFor", "HandlerWithReset": 86 return nil, nil 87 case "NewDesc": 88 m, err = c.decodeDesc(fc) 89 default: 90 return &m, newDecodeErrorf(fc, errNotDirectCall) 91 } 92 if err != nil { 93 return &m, err 94 } 95 m.Type = getMetricType(functionName) 96 return &m, nil 97 } 98 99 func getMetricType(functionName string) string { 100 switch functionName { 101 case "NewDesc": 102 return customType 103 case "NewCounter", "NewCounterVec": 104 return counterMetricType 105 case "NewGauge", "NewGaugeVec", "NewGaugeFunc": 106 return gaugeMetricType 107 case "NewHistogram", "NewHistogramVec": 108 return histogramMetricType 109 case "NewSummary", "NewSummaryVec": 110 return summaryMetricType 111 case "NewTimingHistogram", "NewTimingHistogramVec", "NewTimingRatioHistogramVec": 112 return timingRatioHistogram 113 default: 114 panic("getMetricType expects correct function name") 115 } 116 } 117 118 func (c *metricDecoder) decodeMetric(call *ast.CallExpr) (metric, error) { 119 if len(call.Args) > 2 { 120 return metric{}, newDecodeErrorf(call, errInvalidNewMetricCall) 121 } 122 return c.decodeOpts(call.Args[0]) 123 } 124 125 func (c *metricDecoder) decodeDesc(ce *ast.CallExpr) (metric, error) { 126 m := &metric{} 127 name, err := c.decodeString(ce.Args[0]) 128 if err != nil { 129 return *m, newDecodeErrorf(ce, errorDecodingString) 130 } 131 m.Name = *name 132 help, err := c.decodeString(ce.Args[1]) 133 if err != nil { 134 return *m, newDecodeErrorf(ce, errorDecodingString) 135 } 136 m.Help = *help 137 labels, err := c.decodeLabels(ce.Args[2]) 138 if err != nil { 139 return *m, newDecodeErrorf(ce, errorDecodingLabels) 140 } 141 m.Labels = labels 142 cLabels, err := c.decodeConstLabels(ce.Args[3]) 143 if err != nil { 144 return *m, newDecodeErrorf(ce, "can't decode const labels") 145 } 146 m.ConstLabels = cLabels 147 sl, err := decodeStabilityLevel(ce.Args[4], c.kubeMetricsImportName) 148 if err != nil { 149 return *m, newDecodeErrorf(ce, "can't decode stability level") 150 } 151 if sl != nil { 152 m.StabilityLevel = string(*sl) 153 } 154 deprecatedVersion, err := c.decodeString(ce.Args[5]) 155 if err != nil { 156 return *m, newDecodeErrorf(ce, errorDecodingString) 157 } 158 if deprecatedVersion != nil { 159 m.DeprecatedVersion = *deprecatedVersion 160 } 161 return *m, nil 162 } 163 164 func (c *metricDecoder) decodeString(expr ast.Expr) (*string, error) { 165 switch e := expr.(type) { 166 case *ast.BasicLit: 167 value, err := stringValue(e) 168 if err != nil { 169 return nil, err 170 } 171 return &value, nil 172 case *ast.CallExpr: 173 firstArg, secondArg, thirdArg, err := c.decodeBuildFQNameArguments(e) 174 if err != nil { 175 return nil, newDecodeErrorf(expr, errNonStringAttribute) 176 } 177 se, ok := e.Fun.(*ast.SelectorExpr) 178 if ok { 179 functionName := se.Sel.Name 180 switch functionName { 181 case "BuildFQName": 182 n := metrics.BuildFQName(firstArg, secondArg, thirdArg) 183 return &n, nil 184 } 185 } 186 case *ast.Ident: 187 variableExpr, found := c.variables[e.Name] 188 if !found { 189 return nil, newDecodeErrorf(expr, errBadVariableAttribute) 190 } 191 bl, ok := variableExpr.(*ast.BasicLit) 192 if !ok { 193 return nil, newDecodeErrorf(expr, errNonStringAttribute) 194 } 195 value, err := stringValue(bl) 196 if err != nil { 197 return nil, err 198 } 199 return &value, nil 200 case *ast.SelectorExpr: 201 s, ok := e.X.(*ast.Ident) 202 if !ok { 203 return nil, newDecodeErrorf(expr, errExprNotIdent, e.X) 204 } 205 variableExpr, found := c.variables[strings.Join([]string{s.Name, e.Sel.Name}, ".")] 206 if !found { 207 return nil, newDecodeErrorf(expr, errBadImportedVariableAttribute) 208 } 209 bl, ok := variableExpr.(*ast.BasicLit) 210 if !ok { 211 return nil, newDecodeErrorf(expr, errNonStringAttribute) 212 } 213 value, err := stringValue(bl) 214 if err != nil { 215 return nil, err 216 } 217 return &value, nil 218 case *ast.BinaryExpr: 219 var binaryExpr *ast.BinaryExpr 220 binaryExpr = e 221 var okay bool 222 var value string 223 okay = true 224 225 for okay { 226 yV, okay := binaryExpr.Y.(*ast.BasicLit) 227 if !okay { 228 return nil, newDecodeErrorf(expr, errNonStringAttribute) 229 } 230 yVal, err := stringValue(yV) 231 if err != nil { 232 return nil, newDecodeErrorf(expr, errNonStringAttribute) 233 } 234 value = fmt.Sprintf("%s%s", yVal, value) 235 x, okay := binaryExpr.X.(*ast.BinaryExpr) 236 if !okay { 237 // should be basicLit 238 xV, okay := binaryExpr.X.(*ast.BasicLit) 239 if !okay { 240 return nil, newDecodeErrorf(expr, errNonStringAttribute) 241 } 242 xVal, err := stringValue(xV) 243 if err != nil { 244 return nil, newDecodeErrorf(expr, errNonStringAttribute) 245 } 246 value = fmt.Sprintf("%s%s", xVal, value) 247 break 248 } 249 binaryExpr = x 250 } 251 return &value, nil 252 } 253 return nil, newDecodeErrorf(expr, errorDecodingString) 254 } 255 256 func (c *metricDecoder) decodeMetricVec(call *ast.CallExpr) (metric, error) { 257 if len(call.Args) != 2 { 258 return metric{}, newDecodeErrorf(call, errInvalidNewMetricCall) 259 } 260 m, err := c.decodeOpts(call.Args[0]) 261 if err != nil { 262 return m, err 263 } 264 labels, err := c.decodeLabels(call.Args[1]) 265 if err != nil { 266 return m, err 267 } 268 sort.Strings(labels) 269 m.Labels = labels 270 return m, nil 271 } 272 273 func (c *metricDecoder) decodeMetricVecForTimingRatioHistogram(call *ast.CallExpr) (metric, error) { 274 m, err := c.decodeOpts(call.Args[0]) 275 if err != nil { 276 return m, err 277 } 278 labels, err := c.decodeLabelsFromArray(call.Args[1:]) 279 if err != nil { 280 return m, err 281 } 282 sort.Strings(labels) 283 m.Labels = labels 284 return m, nil 285 } 286 287 func (c *metricDecoder) decodeLabelsFromArray(exprs []ast.Expr) ([]string, error) { 288 retval := []string{} 289 for _, e := range exprs { 290 v, err := c.decodeString(e) 291 if err != nil || v == nil { 292 return nil, newDecodeErrorf(e, errNonStringAttribute) 293 } 294 retval = append(retval, *v) 295 } 296 297 return retval, nil 298 } 299 300 func (c *metricDecoder) decodeLabels(expr ast.Expr) ([]string, error) { 301 cl, ok := expr.(*ast.CompositeLit) 302 if !ok { 303 switch e := expr.(type) { 304 case *ast.Ident: 305 if e.Name == "nil" { 306 return []string{}, nil 307 } 308 variableExpr, found := c.variables[e.Name] 309 if !found { 310 return nil, newDecodeErrorf(expr, errorFindingVariableForLabels) 311 } 312 cl2, ok := variableExpr.(*ast.CompositeLit) 313 if !ok { 314 return nil, newDecodeErrorf(expr, errorFindingVariableForLabels) 315 } 316 cl = cl2 317 } 318 } 319 return c.decodeLabelsFromArray(cl.Elts) 320 } 321 322 func (c *metricDecoder) decodeOpts(expr ast.Expr) (metric, error) { 323 m := metric{ 324 Labels: []string{}, 325 } 326 ue, ok := expr.(*ast.UnaryExpr) 327 if !ok { 328 return m, newDecodeErrorf(expr, errInvalidNewMetricCall) 329 } 330 cl, ok := ue.X.(*ast.CompositeLit) 331 if !ok { 332 return m, newDecodeErrorf(expr, errInvalidNewMetricCall) 333 } 334 335 for _, expr := range cl.Elts { 336 kv, ok := expr.(*ast.KeyValueExpr) 337 if !ok { 338 return m, newDecodeErrorf(expr, errPositionalArguments) 339 } 340 key := fmt.Sprintf("%v", kv.Key) 341 342 switch key { 343 case "Namespace", "Subsystem", "Name", "Help", "DeprecatedVersion": 344 var value string 345 var err error 346 s, err := c.decodeString(kv.Value) 347 if err != nil { 348 return m, newDecodeErrorf(expr, err.Error()) 349 } 350 value = *s 351 switch key { 352 case "Namespace": 353 m.Namespace = value 354 case "Subsystem": 355 m.Subsystem = value 356 case "Name": 357 m.Name = value 358 case "DeprecatedVersion": 359 m.DeprecatedVersion = value 360 case "Help": 361 m.Help = value 362 } 363 case "Buckets": 364 buckets, err := c.decodeBuckets(kv.Value) 365 if err != nil { 366 return m, err 367 } 368 sort.Float64s(buckets) 369 m.Buckets = buckets 370 case "StabilityLevel": 371 level, err := decodeStabilityLevel(kv.Value, c.kubeMetricsImportName) 372 if err != nil { 373 return m, err 374 } 375 m.StabilityLevel = string(*level) 376 case "ConstLabels": 377 labels, err := c.decodeConstLabels(kv.Value) 378 if err != nil { 379 return m, err 380 } 381 m.ConstLabels = labels 382 case "AgeBuckets", "BufCap": 383 uintVal, err := c.decodeUint32(kv.Value) 384 if err != nil { 385 print(key) 386 return m, err 387 } 388 if key == "AgeBuckets" { 389 m.AgeBuckets = uintVal 390 } 391 if key == "BufCap" { 392 m.BufCap = uintVal 393 } 394 395 case "Objectives": 396 obj, err := c.decodeObjectives(kv.Value) 397 if err != nil { 398 print(key) 399 return m, err 400 } 401 m.Objectives = obj 402 case "MaxAge": 403 int64Val, err := c.decodeInt64(kv.Value) 404 if err != nil { 405 return m, err 406 } 407 m.MaxAge = int64Val 408 default: 409 return m, newDecodeErrorf(expr, errFieldNotSupported, key) 410 } 411 } 412 return m, nil 413 } 414 415 func stringValue(bl *ast.BasicLit) (string, error) { 416 if bl.Kind != token.STRING { 417 return "", newDecodeErrorf(bl, errNonStringAttribute) 418 } 419 return strings.Trim(bl.Value, `"`), nil 420 } 421 422 func (c *metricDecoder) decodeBuckets(expr ast.Expr) ([]float64, error) { 423 switch v := expr.(type) { 424 case *ast.Ident: 425 variableExpr, found := c.variables[v.Name] 426 if !found { 427 return nil, newDecodeErrorf(v, "couldn't find variable for bucket") 428 } 429 switch v2 := variableExpr.(type) { 430 case *ast.CompositeLit: 431 return decodeListOfFloats(v2, v2.Elts) 432 case *ast.CallExpr: 433 float64s, err2, done := c.decodeBucketFunctionCall(v2) 434 if done { 435 return float64s, err2 436 } 437 default: 438 return nil, newDecodeErrorf(v, errorFindingVariableForBuckets) 439 } 440 441 case *ast.CompositeLit: 442 return decodeListOfFloats(v, v.Elts) 443 case *ast.SelectorExpr: 444 variableName := v.Sel.String() 445 importName, ok := v.X.(*ast.Ident) 446 if ok && importName.String() == c.kubeMetricsImportName && variableName == "DefBuckets" { 447 return metrics.DefBuckets, nil 448 } 449 case *ast.CallExpr: 450 float64s, err2, done := c.decodeBucketFunctionCall(v) 451 if done { 452 return float64s, err2 453 } 454 } 455 return nil, newDecodeErrorf(expr, errBuckets) 456 } 457 458 func (c *metricDecoder) decodeBucketFunctionCall(v *ast.CallExpr) ([]float64, error, bool) { 459 se, ok := v.Fun.(*ast.SelectorExpr) 460 if !ok { 461 // support merged 462 if ai, ok := v.Fun.(*ast.Ident); ok && ai.Name == "merge" { 463 merged := []float64{} 464 for _, arg := range v.Args { 465 v2, ok := arg.(*ast.CallExpr) 466 if !ok { 467 return nil, newDecodeErrorf(v2, errBuckets), true 468 } 469 se, ok = v2.Fun.(*ast.SelectorExpr) 470 if ok { 471 functionName := se.Sel.String() 472 functionImport, ok := se.X.(*ast.Ident) 473 if !ok { 474 return nil, newDecodeErrorf(v, errBuckets), true 475 } 476 if functionImport.String() != c.kubeMetricsImportName { 477 return nil, newDecodeErrorf(v, errBuckets), true 478 } 479 firstArg, secondArg, thirdArg, err := decodeBucketArguments(v2) 480 if err != nil { 481 return nil, newDecodeErrorf(v, errBuckets), true 482 } 483 switch functionName { 484 case "LinearBuckets": 485 merged = append(merged, metrics.LinearBuckets(firstArg, secondArg, thirdArg)...) 486 case "ExponentialBuckets": 487 merged = append(merged, metrics.ExponentialBuckets(firstArg, secondArg, thirdArg)...) 488 case "ExponentialBucketsRange": 489 merged = append(merged, metrics.ExponentialBucketsRange(firstArg, secondArg, thirdArg)...) 490 } 491 } 492 } 493 return merged, nil, true 494 } 495 return nil, newDecodeErrorf(v, errBuckets), true 496 } 497 functionName := se.Sel.String() 498 functionImport, ok := se.X.(*ast.Ident) 499 if !ok { 500 return nil, newDecodeErrorf(v, errBuckets), true 501 } 502 if functionImport.String() != c.kubeMetricsImportName { 503 return nil, newDecodeErrorf(v, errBuckets), true 504 } 505 switch functionName { 506 case "LinearBuckets": 507 firstArg, secondArg, thirdArg, err := decodeBucketArguments(v) 508 if err != nil { 509 return nil, err, true 510 } 511 return metrics.LinearBuckets(firstArg, secondArg, thirdArg), nil, true 512 case "ExponentialBuckets": 513 firstArg, secondArg, thirdArg, err := decodeBucketArguments(v) 514 if err != nil { 515 return nil, err, true 516 } 517 return metrics.ExponentialBuckets(firstArg, secondArg, thirdArg), nil, true 518 case "ExponentialBucketsRange": 519 firstArg, secondArg, thirdArg, err := decodeBucketArguments(v) 520 if err != nil { 521 return nil, err, true 522 } 523 return metrics.ExponentialBucketsRange(firstArg, secondArg, thirdArg), nil, true 524 case "MergeBuckets": 525 merged := []float64{} 526 for _, arg := range v.Args { 527 switch argExpr := arg.(type) { 528 case *ast.CompositeLit: 529 fs, err := decodeListOfFloats(argExpr, argExpr.Elts) 530 if err != nil { 531 return nil, newDecodeErrorf(v, errBuckets), true 532 } 533 merged = append(merged, fs...) 534 case *ast.CallExpr: 535 se, ok = argExpr.Fun.(*ast.SelectorExpr) 536 if ok { 537 functionName := se.Sel.String() 538 functionImport, ok := se.X.(*ast.Ident) 539 if !ok { 540 return nil, newDecodeErrorf(v, errBuckets), true 541 } 542 if functionImport.String() != c.kubeMetricsImportName { 543 return nil, newDecodeErrorf(v, errBuckets), true 544 } 545 firstArg, secondArg, thirdArg, err := decodeBucketArguments(argExpr) 546 if err != nil { 547 return nil, newDecodeErrorf(v, errBuckets), true 548 } 549 switch functionName { 550 case "LinearBuckets": 551 merged = append(merged, metrics.LinearBuckets(firstArg, secondArg, thirdArg)...) 552 case "ExponentialBuckets": 553 merged = append(merged, metrics.LinearBuckets(firstArg, secondArg, thirdArg)...) 554 } 555 } 556 } 557 } 558 return merged, nil, true 559 } 560 return nil, nil, false 561 } 562 563 func (c *metricDecoder) decodeObjectives(expr ast.Expr) (map[float64]float64, error) { 564 switch v := expr.(type) { 565 case *ast.CompositeLit: 566 return decodeFloatMap(v.Elts) 567 case *ast.Ident: 568 variableExpr, found := c.variables[v.Name] 569 if !found { 570 return nil, newDecodeErrorf(expr, errBadVariableAttribute) 571 } 572 return decodeFloatMap(variableExpr.(*ast.CompositeLit).Elts) 573 } 574 return nil, newDecodeErrorf(expr, errObjectives) 575 } 576 577 func (c *metricDecoder) decodeUint32(expr ast.Expr) (uint32, error) { 578 switch v := expr.(type) { 579 case *ast.BasicLit: 580 if v.Kind != token.FLOAT && v.Kind != token.INT { 581 print(v.Kind) 582 } 583 value, err := strconv.ParseUint(v.Value, 10, 32) 584 if err != nil { 585 return 0, err 586 } 587 return uint32(value), nil 588 case *ast.SelectorExpr: 589 variableName := v.Sel.String() 590 importName, ok := v.X.(*ast.Ident) 591 if ok && importName.String() == c.kubeMetricsImportName { 592 if variableName == "DefAgeBuckets" { 593 // hardcode this for now 594 return metrics.DefAgeBuckets, nil 595 } 596 if variableName == "DefBufCap" { 597 // hardcode this for now 598 return metrics.DefBufCap, nil 599 } 600 } 601 case *ast.CallExpr: 602 _, ok := v.Fun.(*ast.SelectorExpr) 603 if !ok { 604 return 0, newDecodeErrorf(v, errDecodeUint32) 605 } 606 return 0, nil 607 } 608 return 0, newDecodeErrorf(expr, errDecodeUint32) 609 } 610 611 func (c *metricDecoder) decodeInt64(expr ast.Expr) (int64, error) { 612 switch v := expr.(type) { 613 case *ast.BasicLit: 614 if v.Kind != token.FLOAT && v.Kind != token.INT { 615 print(v.Kind) 616 } 617 618 value, err := strconv.ParseInt(v.Value, 10, 64) 619 if err != nil { 620 return 0, err 621 } 622 return value, nil 623 case *ast.SelectorExpr: 624 variableName := v.Sel.String() 625 importName, ok := v.X.(*ast.Ident) 626 if ok && importName.String() == c.kubeMetricsImportName { 627 if variableName == "DefMaxAge" { 628 // hardcode this for now. This is a duration, but we'll output it as 629 // an int64 representing nanoseconds. 630 return int64(metrics.DefMaxAge), nil 631 } 632 } 633 case *ast.Ident: 634 variableExpr, found := c.variables[v.Name] 635 if found { 636 be, ok := variableExpr.(*ast.BinaryExpr) 637 if ok { 638 i, err2, done := c.extractTimeExpression(be) 639 if done { 640 return i, err2 641 } 642 } 643 } 644 case *ast.CallExpr: 645 _, ok := v.Fun.(*ast.SelectorExpr) 646 if !ok { 647 return 0, newDecodeErrorf(v, errDecodeInt64) 648 } 649 return 0, nil 650 case *ast.BinaryExpr: 651 i, err2, done := c.extractTimeExpression(v) 652 if done { 653 return i, err2 654 } 655 } 656 return 0, newDecodeErrorf(expr, errDecodeInt64) 657 } 658 659 func (c *metricDecoder) extractTimeExpression(v *ast.BinaryExpr) (int64, error, bool) { 660 x := v.X.(*ast.BasicLit) 661 if x.Kind != token.FLOAT && x.Kind != token.INT { 662 print(x.Kind) 663 } 664 665 xValue, err := strconv.ParseInt(x.Value, 10, 64) 666 if err != nil { 667 return 0, err, true 668 } 669 670 switch y := v.Y.(type) { 671 case *ast.SelectorExpr: 672 variableName := y.Sel.String() 673 importName, ok := y.X.(*ast.Ident) 674 if ok && importName.String() == "time" { 675 if variableName == "Hour" { 676 return xValue * int64(time.Hour), nil, true 677 } 678 if variableName == "Minute" { 679 return xValue * int64(time.Minute), nil, true 680 } 681 if variableName == "Second" { 682 return xValue * int64(time.Second), nil, true 683 } 684 } 685 } 686 return 0, nil, false 687 } 688 689 func decodeFloatMap(exprs []ast.Expr) (map[float64]float64, error) { 690 buckets := map[float64]float64{} 691 for _, elt := range exprs { 692 bl, ok := elt.(*ast.KeyValueExpr) 693 if !ok { 694 return nil, newDecodeErrorf(bl, errObjectives) 695 } 696 keyExpr, ok := bl.Key.(*ast.BasicLit) 697 if !ok { 698 return nil, newDecodeErrorf(bl, errObjectives) 699 } 700 valueExpr, ok := bl.Value.(*ast.BasicLit) 701 if !ok { 702 return nil, newDecodeErrorf(bl, errObjectives) 703 } 704 valueForKey, err := strconv.ParseFloat(keyExpr.Value, 64) 705 if err != nil { 706 return nil, newDecodeErrorf(bl, errObjectives) 707 } 708 valueForValue, err := strconv.ParseFloat(valueExpr.Value, 64) 709 if err != nil { 710 return nil, newDecodeErrorf(bl, errObjectives) 711 } 712 buckets[valueForKey] = valueForValue 713 } 714 return buckets, nil 715 } 716 717 func decodeListOfFloats(expr ast.Expr, exprs []ast.Expr) ([]float64, error) { 718 buckets := make([]float64, len(exprs)) 719 for i, elt := range exprs { 720 bl, ok := elt.(*ast.BasicLit) 721 if !ok { 722 return nil, newDecodeErrorf(expr, errBuckets) 723 } 724 if bl.Kind != token.FLOAT && bl.Kind != token.INT { 725 return nil, newDecodeErrorf(bl, errBuckets) 726 } 727 value, err := strconv.ParseFloat(bl.Value, 64) 728 if err != nil { 729 return nil, err 730 } 731 buckets[i] = value 732 } 733 return buckets, nil 734 } 735 736 func decodeBucketArguments(fc *ast.CallExpr) (float64, float64, int, error) { 737 if len(fc.Args) != 3 { 738 return 0, 0, 0, newDecodeErrorf(fc, errBuckets) 739 } 740 strArgs := make([]string, len(fc.Args)) 741 for i, elt := range fc.Args { 742 bl, ok := elt.(*ast.BasicLit) 743 if !ok { 744 return 0, 0, 0, newDecodeErrorf(bl, errBuckets) 745 } 746 if bl.Kind != token.FLOAT && bl.Kind != token.INT { 747 return 0, 0, 0, newDecodeErrorf(bl, errBuckets) 748 } 749 strArgs[i] = bl.Value 750 } 751 firstArg, err := strconv.ParseFloat(strArgs[0], 64) 752 if err != nil { 753 return 0, 0, 0, newDecodeErrorf(fc.Args[0], errBuckets) 754 } 755 secondArg, err := strconv.ParseFloat(strArgs[1], 64) 756 if err != nil { 757 return 0, 0, 0, newDecodeErrorf(fc.Args[1], errBuckets) 758 } 759 thirdArg, err := strconv.ParseInt(strArgs[2], 10, 64) 760 if err != nil { 761 return 0, 0, 0, newDecodeErrorf(fc.Args[2], errBuckets) 762 } 763 764 return firstArg, secondArg, int(thirdArg), nil 765 } 766 func (c *metricDecoder) decodeBuildFQNameArguments(fc *ast.CallExpr) (string, string, string, error) { 767 if len(fc.Args) != 3 { 768 return "", "", "", newDecodeErrorf(fc, "can't decode fq name args") 769 } 770 strArgs := make([]string, len(fc.Args)) 771 for i, elt := range fc.Args { 772 s, err := c.decodeString(elt) 773 if err != nil || s == nil { 774 return "", "", "", newDecodeErrorf(fc, err.Error()) 775 } 776 strArgs[i] = *s 777 } 778 return strArgs[0], strArgs[1], strArgs[2], nil 779 } 780 781 func decodeStabilityLevel(expr ast.Expr, metricsFrameworkImportName string) (*metrics.StabilityLevel, error) { 782 se, ok := expr.(*ast.SelectorExpr) 783 if !ok { 784 return nil, newDecodeErrorf(expr, errStabilityLevel) 785 } 786 s, ok := se.X.(*ast.Ident) 787 if !ok { 788 return nil, newDecodeErrorf(expr, errStabilityLevel) 789 } 790 if s.String() != metricsFrameworkImportName { 791 return nil, newDecodeErrorf(expr, errStabilityLevel) 792 } 793 794 stability := metrics.StabilityLevel(se.Sel.Name) 795 return &stability, nil 796 } 797 798 func (c *metricDecoder) decodeConstLabels(expr ast.Expr) (map[string]string, error) { 799 retval := map[string]string{} 800 switch v := expr.(type) { 801 case *ast.CompositeLit: 802 for _, e2 := range v.Elts { 803 kv := e2.(*ast.KeyValueExpr) 804 key := "" 805 switch k := kv.Key.(type) { 806 807 case *ast.Ident: 808 variableExpr, found := c.variables[k.Name] 809 if !found { 810 return nil, newDecodeErrorf(expr, errBadVariableAttribute) 811 } 812 bl, ok := variableExpr.(*ast.BasicLit) 813 if !ok { 814 return nil, newDecodeErrorf(expr, errNonStringAttribute) 815 } 816 k2, err := stringValue(bl) 817 if err != nil { 818 return nil, err 819 } 820 key = k2 821 case *ast.BasicLit: 822 k2, err := stringValue(k) 823 if err != nil { 824 return nil, err 825 } 826 key = k2 827 } 828 val, err := stringValue(kv.Value.(*ast.BasicLit)) 829 if err != nil { 830 return nil, err 831 } 832 retval[key] = val 833 } 834 } 835 return retval, nil 836 }