forked from prometheus/prometheus
-
Notifications
You must be signed in to change notification settings - Fork 2
/
parse.go
151 lines (126 loc) · 3.35 KB
/
parse.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
// Copyright 2017 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:generate go get github.com/cznic/golex
//go:generate golex -o=lex.l.go lex.l
// Package textparse contains an efficient parser for the Prometheus text format.
package textparse
import (
"errors"
"io"
"sort"
"strings"
"unsafe"
"github.com/prometheus/prometheus/pkg/labels"
)
type lexer struct {
b []byte
i int
vstart int
tstart int
err error
val float64
ts *int64
offsets []int
mstart, mend int
nextMstart int
state int
}
const eof = 0
func (l *lexer) next() byte {
l.i++
if l.i >= len(l.b) {
l.err = io.EOF
return eof
}
c := l.b[l.i]
// Consume null byte when encountered in label-value.
if c == eof && (l.state == lstateLValueIn || l.state == lstateLValue) {
return l.next()
}
return c
}
func (l *lexer) Error(es string) {
l.err = errors.New(es)
}
// Parser parses samples from a byte slice of samples in the official
// Prometheus text exposition format.
type Parser struct {
l *lexer
err error
val float64
}
// New returns a new parser of the byte slice.
func New(b []byte) *Parser {
return &Parser{l: &lexer{b: b}}
}
// Next advances the parser to the next sample. It returns false if no
// more samples were read or an error occurred.
func (p *Parser) Next() bool {
switch p.l.Lex() {
case -1, eof:
return false
case 1:
return true
}
panic("unexpected")
}
// At returns the bytes of the metric, the timestamp if set, and the value
// of the current sample.
func (p *Parser) At() ([]byte, *int64, float64) {
return p.l.b[p.l.mstart:p.l.mend], p.l.ts, p.l.val
}
// Err returns the current error.
func (p *Parser) Err() error {
if p.err != nil {
return p.err
}
if p.l.err == io.EOF {
return nil
}
return p.l.err
}
// Metric writes the labels of the current sample into the passed labels.
// It returns the string from which the metric was parsed.
func (p *Parser) Metric(l *labels.Labels) string {
// Allocate the full immutable string immediately, so we just
// have to create references on it below.
s := string(p.l.b[p.l.mstart:p.l.mend])
*l = append(*l, labels.Label{
Name: labels.MetricName,
Value: s[:p.l.offsets[0]-p.l.mstart],
})
for i := 1; i < len(p.l.offsets); i += 4 {
a := p.l.offsets[i] - p.l.mstart
b := p.l.offsets[i+1] - p.l.mstart
c := p.l.offsets[i+2] - p.l.mstart
d := p.l.offsets[i+3] - p.l.mstart
// Replacer causes allocations. Replace only when necessary.
if strings.IndexByte(s[c:d], byte('\\')) >= 0 {
*l = append(*l, labels.Label{Name: s[a:b], Value: replacer.Replace(s[c:d])})
continue
}
*l = append(*l, labels.Label{Name: s[a:b], Value: s[c:d]})
}
sort.Sort((*l)[1:])
return s
}
var replacer = strings.NewReplacer(
`\"`, `"`,
`\\`, `\`,
`\n`, `
`,
`\t`, ` `,
)
func yoloString(b []byte) string {
return *((*string)(unsafe.Pointer(&b)))
}