forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 7
/
field.go
136 lines (115 loc) · 3.62 KB
/
field.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package common
import (
"fmt"
"strings"
"github.com/elastic/go-ucfg/yaml"
)
//This reflects allowed attributes for field definitions in the fields.yml.
//No logic is put into this data structure.
//The purpose is to enable using different kinds of transformation, on top of the same data structure.
//Current transformation:
// -ElasticSearch Template
// -Kibana Index Pattern
type Fields []Field
type Field struct {
Name string `config:"name"`
Type string `config:"type"`
Description string `config:"description"`
Format string `config:"format"`
ScalingFactor int `config:"scaling_factor"`
Fields Fields `config:"fields"`
MultiFields Fields `config:"multi_fields"`
ObjectType string `config:"object_type"`
Enabled *bool `config:"enabled"`
Analyzer string `config:"analyzer"`
SearchAnalyzer string `config:"search_analyzer"`
Norms bool `config:"norms"`
Dynamic DynamicType `config:"dynamic"`
Index *bool `config:"index"`
DocValues *bool `config:"doc_values"`
CopyTo string `config:"copy_to"`
// Kibana specific
Analyzed *bool `config:"analyzed"`
Count int `config:"count"`
Searchable *bool `config:"searchable"`
Aggregatable *bool `config:"aggregatable"`
Script string `config:"script"`
// Kibana params
Pattern string `config:"pattern"`
InputFormat string `config:"input_format"`
OutputFormat string `config:"output_format"`
OutputPrecision *int `config:"output_precision"`
LabelTemplate string `config:"label_template"`
UrlTemplate []VersionizedString `config:"url_template"`
OpenLinkInCurrentTab *bool `config:"open_link_in_current_tab"`
Path string
}
type VersionizedString struct {
MinVersion string `config:"min_version"`
Value string `config:"value"`
}
type DynamicType struct{ Value interface{} }
func (d *DynamicType) Unpack(s string) error {
switch s {
case "true":
d.Value = true
case "false":
d.Value = false
case "strict":
d.Value = s
default:
return fmt.Errorf("'%v' is invalid dynamic setting", s)
}
return nil
}
func LoadFieldsYaml(path string) (Fields, error) {
keys := []Field{}
cfg, err := yaml.NewConfigWithFile(path)
if err != nil {
return nil, err
}
cfg.Unpack(&keys)
fields := Fields{}
for _, key := range keys {
fields = append(fields, key.Fields...)
}
return fields, nil
}
// HasKey checks if inside fields the given key exists
// The key can be in the form of a.b.c and it will check if the nested field exist
// In case the key is `a` and there is a value `a.b` false is return as it only
// returns true if it's a leave node
func (f Fields) HasKey(key string) bool {
keys := strings.Split(key, ".")
return f.hasKey(keys)
}
// Recursively generates the correct key based on the dots
// The mapping requires "properties" between each layer. This is added here.
func GenerateKey(key string) string {
if strings.Contains(key, ".") {
keys := strings.SplitN(key, ".", 2)
key = keys[0] + ".properties." + GenerateKey(keys[1])
}
return key
}
func (f Fields) hasKey(keys []string) bool {
// Nothing to compare anymore
if len(keys) == 0 {
return false
}
key := keys[0]
keys = keys[1:]
for _, field := range f {
if field.Name == key {
if len(field.Fields) > 0 {
return field.Fields.hasKey(keys)
}
// Last entry in the tree but still more keys
if len(keys) > 0 {
return false
}
return true
}
}
return false
}