This repository has been archived by the owner on Mar 9, 2022. It is now read-only.
/
prometheus.go
114 lines (97 loc) · 2.16 KB
/
prometheus.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
package monitor
import (
"bytes"
"errors"
"strconv"
)
// Metric represents a single Prometheus metric line, including its
// labels and timestamp.
type Metric struct {
Name []byte
Labels LabelPairs
Value int
Milliseconds int64
}
// LabelPairs contains the set of labels for a metric.
type LabelPairs []LabelPair
// LabelPair contains a label name and value.
type LabelPair struct {
Name []byte
Value []byte
}
// ParseMetric parses a single Promethesus metric line.
//
// Note: The implementation currently only supports integer values and
// also doesn't handle escaped characters nor multiple sequential
// whitespace characters. This is OK for now because this only needs
// to support metrics generated by the various influx-spout
// components.
func ParseMetric(s []byte) (*Metric, error) {
if len(s) < 3 {
return nil, errors.New("invalid metric")
}
out := new(Metric)
var err error
i := bytes.IndexAny(s, " {")
if i == -1 {
return nil, errors.New("no value")
}
out.Name = s[:i]
if s[i] == '{' {
i++
labels, n, err := parseLabels(s[i:])
if err != nil {
return nil, err
}
out.Labels = labels
i += n
}
i++
j := bytes.IndexByte(s[i:], ' ')
if j == -1 {
j = len(s[i:]) // No timestamp
}
out.Value, err = strconv.Atoi(string(s[i : i+j]))
if err != nil {
return nil, errors.New("invalid value")
}
i += j
if i < len(s) {
out.Milliseconds, err = strconv.ParseInt(string(s[i+1:]), 10, 64)
if err != nil {
return nil, errors.New("invalid timestamp")
}
}
return out, nil
}
func parseLabels(s []byte) (LabelPairs, int, error) {
if s[0] == '}' {
return nil, 1, nil
}
i := 0
out := make(LabelPairs, 0, 1)
for {
var label LabelPair
j := bytes.Index(s[i:], []byte(`="`))
if j == -1 {
return nil, i, errors.New("invalid label")
}
label.Name = s[i : i+j]
i = i + j + 2
j = bytes.IndexByte(s[i:], '"')
if j == -1 {
return nil, i, errors.New("missing label closing quote")
}
label.Value = s[i : i+j]
i = i + j + 1
out = append(out, label)
switch s[i] {
case '}':
return out, i + 1, nil
case ',':
i++
default:
return nil, i, errors.New("invalid label separator")
}
}
}