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  }