forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 1
/
mapstrstr.go
160 lines (129 loc) · 4.1 KB
/
mapstrstr.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
Package mapstrstr contains utilities for transforming map[string]string objects
into metricbeat events. For example, given this input object:
input := map[string]interface{}{
"testString": "hello",
"testInt": "42",
"testBool": "true",
"testFloat": "42.1",
"testObjString": "hello, object",
}
And the requirement to transform it into this one:
common.MapStr{
"test_string": "hello",
"test_int": int64(42),
"test_bool": true,
"test_float": 42.1,
"test_obj": common.MapStr{
"test_obj_string": "hello, object",
},
}
It can be done with the following code:
schema := s.Schema{
"test_string": Str("testString"),
"test_int": Int("testInt"),
"test_bool": Bool("testBool"),
"test_float": Float("testFloat"),
"test_obj": s.Object{
"test_obj_string": Str("testObjString"),
},
}
schema.Apply(input)
Note that this allows parsing, renaming of fields and restructuring the result
object.
*/
package mapstrstr
import (
"fmt"
"strconv"
"time"
"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/metricbeat/schema"
)
// toBool converts value to bool. In case of error, returns false
func toBool(key string, data map[string]interface{}) (interface{}, error) {
str, err := getString(key, data)
if err != nil {
return false, err
}
value, err := strconv.ParseBool(str)
if err != nil {
return false, fmt.Errorf("Error converting param to bool: %s", key)
}
return value, nil
}
// Bool creates a Conv object for parsing booleans
func Bool(key string, opts ...schema.SchemaOption) schema.Conv {
return schema.SetOptions(schema.Conv{Key: key, Func: toBool}, opts)
}
// toFloat converts value to float64. In case of error, returns 0.0
func toFloat(key string, data map[string]interface{}) (interface{}, error) {
str, err := getString(key, data)
if err != nil {
return false, err
}
value, err := strconv.ParseFloat(str, 64)
if err != nil {
return 0.0, fmt.Errorf("Error converting param to float: %s", key)
}
return value, nil
}
// Float creates a Conv object for parsing floats
func Float(key string, opts ...schema.SchemaOption) schema.Conv {
return schema.SetOptions(schema.Conv{Key: key, Func: toFloat}, opts)
}
// toInt converts value to int. In case of error, returns 0
func toInt(key string, data map[string]interface{}) (interface{}, error) {
str, err := getString(key, data)
if err != nil {
return false, err
}
value, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return 0, fmt.Errorf("Error converting param to int: %s", key)
}
return value, nil
}
// Int creates a Conv object for parsing integers
func Int(key string, opts ...schema.SchemaOption) schema.Conv {
return schema.SetOptions(schema.Conv{Key: key, Func: toInt}, opts)
}
// toStr converts value to str. In case of error, returns ""
func toStr(key string, data map[string]interface{}) (interface{}, error) {
return getString(key, data)
}
// Time creates a schema.Conv object for parsing timestamps. Unlike the
// other functions, Time receives a `layout` parameter which defines the
// time.Time layout to use for parsing.
func Time(layout, key string, opts ...schema.SchemaOption) schema.Conv {
return schema.SetOptions(schema.Conv{
Key: key,
Func: func(key string, data map[string]interface{}) (interface{}, error) {
str, err := getString(key, data)
if err != nil {
return false, err
}
value, err := time.Parse(layout, str)
if err != nil {
return 0, fmt.Errorf("Error converting param to time.Time: %s. Original: %s", key, str)
}
return common.Time(value), nil
},
}, opts)
}
// Str creates a schema.Conv object for parsing strings
func Str(key string, opts ...schema.SchemaOption) schema.Conv {
return schema.SetOptions(schema.Conv{Key: key, Func: toStr}, opts)
}
// checkExists checks if a key exists in the given data set
func getString(key string, data map[string]interface{}) (string, error) {
val, exists := data[key]
if !exists {
return "", fmt.Errorf("Key `%s` not found", key)
}
str, ok := val.(string)
if !ok {
return "", fmt.Errorf("Expected value of `%s` to have type string but has %T", key, val)
}
return str, nil
}