@@ -157,6 +157,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
157157 compiledCommon : * cc ,
158158 ValueFrom : valueFromPath ,
159159 NilIsZero : m .Gauge .NilIsZero ,
160+ labelFromKey : m .Gauge .LabelFromKey ,
160161 }, nil
161162 case MetricTypeInfo :
162163 if m .Info == nil {
@@ -168,6 +169,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
168169 }
169170 return & compiledInfo {
170171 compiledCommon : * cc ,
172+ labelFromKey : m .Info .LabelFromKey ,
171173 }, nil
172174 case MetricTypeStateSet :
173175 if m .StateSet == nil {
@@ -195,23 +197,8 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
195197type compiledGauge struct {
196198 compiledCommon
197199 ValueFrom valuePath
198- LabelFromKey string
199200 NilIsZero bool
200- }
201-
202- func newCompiledGauge (m * MetricGauge ) (* compiledGauge , error ) {
203- cc , err := compileCommon (m .MetricMeta )
204- if err != nil {
205- return nil , fmt .Errorf ("compile common: %w" , err )
206- }
207- valueFromPath , err := compilePath (m .ValueFrom )
208- if err != nil {
209- return nil , fmt .Errorf ("compile path ValueFrom: %w" , err )
210- }
211- return & compiledGauge {
212- compiledCommon : * cc ,
213- ValueFrom : valueFromPath ,
214- }, nil
201+ labelFromKey string
215202}
216203
217204func (c * compiledGauge ) Values (v interface {}) (result []eachValue , errs []error ) {
@@ -227,8 +214,8 @@ func (c *compiledGauge) Values(v interface{}) (result []eachValue, errs []error)
227214 onError (fmt .Errorf ("[%s]: %w" , key , err ))
228215 continue
229216 }
230- if key != "" && c .LabelFromKey != "" {
231- ev .Labels [c .LabelFromKey ] = key
217+ if key != "" && c .labelFromKey != "" {
218+ ev .Labels [c .labelFromKey ] = key
232219 }
233220 addPathLabels (it , c .LabelFromPath (), ev .Labels )
234221 result = append (result , * ev )
@@ -257,22 +244,54 @@ func (c *compiledGauge) Values(v interface{}) (result []eachValue, errs []error)
257244
258245type compiledInfo struct {
259246 compiledCommon
247+ labelFromKey string
260248}
261249
262250func (c * compiledInfo ) Values (v interface {}) (result []eachValue , errs []error ) {
263- if vs , isArray := v .([]interface {}); isArray {
264- for _ , obj := range vs {
251+ onError := func (err ... error ) {
252+ errs = append (errs , fmt .Errorf ("%s: %v" , c .Path (), err ))
253+ }
254+
255+ switch iter := v .(type ) {
256+ case []interface {}:
257+ for _ , obj := range iter {
265258 ev , err := c .values (obj )
266259 if len (err ) > 0 {
267- errs = append ( errs , err ... )
260+ onError ( err ... )
268261 continue
269262 }
270263 result = append (result , ev ... )
271264 }
272- return
265+ default :
266+ value , err := c .values (v )
267+ if err != nil {
268+ onError (err ... )
269+ break
270+ }
271+ // labelFromKey logic
272+ if vv , ok := v .(map [string ]interface {}); ok {
273+ for key , val := range vv {
274+ if key != "" && c .labelFromKey != "" {
275+ n , err := toFloat64 (val , false )
276+ if err != nil {
277+ onError (err )
278+ continue
279+ }
280+ result = append (result , eachValue {
281+ Labels : map [string ]string {
282+ c .labelFromKey : key ,
283+ },
284+ Value : n ,
285+ })
286+ }
287+ }
288+ }
289+ if len (result ) == 0 {
290+ result = value
291+ }
273292 }
274293
275- return c . values ( v )
294+ return
276295}
277296
278297func (c * compiledInfo ) values (v interface {}) (result []eachValue , err []error ) {
@@ -355,7 +374,7 @@ func less(a, b map[string]string) bool {
355374
356375func (c compiledGauge ) value (it interface {}) (* eachValue , error ) {
357376 labels := make (map [string ]string )
358- value , err := getNum (c .ValueFrom .Get (it ), c .NilIsZero )
377+ value , err := toFloat64 (c .ValueFrom .Get (it ), c .NilIsZero )
359378 if err != nil {
360379 return nil , fmt .Errorf ("%s: %w" , c .ValueFrom , err )
361380 }
@@ -478,7 +497,7 @@ func compilePath(path []string) (out valuePath, _ error) {
478497 return nil , fmt .Errorf ("invalid list lookup: %s" , part )
479498 }
480499 key , val := eq [0 ], eq [1 ]
481- num , notNum := getNum (val , false )
500+ num , notNum := toFloat64 (val , false )
482501 boolVal , notBool := strconv .ParseBool (val )
483502 out = append (out , pathOp {
484503 part : part ,
@@ -496,7 +515,7 @@ func compilePath(path []string) (out valuePath, _ error) {
496515 }
497516
498517 if notNum == nil {
499- if i , err := getNum (candidate , false ); err == nil && num == i {
518+ if i , err := toFloat64 (candidate , false ); err == nil && num == i {
500519 return m
501520 }
502521 }
@@ -522,13 +541,14 @@ func compilePath(path []string) (out valuePath, _ error) {
522541 } else if s , ok := m .([]interface {}); ok {
523542 i , err := strconv .Atoi (part )
524543 if err != nil {
525- return nil
544+ return fmt . Errorf ( "invalid list index: %s" , part )
526545 }
527546 if i < 0 {
547+ // negative index
528548 i += len (s )
529549 }
530550 if ! (0 <= i && i < len (s )) {
531- return nil
551+ return fmt . Errorf ( "list index out of range: %s" , part )
532552 }
533553 return s [i ]
534554 }
@@ -544,6 +564,7 @@ func famGen(f compiledFamily) generator.FamilyGenerator {
544564 errLog := klog .V (f .ErrorLogV )
545565 return generator.FamilyGenerator {
546566 Name : f .Name ,
567+ // TODO(@rexagod): This should be dynamic.
547568 Type : metric .Gauge ,
548569 Help : f .Help ,
549570 GenerateFunc : func (obj interface {}) * metric.Family {
@@ -585,8 +606,8 @@ func scrapeValuesFor(e compiledEach, obj map[string]interface{}) ([]eachValue, [
585606 return result , errs
586607}
587608
588- // getNum converts the value to a float64 which is the value type for any metric.
589- func getNum (value interface {}, nilIsZero bool ) (float64 , error ) {
609+ // toFloat64 converts the value to a float64 which is the value type for any metric.
610+ func toFloat64 (value interface {}, nilIsZero bool ) (float64 , error ) {
590611 var v float64
591612 // same as bool==false but for bool pointers
592613 if value == nil {
0 commit comments