-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
parser.go
122 lines (94 loc) · 2.34 KB
/
parser.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
package form_urlencoded
import (
"bytes"
"fmt"
"net/url"
"strconv"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
)
var (
// ErrNoMetric is returned when no metric is found in input line
ErrNoMetric = fmt.Errorf("no metric in line")
)
// Parser decodes "application/x-www-form-urlencoded" data into metrics
type Parser struct {
MetricName string
DefaultTags map[string]string
TagKeys []string
AllowedKeys []string
}
// Parse converts a slice of bytes in "application/x-www-form-urlencoded" format into metrics
func (p Parser) Parse(buf []byte) ([]telegraf.Metric, error) {
buf = bytes.TrimSpace(buf)
if len(buf) == 0 {
return make([]telegraf.Metric, 0), nil
}
values, err := url.ParseQuery(string(buf))
if err != nil {
return nil, err
}
if len(p.AllowedKeys) > 0 {
values = p.filterAllowedKeys(values)
}
tags := p.extractTags(values)
fields := p.parseFields(values)
for key, value := range p.DefaultTags {
tags[key] = value
}
m := metric.New(p.MetricName, tags, fields, time.Now().UTC())
return []telegraf.Metric{m}, nil
}
// ParseLine delegates a single line of text to the Parse function
func (p Parser) ParseLine(line string) (telegraf.Metric, error) {
metrics, err := p.Parse([]byte(line))
if err != nil {
return nil, err
}
if len(metrics) < 1 {
return nil, ErrNoMetric
}
return metrics[0], nil
}
// SetDefaultTags sets the default tags for every metric
func (p *Parser) SetDefaultTags(tags map[string]string) {
p.DefaultTags = tags
}
func (p Parser) filterAllowedKeys(original url.Values) url.Values {
result := make(url.Values)
for _, key := range p.AllowedKeys {
value, exists := original[key]
if !exists {
continue
}
result[key] = value
}
return result
}
func (p Parser) extractTags(values url.Values) map[string]string {
tags := make(map[string]string)
for _, key := range p.TagKeys {
value, exists := values[key]
if !exists || len(key) == 0 {
continue
}
tags[key] = value[0]
delete(values, key)
}
return tags
}
func (p Parser) parseFields(values url.Values) map[string]interface{} {
fields := make(map[string]interface{})
for key, value := range values {
if len(key) == 0 || len(value) == 0 {
continue
}
field, err := strconv.ParseFloat(value[0], 64)
if err != nil {
continue
}
fields[key] = field
}
return fields
}