in confgenerator/feature_tracking.go [153:361]
func trackingFeatures(c reflect.Value, md metadata, feature Feature) ([]Feature, error) {
if customFeatures, ok := c.Interface().(CustomFeatures); ok {
cfs, err := customFeatures.ExtractFeatures()
if err != nil {
return nil, err
}
var features []Feature
for _, cf := range cfs {
features = append(features, Feature{
Module: feature.Module,
Kind: feature.Kind,
Type: feature.Type,
Key: append(feature.Key, cf.Key...),
Value: cf.Value,
})
}
return features, nil
}
if md.isExcluded {
return nil, nil
}
t := c.Type()
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if c.IsZero() {
return nil, nil
}
v := reflect.Indirect(c)
if v.Kind() == reflect.Invalid {
return nil, nil
}
var features []Feature
switch kind := t.Kind(); {
case kind == reflect.Struct:
// If struct has tracking it must have a value
if md.hasTracking && !md.hasOverride {
return nil, ErrTrackingOverrideStruct
}
if md.yamlTag != "" {
feature.Key = append(feature.Key, md.yamlTag)
}
if md.hasTracking {
// If struct is inline there is no associated name for key generation
// By default inline structs of a tracked field are also tracked
if md.isInline {
return nil, ErrTrackingInlineStruct
} else {
// For structs that are in a Component. An extra metric is added with
// the value being the override value from the yaml tag
ftr := feature
ftr.Value = md.overrideValue
features = append(features, ftr)
}
}
// Iterate over all available fields and read the tag value
for i := 0; i < t.NumField(); i++ {
// Get the field, returns https://golang.org/pkg/reflect/#StructField
field := t.Field(i)
if !field.IsExported() {
continue
}
// Type field name is part of the ConfigComponent definition.
// All user visible component inlines that component, this field can help
// us assert that a certain component is enabled.
// Capture special metrics for enabled receiver or processor
if field.Name == "Type" {
f := feature
f.Key = append(f.Key, "enabled")
f.Value = "true"
features = append(features, f)
continue
}
f := Feature{
Module: feature.Module,
Kind: feature.Kind,
Type: feature.Type,
Key: append([]string{}, feature.Key...),
Value: feature.Value,
}
tf, err := trackingFeatures(v.Field(i), getMetadata(field), f)
if err != nil {
return nil, err
}
features = append(features, tf...)
}
case kind == reflect.Map:
// Create map length metric
features = append(features, Feature{
Module: feature.Module,
Kind: feature.Kind,
Type: feature.Type,
Key: append(feature.Key, md.yamlTag, "__length"),
Value: fmt.Sprintf("%d", v.Len()),
})
keys := make([]string, 0)
for _, k := range v.MapKeys() {
keys = append(keys, k.String())
}
sort.Strings(keys)
for i, key := range keys {
f := Feature{
Module: feature.Module,
Kind: feature.Kind,
Type: feature.Type,
Key: append(feature.Key, md.yamlTag),
}
vAtKey := v.MapIndex(reflect.ValueOf(key))
t := vAtKey.Type()
fs := make([]Feature, 0)
k := fmt.Sprintf("[%d]", i)
if md.keepKeys {
features = append(features, Feature{
Module: feature.Module,
Kind: feature.Kind,
Type: feature.Type,
Key: append(feature.Key, md.yamlTag, k, "__key"),
Value: key,
})
}
mdCopy := md.deepCopy()
var err error
if t.Kind() == reflect.Struct {
f.Key = append(f.Key, k)
mdCopy.yamlTag = ""
fs, err = trackingFeatures(vAtKey, mdCopy, f)
} else {
mdCopy.yamlTag = k
fs, err = trackingFeatures(vAtKey, mdCopy, f)
}
if err != nil {
return nil, err
}
features = append(features, fs...)
}
case kind == reflect.Slice || kind == reflect.Array:
// Create array length metric
features = append(features, Feature{
Module: feature.Module,
Kind: feature.Kind,
Type: feature.Type,
Key: append(feature.Key, md.yamlTag, "__length"),
Value: fmt.Sprintf("%d", v.Len()),
})
for i := 0; i < v.Len(); i++ {
f := Feature{
Module: feature.Module,
Kind: feature.Kind,
Type: feature.Type,
Key: append(feature.Key, md.yamlTag),
}
v := v.Index(i)
t := v.Type()
fs := make([]Feature, 0)
m2 := md.deepCopy()
var err error
if t.Kind() == reflect.Struct {
f.Key = append(f.Key, fmt.Sprintf("[%d]", i))
m2.yamlTag = ""
fs, err = trackingFeatures(v, m2, f)
} else {
m2.yamlTag = fmt.Sprintf("[%d]", i)
fs, err = trackingFeatures(v, m2, f)
}
if err != nil {
return nil, err
}
features = append(features, fs...)
}
default:
if skipField(v, md) {
return nil, nil
}
feature.Key = append(feature.Key, md.yamlTag)
if md.hasOverride {
feature.Value = md.overrideValue
} else {
feature.Value = fmt.Sprintf("%v", v.Interface())
}
features = append(features, feature)
}
return features, nil
}