Skip to content

Commit 5eaafff

Browse files
kvchruflin
authored andcommitted
Improve fields.yml generator of modules (#7533)
From now on when a user provides a type hint in an Ingest pipeline, it's added to the generated `fields.yml` instead of guessing. Closes #7472
1 parent 731081b commit 5eaafff

File tree

2 files changed

+61
-25
lines changed

2 files changed

+61
-25
lines changed

filebeat/scripts/generator/fields/main.go

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ import (
3333
const (
3434
pipelinePath = "%s/module/%s/%s/ingest/pipeline.json"
3535
fieldsYmlPath = "%s/module/%s/%s/_meta/fields.yml"
36+
37+
typeIdx = 0
38+
elementsIdx = 1
39+
hintIdx = 2
3640
)
3741

3842
var (
@@ -64,8 +68,9 @@ type pipeline struct {
6468
}
6569

6670
type field struct {
67-
Type string
68-
Elements []string
71+
Syntax string
72+
SemanticElements []string
73+
Type string
6974
}
7075

7176
type fieldYml struct {
@@ -92,23 +97,41 @@ func newFieldYml(name, typeName string, noDoc bool) *fieldYml {
9297
}
9398
}
9499

95-
func newField(lp string) field {
96-
lp = lp[1 : len(lp)-1]
97-
ee := strings.Split(lp, ":")
98-
if len(ee) != 2 {
99-
return field{
100-
Type: ee[0],
101-
Elements: nil,
102-
}
100+
func newField(pattern string) field {
101+
if len(pattern) <= 2 {
102+
return field{}
103+
}
104+
pattern = pattern[1 : len(pattern)-1]
105+
106+
elements := strings.Split(pattern, ":")
107+
if !isValidFormat(elements) {
108+
return field{}
109+
}
110+
111+
hint := ""
112+
if containsType(elements) {
113+
hint = elements[hintIdx]
103114
}
104115

105-
e := strings.Split(ee[1], ".")
106116
return field{
107-
Type: ee[0],
108-
Elements: e,
117+
Syntax: elements[typeIdx],
118+
SemanticElements: strings.Split(elements[elementsIdx], "."),
119+
Type: hint,
109120
}
110121
}
111122

123+
// isValidFormat checks if the input can be split correctly
124+
// 1. if lenght is 2, the format is {type}:{field.elements}
125+
// 2. if the lenght is 3, the format is {type}:{field.elements}:{hint}
126+
func isValidFormat(ee []string) bool {
127+
return len(ee) == 2 || len(ee) == 3
128+
}
129+
130+
// the last element is the type hint
131+
func containsType(ee []string) bool {
132+
return len(ee) == 3
133+
}
134+
112135
func readPipeline(beatsPath, module, fileset string) (*pipeline, error) {
113136
pp := fmt.Sprintf(pipelinePath, beatsPath, module, fileset)
114137
r, err := ioutil.ReadFile(pp)
@@ -134,7 +157,7 @@ func addNewField(fs []field, f field) []field {
134157
return append(fs, f)
135158
}
136159

137-
func getElementsFromPatterns(patterns []string) ([]field, error) {
160+
func getSemanticElementsFromPatterns(patterns []string) ([]field, error) {
138161
r, err := regexp.Compile("{[\\.\\w\\:]*}")
139162
if err != nil {
140163
return nil, err
@@ -145,7 +168,7 @@ func getElementsFromPatterns(patterns []string) ([]field, error) {
145168
pp := r.FindAllString(lp, -1)
146169
for _, p := range pp {
147170
f := newField(p)
148-
if f.Elements == nil {
171+
if f.SemanticElements == nil {
149172
continue
150173
}
151174
fs = addNewField(fs, f)
@@ -214,16 +237,16 @@ type processors struct {
214237
}
215238

216239
func (p *processors) processFields() ([]field, error) {
217-
f, err := getElementsFromPatterns(p.patterns)
240+
f, err := getSemanticElementsFromPatterns(p.patterns)
218241
if err != nil {
219242
return nil, err
220243
}
221244

222245
for i, ff := range f {
223-
fs := strings.Join(ff.Elements, ".")
246+
fs := strings.Join(ff.SemanticElements, ".")
224247
for k, mv := range p.rename {
225248
if k == fs {
226-
ff.Elements = strings.Split(mv, ".")
249+
ff.SemanticElements = strings.Split(mv, ".")
227250
}
228251
}
229252
for _, rm := range p.remove {
@@ -275,33 +298,37 @@ func getFieldByName(f []*fieldYml, name string) *fieldYml {
275298
return nil
276299
}
277300

278-
func insertLastField(f []*fieldYml, name, typeName string, noDoc bool) []*fieldYml {
301+
func insertLastField(f []*fieldYml, name string, field field, noDoc bool) []*fieldYml {
279302
ff := getFieldByName(f, name)
280303
if ff != nil {
281304
return f
282305
}
283306

284-
nf := newFieldYml(name, types[typeName], noDoc)
307+
fieldType := field.Type
308+
if fieldType == "" {
309+
fieldType = types[field.Syntax]
310+
}
311+
nf := newFieldYml(name, fieldType, noDoc)
285312
return append(f, nf)
286313
}
287314

288315
func insertGroup(out []*fieldYml, field field, index, count int, noDoc bool) []*fieldYml {
289-
g := getFieldByName(out, field.Elements[index])
316+
g := getFieldByName(out, field.SemanticElements[index])
290317
if g != nil {
291318
g.Fields = generateField(g.Fields, field, index+1, count, noDoc)
292319
return out
293320
}
294321

295322
var groupFields []*fieldYml
296323
groupFields = generateField(groupFields, field, index+1, count, noDoc)
297-
group := newFieldYml(field.Elements[index], "group", noDoc)
324+
group := newFieldYml(field.SemanticElements[index], "group", noDoc)
298325
group.Fields = groupFields
299326
return append(out, group)
300327
}
301328

302329
func generateField(out []*fieldYml, field field, index, count int, noDoc bool) []*fieldYml {
303330
if index+1 == count {
304-
return insertLastField(out, field.Elements[index], field.Type, noDoc)
331+
return insertLastField(out, field.SemanticElements[index], field, noDoc)
305332
}
306333
return insertGroup(out, field, index, count, noDoc)
307334
}
@@ -310,10 +337,10 @@ func generateFields(f []field, noDoc bool) []*fieldYml {
310337
var out []*fieldYml
311338
for _, ff := range f {
312339
index := 1
313-
if len(ff.Elements) == 1 {
340+
if len(ff.SemanticElements) == 1 {
314341
index = 0
315342
}
316-
out = generateField(out, ff, index, len(ff.Elements), noDoc)
343+
out = generateField(out, ff, index, len(ff.SemanticElements), noDoc)
317344
}
318345
return out
319346
}

filebeat/scripts/generator/fields/main_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,15 @@ func TestFieldsGenerator(t *testing.T) {
126126
&fieldYml{Name: "message", Description: "Please add description", Example: "Please add example", Type: "text"},
127127
},
128128
},
129+
FieldsGeneratorTestCase{
130+
patterns: []string{
131+
"\\[%{TIMESTAMP:timestamp}\\] %{NUMBER:idx:int}",
132+
},
133+
fields: []*fieldYml{
134+
&fieldYml{Name: "timestamp", Description: "Please add description", Example: "Please add example", Type: "text"},
135+
&fieldYml{Name: "idx", Description: "Please add description", Example: "Please add example", Type: "int"},
136+
},
137+
},
129138
}
130139

131140
for _, tc := range tests {

0 commit comments

Comments
 (0)