Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle base fields imported from nested ECS definitions in a more generic way #779

Merged
merged 1 commit into from
Apr 4, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 39 additions & 14 deletions internal/fields/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,22 @@ func (fds *FieldDefinitions) UnmarshalYAML(value *yaml.Node) error {
return err
}

// Some groups are used by convention in ECS to include
// fields that can appear in the root level of the document.
// Append their child fields directly instead.
// TODO: Make this generic looking for groups whose children don't match.
if name == "base" || name == "tracing" {
fields = append(fields, field.Fields...)
} else {
field.Name = name
cleanNestedNames(field.Name, field.Fields)
fields = append(fields, field)
field.Name = name
baseFields := cleanNested(&field)
if len(baseFields) > 0 {
// Some groups are used by convention in ECS to include
// fields that can appear in the root level of the document.
// Append their child fields directly instead.
// Examples of such groups are `base` or `tracing`.
fields = append(fields, baseFields...)
if len(field.Fields) == 0 {
// If it had base fields, and doesn't have any other
// field, don't add it.
continue
}
}

fields = append(fields, field)
}
*fds = fields
return nil
Expand All @@ -150,10 +155,30 @@ func (fds *FieldDefinitions) UnmarshalYAML(value *yaml.Node) error {
}
}

func cleanNestedNames(parent string, fields []FieldDefinition) {
for i := range fields {
if strings.HasPrefix(fields[i].Name, parent+".") {
fields[i].Name = fields[i].Name[len(parent)+1:]
// cleanNested processes fields nested inside another field, and returns
// defined base fields.
// If a field name is prefixed by the parent field, this part is removed,
// so the full path, taking into account the parent name, matches.
// If a field name is not prefixed by the parent field, this is considered
// a base field, that should appear at the top-level. It is removed from
// the list of nested fields and returned as base field.
func cleanNested(parent *FieldDefinition) (base []FieldDefinition) {
var nested []FieldDefinition
for _, field := range parent.Fields {
// If the field name is prefixed by the name of its parent,
// this is a normal nested field. If not, it is a base field.
if strings.HasPrefix(field.Name, parent.Name+".") {
field.Name = field.Name[len(parent.Name)+1:]
nested = append(nested, field)
} else {
base = append(base, field)
}
}

// At the moment of writing this code, a group field has base fields
// (`base` and `tracing` groups), or nested fields, but not both.
// This code handles the case of having groups with both kinds of fields,
// just in case this happens.
parent.Fields = nested
return base
}