@@ -157,6 +157,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
157
157
compiledCommon : * cc ,
158
158
ValueFrom : valueFromPath ,
159
159
NilIsZero : m .Gauge .NilIsZero ,
160
+ labelFromKey : m .Gauge .LabelFromKey ,
160
161
}, nil
161
162
case MetricTypeInfo :
162
163
if m .Info == nil {
@@ -168,6 +169,7 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
168
169
}
169
170
return & compiledInfo {
170
171
compiledCommon : * cc ,
172
+ labelFromKey : m .Info .LabelFromKey ,
171
173
}, nil
172
174
case MetricTypeStateSet :
173
175
if m .StateSet == nil {
@@ -195,23 +197,8 @@ func newCompiledMetric(m Metric) (compiledMetric, error) {
195
197
type compiledGauge struct {
196
198
compiledCommon
197
199
ValueFrom valuePath
198
- LabelFromKey string
199
200
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
215
202
}
216
203
217
204
func (c * compiledGauge ) Values (v interface {}) (result []eachValue , errs []error ) {
@@ -227,8 +214,12 @@ func (c *compiledGauge) Values(v interface{}) (result []eachValue, errs []error)
227
214
onError (fmt .Errorf ("[%s]: %w" , key , err ))
228
215
continue
229
216
}
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
232
223
}
233
224
addPathLabels (it , c .LabelFromPath (), ev .Labels )
234
225
result = append (result , * ev )
@@ -257,22 +248,53 @@ func (c *compiledGauge) Values(v interface{}) (result []eachValue, errs []error)
257
248
258
249
type compiledInfo struct {
259
250
compiledCommon
251
+ labelFromKey string
260
252
}
261
253
262
254
func (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 {
265
262
ev , err := c .values (obj )
266
263
if len (err ) > 0 {
267
- errs = append ( errs , err ... )
264
+ onError ( err ... )
268
265
continue
269
266
}
270
267
result = append (result , ev ... )
271
268
}
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 )
273
295
}
274
296
275
- return c . values ( v )
297
+ return
276
298
}
277
299
278
300
func (c * compiledInfo ) values (v interface {}) (result []eachValue , err []error ) {
@@ -281,7 +303,9 @@ func (c *compiledInfo) values(v interface{}) (result []eachValue, err []error) {
281
303
}
282
304
value := eachValue {Value : 1 , Labels : map [string ]string {}}
283
305
addPathLabels (v , c .labelFromPath , value .Labels )
284
- result = append (result , value )
306
+ if len (value .Labels ) != 0 {
307
+ result = append (result , value )
308
+ }
285
309
return
286
310
}
287
311
@@ -355,7 +379,7 @@ func less(a, b map[string]string) bool {
355
379
356
380
func (c compiledGauge ) value (it interface {}) (* eachValue , error ) {
357
381
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 )
359
383
if err != nil {
360
384
return nil , fmt .Errorf ("%s: %w" , c .ValueFrom , err )
361
385
}
@@ -478,7 +502,7 @@ func compilePath(path []string) (out valuePath, _ error) {
478
502
return nil , fmt .Errorf ("invalid list lookup: %s" , part )
479
503
}
480
504
key , val := eq [0 ], eq [1 ]
481
- num , notNum := getNum (val , false )
505
+ num , notNum := toFloat64 (val , false )
482
506
boolVal , notBool := strconv .ParseBool (val )
483
507
out = append (out , pathOp {
484
508
part : part ,
@@ -496,7 +520,7 @@ func compilePath(path []string) (out valuePath, _ error) {
496
520
}
497
521
498
522
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 {
500
524
return m
501
525
}
502
526
}
@@ -522,13 +546,14 @@ func compilePath(path []string) (out valuePath, _ error) {
522
546
} else if s , ok := m .([]interface {}); ok {
523
547
i , err := strconv .Atoi (part )
524
548
if err != nil {
525
- return nil
549
+ return fmt . Errorf ( "invalid list index: %s" , part )
526
550
}
527
551
if i < 0 {
552
+ // negative index
528
553
i += len (s )
529
554
}
530
555
if ! (0 <= i && i < len (s )) {
531
- return nil
556
+ return fmt . Errorf ( "list index out of range: %s" , part )
532
557
}
533
558
return s [i ]
534
559
}
@@ -544,6 +569,7 @@ func famGen(f compiledFamily) generator.FamilyGenerator {
544
569
errLog := klog .V (f .ErrorLogV )
545
570
return generator.FamilyGenerator {
546
571
Name : f .Name ,
572
+ // TODO(@rexagod): This should be dynamic.
547
573
Type : metric .Gauge ,
548
574
Help : f .Help ,
549
575
GenerateFunc : func (obj interface {}) * metric.Family {
@@ -585,8 +611,8 @@ func scrapeValuesFor(e compiledEach, obj map[string]interface{}) ([]eachValue, [
585
611
return result , errs
586
612
}
587
613
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 ) {
590
616
var v float64
591
617
// same as bool==false but for bool pointers
592
618
if value == nil {
0 commit comments