@@ -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,12 @@ 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 _ , ok := ev .Labels [c .labelFromKey ]; ok {
218+ onError (fmt .Errorf ("labelFromKey (%s) generated labels conflict with labelsFromPath, consider renaming it" , c .labelFromKey ))
219+ continue
220+ }
221+ if key != "" && c .labelFromKey != "" {
222+ ev .Labels [c .labelFromKey ] = key
232223 }
233224 addPathLabels (it , c .LabelFromPath (), ev .Labels )
234225 result = append (result , * ev )
@@ -257,22 +248,53 @@ func (c *compiledGauge) Values(v interface{}) (result []eachValue, errs []error)
257248
258249type compiledInfo struct {
259250 compiledCommon
251+ labelFromKey string
260252}
261253
262254func (c * compiledInfo ) Values (v interface {}) (result []eachValue , errs []error ) {
263- if vs , isArray := v .([]interface {}); isArray {
264- for _ , obj := range vs {
255+ onError := func (err ... error ) {
256+ errs = append (errs , fmt .Errorf ("%s: %v" , c .Path (), err ))
257+ }
258+
259+ switch iter := v .(type ) {
260+ case []interface {}:
261+ for _ , obj := range iter {
265262 ev , err := c .values (obj )
266263 if len (err ) > 0 {
267- errs = append ( errs , err ... )
264+ onError ( err ... )
268265 continue
269266 }
270267 result = append (result , ev ... )
271268 }
272- return
269+ case map [string ]interface {}:
270+ value , err := c .values (v )
271+ if err != nil {
272+ onError (err ... )
273+ break
274+ }
275+ for _ , ev := range value {
276+ if _ , ok := ev .Labels [c .labelFromKey ]; ok {
277+ onError (fmt .Errorf ("labelFromKey (%s) generated labels conflict with labelsFromPath, consider renaming it" , c .labelFromKey ))
278+ continue
279+ }
280+ }
281+ // labelFromKey logic
282+ for key := range iter {
283+ if key != "" && c .labelFromKey != "" {
284+ result = append (result , eachValue {
285+ Labels : map [string ]string {
286+ c .labelFromKey : key ,
287+ },
288+ Value : 1 ,
289+ })
290+ }
291+ }
292+ result = append (result , value ... )
293+ default :
294+ result , errs = c .values (v )
273295 }
274296
275- return c . values ( v )
297+ return
276298}
277299
278300func (c * compiledInfo ) values (v interface {}) (result []eachValue , err []error ) {
@@ -281,7 +303,9 @@ func (c *compiledInfo) values(v interface{}) (result []eachValue, err []error) {
281303 }
282304 value := eachValue {Value : 1 , Labels : map [string ]string {}}
283305 addPathLabels (v , c .labelFromPath , value .Labels )
284- result = append (result , value )
306+ if len (value .Labels ) != 0 {
307+ result = append (result , value )
308+ }
285309 return
286310}
287311
@@ -355,7 +379,7 @@ func less(a, b map[string]string) bool {
355379
356380func (c compiledGauge ) value (it interface {}) (* eachValue , error ) {
357381 labels := make (map [string ]string )
358- value , err := getNum (c .ValueFrom .Get (it ), c .NilIsZero )
382+ value , err := toFloat64 (c .ValueFrom .Get (it ), c .NilIsZero )
359383 if err != nil {
360384 return nil , fmt .Errorf ("%s: %w" , c .ValueFrom , err )
361385 }
@@ -478,7 +502,7 @@ func compilePath(path []string) (out valuePath, _ error) {
478502 return nil , fmt .Errorf ("invalid list lookup: %s" , part )
479503 }
480504 key , val := eq [0 ], eq [1 ]
481- num , notNum := getNum (val , false )
505+ num , notNum := toFloat64 (val , false )
482506 boolVal , notBool := strconv .ParseBool (val )
483507 out = append (out , pathOp {
484508 part : part ,
@@ -496,7 +520,7 @@ func compilePath(path []string) (out valuePath, _ error) {
496520 }
497521
498522 if notNum == nil {
499- if i , err := getNum (candidate , false ); err == nil && num == i {
523+ if i , err := toFloat64 (candidate , false ); err == nil && num == i {
500524 return m
501525 }
502526 }
@@ -522,13 +546,14 @@ func compilePath(path []string) (out valuePath, _ error) {
522546 } else if s , ok := m .([]interface {}); ok {
523547 i , err := strconv .Atoi (part )
524548 if err != nil {
525- return nil
549+ return fmt . Errorf ( "invalid list index: %s" , part )
526550 }
527551 if i < 0 {
552+ // negative index
528553 i += len (s )
529554 }
530555 if ! (0 <= i && i < len (s )) {
531- return nil
556+ return fmt . Errorf ( "list index out of range: %s" , part )
532557 }
533558 return s [i ]
534559 }
@@ -544,6 +569,7 @@ func famGen(f compiledFamily) generator.FamilyGenerator {
544569 errLog := klog .V (f .ErrorLogV )
545570 return generator.FamilyGenerator {
546571 Name : f .Name ,
572+ // TODO(@rexagod): This should be dynamic.
547573 Type : metric .Gauge ,
548574 Help : f .Help ,
549575 GenerateFunc : func (obj interface {}) * metric.Family {
@@ -585,8 +611,8 @@ func scrapeValuesFor(e compiledEach, obj map[string]interface{}) ([]eachValue, [
585611 return result , errs
586612}
587613
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 ) {
614+ // toFloat64 converts the value to a float64 which is the value type for any metric.
615+ func toFloat64 (value interface {}, nilIsZero bool ) (float64 , error ) {
590616 var v float64
591617 // same as bool==false but for bool pointers
592618 if value == nil {
0 commit comments