Skip to content

Commit

Permalink
metics: allow maps in metrics structs
Browse files Browse the repository at this point in the history
This allows us to have a map of metrics in a struct.

Epic: none
Release note: None
  • Loading branch information
stevendanna committed Oct 31, 2024
1 parent 21fe75e commit 56ff146
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 7 deletions.
20 changes: 13 additions & 7 deletions pkg/util/metric/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ func (r *Registry) AddMetricStruct(metricStruct interface{}) {
}
t := v.Type()

const allowNil = true
const disallowNil = false
for i := 0; i < v.NumField(); i++ {
vfield, tfield := v.Field(i), t.Field(i)
tname := tfield.Name
Expand All @@ -137,14 +139,18 @@ func (r *Registry) AddMetricStruct(metricStruct interface{}) {
for i := 0; i < vfield.Len(); i++ {
velem := vfield.Index(i)
telemName := fmt.Sprintf("%s[%d]", tname, i)
// Permit elements in the array to be nil.
const skipNil = true
r.addMetricValue(ctx, velem, telemName, skipNil, t)
r.addMetricValue(ctx, velem, telemName, allowNil, t)
}
case reflect.Map:
iter := vfield.MapRange()
for iter.Next() {
// telemName is only used for assertion errors.
telemName := iter.Key().String()
r.addMetricValue(ctx, iter.Value(), telemName, allowNil, t)
}
default:
// No metric fields should be nil.
const skipNil = false
r.addMetricValue(ctx, vfield, tname, skipNil, t)
r.addMetricValue(ctx, vfield, tname, disallowNil, t)
}
}
}
Expand Down Expand Up @@ -274,7 +280,7 @@ func checkFieldCanBeSkipped(
}

switch fieldType.Kind() {
case reflect.Array, reflect.Slice:
case reflect.Array, reflect.Slice, reflect.Map:
checkFieldCanBeSkipped(skipReason, fieldName, fieldType.Elem(), parentType)
case reflect.Struct:
containsMetrics := false
Expand Down Expand Up @@ -317,7 +323,7 @@ func containsMetricType(ft reflect.Type) bool {
}

switch ft.Kind() {
case reflect.Slice, reflect.Array:
case reflect.Slice, reflect.Array, reflect.Map:
return containsMetricType(ft.Elem())
case reflect.Struct:
for i := 0; i < ft.NumField(); i++ {
Expand Down
7 changes: 7 additions & 0 deletions pkg/util/metric/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func TestRegistry(t *testing.T) {
StructHistogram IHistogram
NestedStructGauge NestedStruct
ArrayStructCounters [4]*Counter
MapOfCounters map[int32]*Counter
// Ensure that nil struct values in arrays are safe.
NestedStructArray [2]*NestedStruct
// A few extra ones: either not exported, or not metric objects.
Expand Down Expand Up @@ -125,6 +126,10 @@ func TestRegistry(t *testing.T) {
nil, // skipped
NewCounter(Metadata{Name: "array.struct.counter.3"}),
},
MapOfCounters: map[int32]*Counter{
1: NewCounter(Metadata{Name: "map.counter.0"}),
2: NewCounter(Metadata{Name: "map.counter.1"}),
},
NestedStructArray: [2]*NestedStruct{
0: nil, // skipped
1: {
Expand Down Expand Up @@ -154,6 +159,8 @@ func TestRegistry(t *testing.T) {
"array.struct.counter.0": {},
"array.struct.counter.1": {},
"array.struct.counter.3": {},
"map.counter.0": {},
"map.counter.1": {},
"nested.struct.array.1.gauge": {},
}
totalMetrics := len(expNames)
Expand Down

0 comments on commit 56ff146

Please sign in to comment.