Skip to content

Commit 2b0df2f

Browse files
kvchjsoriano
authored andcommitted
Port fields.yml collector to Golang (#6911)
Existing Python and shell code is ported to Golang. The previous Beat specific field collection is generalized and moved to the `Makefile` of `libbeat`. A new variable is added to makefiles: `FIELDS_FILE_PATH`. This specifies where `fields.yml` are. Packetbeat's `fields_base.yml` is renamed to `fields.common.yml` to be the same as in other Beats
1 parent 86ba4fb commit 2b0df2f

File tree

21 files changed

+1109
-58
lines changed

21 files changed

+1109
-58
lines changed

CHANGELOG-developer.asciidoc

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ The list below covers the major changes between 6.3.0 and master only.
2121

2222
- The beat.Pipeline is now passed to cfgfile.RunnerFactory. Beats using libbeat for module reloading or autodiscovery need to be adapted. {pull}7018[7017]
2323
- Moving of TLS helper functions and structs from `output/tls` to `tlscommon`. {pull}7054[7054]
24+
- Port fields.yml collector to Golang {pull}6911[6911]
2425

2526
==== Bugfixes
2627

auditbeat/Makefile

+1-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ GOX_OS?=linux windows ## @Building List of all OS to be supported by "make cross
77
DEV_OS?=linux
88
TESTING_ENVIRONMENT?=snapshot-noxpack
99
ES_BEATS?=..
10+
FIELDS_FILE_PATH=module
1011

1112
# Path to the libbeat Makefile
1213
include ${ES_BEATS}/libbeat/scripts/Makefile
@@ -58,13 +59,6 @@ before-build:
5859
.PHONY: collect
5960
collect: fields collect-docs configs kibana
6061

61-
# Collects all module and metricset fields
62-
.PHONY: fields
63-
fields: python-env
64-
@mkdir -p _meta
65-
@cp _meta/fields.common.yml _meta/fields.generated.yml
66-
@${PYTHON_ENV}/bin/python ${ES_BEATS}/metricbeat/scripts/fields_collector.py >> _meta/fields.generated.yml
67-
6862
# Collects all module configs
6963
.PHONY: configs
7064
configs: python-env

auditbeat/include/fields.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

filebeat/Makefile

+2-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ SYSTEM_TESTS?=true
55
TEST_ENVIRONMENT?=true
66
GOX_FLAGS=-arch="amd64 386 arm ppc64 ppc64le"
77
ES_BEATS?=..
8+
FIELDS_FILE_PATH=module
9+
810

911
include ${ES_BEATS}/libbeat/scripts/Makefile
1012

@@ -19,13 +21,6 @@ kibana:
1921
@mkdir -p _meta/kibana
2022
@-cp -r module/*/_meta/kibana _meta/
2123

22-
# Collects all module and dataset fields
23-
.PHONY: fields
24-
fields: python-env
25-
@mkdir -p _meta/
26-
@cp ${ES_BEATS}/filebeat/_meta/fields.common.yml _meta/fields.generated.yml
27-
@${PYTHON_ENV}/bin/python ${ES_BEATS}/metricbeat/scripts/fields_collector.py >> _meta/fields.generated.yml
28-
2924
# Collects all modules files to be packaged in a temporary folder
3025
.PHONY: modules
3126
modules:

filebeat/include/fields.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

generator/beat/Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1+
override FIELDS_FILE_PATH=
2+
export FIELDS_FILE_PATH
3+
14
include ../common/Makefile

generator/beat/{beat}/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,4 @@ before-build:
4646

4747
# Collects all dependencies and then calls update
4848
.PHONY: collect
49-
collect:
49+
collect: fields

generator/common/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ BEAT_PATH=${BUILD_DIR}/src/beatpath/testbeat
66
ES_BEATS=${GOPATH}/src/github.com/elastic/beats
77
PREPARE_COMMAND?=
88

9+
910
# Runs test build for mock beat
1011
.PHONY: test
1112
test: prepare-test

generator/metricbeat/Makefile

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
BEAT_TYPE=metricbeat
2-
PREPARE_COMMAND=MODULE=elastic METRICSET=test make create-metricset ;
2+
PREPARE_COMMAND=MODULE=elastic METRICSET=test make create-metricset ; FIELDS_FILE_PATH=module
3+
override FIELDS_FILE_PATH=
4+
export FIELDS_FILE_PATH
5+
36

47
include ../common/Makefile
58

69
prepare-test:: python-env
710

811
mkdir -p ${BEAT_PATH}/scripts
912
rsync -a --exclude=build ${PWD}/../../metricbeat/scripts/generate_imports_helper.py ${BEAT_PATH}/scripts
13+
14+
# Collects all dependencies and then calls update
15+
.PHONY: collect
16+
collect: fields

heartbeat/Makefile

+1-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ BEAT_PACKAGE_NAME=heartbeat-elastic
44
BEAT_DESCRIPTION?=Ping remote services for availability and log results to Elasticsearch or send to Logstash.
55
SYSTEM_TESTS=true
66
TEST_ENVIRONMENT=false
7+
FIELDS_FILE_PATH=monitors/active
78

89
# Path to the libbeat Makefile
910
-include ../libbeat/scripts/Makefile
@@ -16,13 +17,6 @@ before-build:
1617
.PHONY: collect
1718
collect: fields imports
1819

19-
# Collects all module and metricset fields
20-
.PHONY: fields
21-
fields:
22-
@mkdir -p _meta/
23-
@cp ${ES_BEATS}/heartbeat/_meta/fields.common.yml _meta/fields.generated.yml
24-
@cat ${ES_BEATS}/heartbeat/monitors/active/*/_meta/fields.yml >> _meta/fields.generated.yml
25-
2620
# Generate imports for all monitors
2721
.PHONY: imports
2822
imports: python-env

libbeat/Makefile

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
BEAT_NAME=libbeat
22
TEST_ENVIRONMENT?=true
33
SYSTEM_TESTS=true
4+
FIELDS_FILE_PATH=processors
45

56
include scripts/Makefile
67

7-
# Collects all fields from processors
8-
.PHONY: fields
9-
fields:
10-
@cp _meta/fields.common.yml _meta/fields.generated.yml
11-
@cat processors/*/_meta/fields.yml >> _meta/fields.generated.yml
12-
138
# Collects all dependencies and then calls update
149
.PHONY: collect
15-
collect: fields
10+
collect: libbeat_fields

libbeat/generator/fields/fields.go

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package fields
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"io/ioutil"
7+
"os"
8+
"path"
9+
"path/filepath"
10+
"strings"
11+
)
12+
13+
var (
14+
generatedFieldsYml = filepath.Join("_meta", "fields.generated.yml")
15+
)
16+
17+
// YmlFile holds the info on files and how to write them into the global fields.yml
18+
type YmlFile struct {
19+
Path string
20+
Indent int
21+
}
22+
23+
func collectBeatFiles(beatPath string, fieldFiles []*YmlFile) ([]*YmlFile, error) {
24+
commonFields := filepath.Join(beatPath, "_meta", "fields.common.yml")
25+
_, err := os.Stat(commonFields)
26+
if os.IsNotExist(err) {
27+
return fieldFiles, nil
28+
} else if err != nil {
29+
return nil, err
30+
}
31+
32+
files := []*YmlFile{
33+
&YmlFile{
34+
Path: commonFields,
35+
Indent: 0,
36+
},
37+
}
38+
39+
return append(files, fieldFiles...), nil
40+
}
41+
42+
func writeGeneratedFieldsYml(beatsPath string, fieldFiles []*YmlFile) error {
43+
outPath := path.Join(beatsPath, generatedFieldsYml)
44+
f, err := os.Create(outPath)
45+
if err != nil {
46+
return err
47+
}
48+
defer f.Close()
49+
50+
fw := bufio.NewWriter(f)
51+
for _, p := range fieldFiles {
52+
ff, err := os.Open(p.Path)
53+
if err != nil {
54+
return err
55+
}
56+
defer ff.Close()
57+
58+
fs := bufio.NewScanner(ff)
59+
for fs.Scan() {
60+
err = writeIndentedLine(fw, fs.Text()+"\n", p.Indent)
61+
if err != nil {
62+
return err
63+
}
64+
65+
}
66+
if err := fs.Err(); err != nil {
67+
return err
68+
}
69+
}
70+
return nil
71+
}
72+
73+
func writeIndentedLine(fw *bufio.Writer, l string, indent int) error {
74+
ll := strings.Repeat(" ", indent) + l
75+
fmt.Fprint(fw, ll)
76+
return fw.Flush()
77+
}
78+
79+
// Generate collects fields.yml files and concatenates them into one global file.
80+
func Generate(esBeatsPath, beatPath string, files []*YmlFile) error {
81+
files, err := collectBeatFiles(beatPath, files)
82+
if err != nil {
83+
return err
84+
}
85+
86+
err = writeGeneratedFieldsYml(beatPath, files)
87+
if err != nil {
88+
return err
89+
}
90+
91+
return AppendFromLibbeat(esBeatsPath, beatPath)
92+
}
93+
94+
// AppendFromLibbeat appends fields.yml of libbeat to the fields.yml
95+
func AppendFromLibbeat(esBeatsPath, beatPath string) error {
96+
fieldsMetaPath := path.Join(beatPath, "_meta", "fields.yml")
97+
generatedPath := path.Join(beatPath, generatedFieldsYml)
98+
99+
err := createIfNotExists(fieldsMetaPath, generatedPath)
100+
if err != nil {
101+
return err
102+
}
103+
104+
if isLibbeat(beatPath) {
105+
out := filepath.Join(esBeatsPath, "libbeat", "fields.yml")
106+
return copyFileWithFlag(generatedPath, out, os.O_RDWR|os.O_CREATE|os.O_TRUNC)
107+
}
108+
109+
libbeatPath := filepath.Join(esBeatsPath, "libbeat", generatedFieldsYml)
110+
out := filepath.Join(beatPath, "fields.yml")
111+
err = copyFileWithFlag(libbeatPath, out, os.O_RDWR|os.O_CREATE|os.O_TRUNC)
112+
if err != nil {
113+
return err
114+
}
115+
return copyFileWithFlag(generatedPath, out, os.O_WRONLY|os.O_APPEND)
116+
}
117+
118+
func isLibbeat(beatPath string) bool {
119+
return filepath.Base(beatPath) == "libbeat"
120+
}
121+
122+
func createIfNotExists(inPath, outPath string) error {
123+
_, err := os.Stat(outPath)
124+
if os.IsNotExist(err) {
125+
err := copyFileWithFlag(inPath, outPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC)
126+
if err != nil {
127+
fmt.Println("Cannot find _meta/fields.yml")
128+
}
129+
return nil
130+
}
131+
return err
132+
}
133+
134+
func copyFileWithFlag(in, out string, flag int) error {
135+
input, err := ioutil.ReadFile(in)
136+
if err != nil {
137+
return err
138+
}
139+
140+
output, err := os.OpenFile(out, flag, 0644)
141+
if err != nil {
142+
return err
143+
}
144+
defer output.Close()
145+
146+
_, err = output.Write(input)
147+
return err
148+
149+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package fields
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"path/filepath"
7+
)
8+
9+
var indentByModule = map[string]int{
10+
"processors": 0,
11+
"module": 8,
12+
"active": 8,
13+
"protos": 8,
14+
}
15+
16+
// CollectModuleFiles looks for fields.yml files under the
17+
// specified root directory
18+
func CollectModuleFiles(root string) ([]*YmlFile, error) {
19+
modules, err := ioutil.ReadDir(root)
20+
if err != nil {
21+
return nil, err
22+
}
23+
24+
var files []*YmlFile
25+
for _, m := range modules {
26+
f, err := collectFiles(m, root)
27+
if err != nil {
28+
return nil, err
29+
}
30+
files = append(files, f...)
31+
}
32+
33+
return files, nil
34+
}
35+
36+
func collectFiles(module os.FileInfo, modulesPath string) ([]*YmlFile, error) {
37+
if !module.IsDir() {
38+
return nil, nil
39+
}
40+
41+
var files []*YmlFile
42+
fieldsYmlPath := filepath.Join(modulesPath, module.Name(), "_meta", "fields.yml")
43+
if _, err := os.Stat(fieldsYmlPath); !os.IsNotExist(err) {
44+
files = append(files, &YmlFile{
45+
Path: fieldsYmlPath,
46+
Indent: 0,
47+
})
48+
} else if !os.IsNotExist(err) && err != nil {
49+
return nil, err
50+
}
51+
52+
modulesRoot := filepath.Base(modulesPath)
53+
sets, err := ioutil.ReadDir(filepath.Join(modulesPath, module.Name()))
54+
if err != nil {
55+
return nil, err
56+
}
57+
58+
for _, s := range sets {
59+
if !s.IsDir() {
60+
continue
61+
}
62+
63+
fieldsYmlPath = filepath.Join(modulesPath, module.Name(), s.Name(), "_meta", "fields.yml")
64+
if _, err = os.Stat(fieldsYmlPath); !os.IsNotExist(err) {
65+
files = append(files, &YmlFile{
66+
Path: fieldsYmlPath,
67+
Indent: indentByModule[modulesRoot],
68+
})
69+
} else if !os.IsNotExist(err) && err != nil {
70+
return nil, err
71+
}
72+
}
73+
return files, nil
74+
}

libbeat/scripts/Makefile

+12-10
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,19 @@ coverage-report:
304304
test ! -s ${COVERAGE_DIR}/unit.cov || go tool cover -html=${COVERAGE_DIR}/unit.cov -o ${COVERAGE_DIR}/unit.html
305305

306306

307+
.PHONY: fields
308+
fields:
309+
echo $(PWD)
310+
@go run ${ES_BEATS}/libbeat/scripts/cmd/global_fields/main.go --es_beats_path $(ES_BEATS) --beat_path $(PWD) $(FIELDS_FILE_PATH)
311+
312+
313+
.PHONY: libbeat_fields
314+
libbeat_fields:
315+
@$(MAKE) -C ${ES_BEATS}/libbeat fields
316+
307317
.PHONY: update
308318
update: ## @build Update expects the most recent version of libbeat in the GOPATH
309-
update: python-env collect
319+
update: python-env libbeat_fields collect
310320
@echo "Updating generated files for ${BEAT_NAME}"
311321

312322
@# Update config files.
@@ -324,15 +334,7 @@ ifeq ($(BEAT_REF_YAML),true)
324334
@chmod 0640 ${BEAT_NAME}.reference.yml
325335
endif
326336

327-
@# Update libbeat fields.generated.yml
328-
@$(MAKE) -C ${ES_BEATS}/libbeat fields
329-
330-
@# Update fields.yml
331-
@test -s _meta/fields.generated.yml || cp _meta/fields.yml _meta/fields.generated.yml
332-
ifeq ($(BEAT_NAME), libbeat)
333-
@cp ${ES_BEATS}/libbeat/_meta/fields.generated.yml fields.yml
334-
else
335-
@cat ${ES_BEATS}/libbeat/_meta/fields.generated.yml _meta/fields.generated.yml > fields.yml
337+
ifneq ($(BEAT_NAME), libbeat)
336338
mkdir -p include
337339
go run ${ES_BEATS}/dev-tools/cmd/asset/asset.go -pkg include fields.yml $(BEAT_NAME) > include/fields.go
338340
endif

0 commit comments

Comments
 (0)