Codebase list golang-github-influxdata-line-protocol / upstream/0.0_git20210311.9aa0e37
Import upstream version 0.0~git20210311.9aa0e37 Debian Janitor 2 years ago
17 changed file(s) with 8940 addition(s) and 89 deletion(s). Raw diff Collapse all Expand all
22 build:
33 docker:
44 # specify the version
5 - image: circleci/golang:1.10.2
6
5 - image: circleci/golang:1.12.3
6
77 working_directory: /go/src/github.com/influxdata/line-protocol
88 steps:
99 - checkout
1010
1111 - run: go get -v -t -d ./...
12 - run: go get honnef.co/go/tools/cmd/megacheck
13 - run: go vet -v ./...
12 - run: go get honnef.co/go/tools/...
13 - run: go vet -v -unreachable=false ./...
1414 - run: go test -v ./...
15 - run: megacheck ./...
15 - run: staticcheck ./...
0 go.sum linguist-generated=true
1
0 # line-protocol
0 # line-protocol
1
2 This is an encoder for the influx [line protocol.](https://docs.influxdata.com/influxdb/latest/reference/syntax/line-protocol/)
3
4 It has an interface similar to the standard library's `json.Encoder`.
5
6
7 ### some caveats.
8 - It is not concurrency-safe. If you want to make multiple calls to `Encoder.Encode` concurrently you have to manage the concurrency yourself.
9 - It can only encode values that are uint64, int64, int, float32, float64, string, or bool.
10 - Ints are converted to int64, float32's to float64.
11 - If UintSupport is not set, uint64s are converted to int64's and if they are larger than the max int64, they get truncated to the max int64 instead of overflowing.
12
13
14 ### Example:
15 ```go
16 buf := &bytes.Buffer{}
17 serializer := protocol.NewEncoder(buf)
18 serializer.SetMaxLineBytes(1024)
19 serializer.SetFieldTypeSupport(UintSupport)
20 serializer.Encode(e) // where e is something that implements the protocol.Metric interface
21 ```
55 "math"
66 "sort"
77 "strconv"
8 "time"
89 )
10
11 // ErrIsNaN is a field error for when a float field is NaN.
12 var ErrIsNaN = &FieldError{"is NaN"}
13
14 // ErrIsInf is a field error for when a float field is Inf.
15 var ErrIsInf = &FieldError{"is Inf"}
916
1017 // Encoder marshals Metrics into influxdb line protocol.
1118 // It is not safe for concurrent use, make a new one!
2128 header []byte
2229 footer []byte
2330 pair []byte
31 precision time.Duration
2432 }
2533
2634 // SetMaxLineBytes sets a maximum length for a line, Encode will error if the generated line is longer
4553 // The default behavior to move on
4654 func (e *Encoder) FailOnFieldErr(s bool) {
4755 e.failOnFieldError = s
56 }
57
58 // SetPrecision sets time precision for writes
59 // Default is nanoseconds precision
60 func (e *Encoder) SetPrecision(p time.Duration) {
61 e.precision = p
4862 }
4963
5064 // NewEncoder gives us an encoder that marshals to a writer in influxdb line protocol
5771 footer: make([]byte, 0, 128),
5872 pair: make([]byte, 0, 128),
5973 fieldList: make([]*Field, 0, 16),
74 precision: time.Nanosecond,
6075 }
6176 }
6277
7186 return 0, err
7287 }
7388
74 e.buildFooter(m)
75
76 // here we make a copy of the fields so we can do an in-place sort
89 e.buildFooter(m.Time())
90
91 // here we make a copy of the *fields so we can do an in-place sort
7792 e.fieldList = append(e.fieldList[:0], m.FieldList()...)
7893
7994 if e.fieldSortOrder == SortFields {
111126 if err != nil {
112127 return 0, err
113128 }
129 pairsLen = 0
114130 totalWritten += i
115131
116132 bytesNeeded = len(e.header) + len(e.pair) + len(e.footer)
152168
153169 }
154170
155 e.w.Write(e.pair)
171 i, err = e.w.Write(e.pair)
172 if err != nil {
173 return 0, err
174 }
175 totalWritten += i
156176
157177 pairsLen += len(e.pair)
158178 firstField = false
198218 return nil
199219 }
200220
201 func (e *Encoder) buildFieldPair(key string, value interface{}) error {
202 e.pair = e.pair[:0]
203 key = escape(key)
204 // Some keys are not encodeable as line protocol, such as those with a
205 // trailing '\' or empty strings.
206 if key == "" {
207 return &FieldError{"invalid field key"}
208 }
209 e.pair = append(e.pair, key...)
210 e.pair = append(e.pair, '=')
221 func (e *Encoder) buildFieldVal(value interface{}) error {
211222 switch v := value.(type) {
212223 case uint64:
213224 if e.fieldTypeSupport&UintSupport != 0 {
223234 e.pair = append(strconv.AppendInt(e.pair, int64(v), 10), 'i')
224235 case float64:
225236 if math.IsNaN(v) {
226 return &FieldError{"is NaN"}
237 return ErrIsNaN
227238 }
228239
229240 if math.IsInf(v, 0) {
230 return &FieldError{"is Inf"}
241 return ErrIsInf
231242 }
232243
233244 e.pair = strconv.AppendFloat(e.pair, v, 'f', -1, 64)
234245 case float32:
235246 v32 := float64(v)
236247 if math.IsNaN(v32) {
237 return &FieldError{"is NaN"}
248 return ErrIsNaN
238249 }
239250
240251 if math.IsInf(v32, 0) {
241 return &FieldError{"is Inf"}
252 return ErrIsInf
242253 }
243254
244255 e.pair = strconv.AppendFloat(e.pair, v32, 'f', -1, 64)
246257 case string:
247258 e.pair = append(e.pair, '"')
248259 e.pair = append(e.pair, stringFieldEscape(v)...)
260 e.pair = append(e.pair, '"')
261 case []byte:
262 e.pair = append(e.pair, '"')
263 stringFieldEscapeBytes(&e.pair, v)
249264 e.pair = append(e.pair, '"')
250265 case bool:
251266 e.pair = strconv.AppendBool(e.pair, v)
255270 return nil
256271 }
257272
258 func (e *Encoder) buildFooter(m Metric) {
273 func (e *Encoder) buildFieldPair(key string, value interface{}) error {
274 e.pair = e.pair[:0]
275 key = escape(key)
276 // Some keys are not encodeable as line protocol, such as those with a
277 // trailing '\' or empty strings.
278 if key == "" || key[:len(key)-1] == "\\" {
279 return &FieldError{"invalid field key"}
280 }
281 e.pair = append(e.pair, key...)
282 e.pair = append(e.pair, '=')
283 return e.buildFieldVal(value)
284 }
285
286 func (e *Encoder) buildFooter(t time.Time) {
259287 e.footer = e.footer[:0]
260 e.footer = append(e.footer, ' ')
261 e.footer = strconv.AppendInt(e.footer, m.Time().UnixNano(), 10)
288 if !t.IsZero() {
289 e.footer = append(e.footer, ' ')
290 switch e.precision {
291 case time.Microsecond:
292 e.footer = strconv.AppendInt(e.footer, t.UnixNano()/1000, 10)
293 case time.Millisecond:
294 e.footer = strconv.AppendInt(e.footer, t.UnixNano()/1000000, 10)
295 case time.Second:
296 e.footer = strconv.AppendInt(e.footer, t.Unix(), 10)
297 default:
298 e.footer = strconv.AppendInt(e.footer, t.UnixNano(), 10)
299 }
300 }
262301 e.footer = append(e.footer, '\n')
263302 }
55 "sort"
66 "testing"
77 "time"
8
9 "github.com/stretchr/testify/require"
108 )
119
1210 type MockMetric struct {
4947 }
5048 }
5149 m.fields = append(m.fields, &Field{Key: k, Value: convertField(v)})
52 }
53
54 func convertField(v interface{}) interface{} {
55 switch v := v.(type) {
56 case float64:
57 return v
58 case int64:
59 return v
60 case string:
61 return v
62 case bool:
63 return v
64 case int:
65 return int64(v)
66 case uint:
67 return uint64(v)
68 case uint64:
69 return uint64(v)
70 case []byte:
71 return string(v)
72 case int32:
73 return int64(v)
74 case int16:
75 return int64(v)
76 case int8:
77 return int64(v)
78 case uint32:
79 return uint64(v)
80 case uint16:
81 return uint64(v)
82 case uint8:
83 return uint64(v)
84 case float32:
85 return float64(v)
86 default:
87 return nil
88 }
50 sort.Slice(m.fields, func(i, j int) bool {
51 return string(m.fields[i].Key) < string(m.fields[j].Key)
52 })
8953 }
9054
9155 func NewMockMetric(name string,
9357 fields map[string]interface{},
9458 tm time.Time,
9559 ) Metric {
96 // var vtype telegraf.ValueType
97 // if len(tp) > 0 {
98 // vtype = tp[0]
99 // } else {
100 // vtype = telegraf.Untyped
101 // }
10260 m := &MockMetric{
10361 name: name,
10462 tags: nil,
13593 output []byte
13694 failOnFieldErr bool
13795 err error
96 precision time.Duration
13897 }{
13998 {
14099 name: "minimal",
351310 time.Unix(1519194109, 42),
352311 ),
353312 output: []byte("cpu abc=123i 1519194109000000042\ncpu def=456i 1519194109000000042\n"),
313 },
314 {
315 name: "split_fields_overflow",
316 maxBytes: 43,
317 input: NewMockMetric(
318 "cpu",
319 map[string]string{},
320 map[string]interface{}{
321 "abc": 123,
322 "def": 456,
323 "ghi": 789,
324 "jkl": 123,
325 },
326 time.Unix(1519194109, 42),
327 ),
328 output: []byte("cpu abc=123i,def=456i 1519194109000000042\ncpu ghi=789i,jkl=123i 1519194109000000042\n"),
354329 },
355330 {
356331 name: "name newline",
494469 time.Unix(0, 0),
495470 ),
496471 failOnFieldErr: true,
497 err: &FieldError{s: "is NaN"},
472 err: ErrIsNaN,
473 },
474 {
475 name: "explicit nanoseconds precision",
476 input: NewMockMetric(
477 "cpu",
478 map[string]string{},
479 map[string]interface{}{
480 "x": 3,
481 "y": 42.3,
482 },
483 time.Unix(123456789, 123456789),
484 ),
485 precision: time.Nanosecond,
486 output: []byte("cpu x=3i,y=42.3 123456789123456789\n"),
487 },
488 {
489 name: "microseconds precision",
490 input: NewMockMetric(
491 "cpu",
492 map[string]string{},
493 map[string]interface{}{
494 "x": 3,
495 "y": 42.3,
496 },
497 time.Unix(123456789, 123456789),
498 ),
499 precision: time.Microsecond,
500 output: []byte("cpu x=3i,y=42.3 123456789123456\n"),
501 },
502 {
503 name: "milliseconds precision",
504 input: NewMockMetric(
505 "cpu",
506 map[string]string{},
507 map[string]interface{}{
508 "x": 3,
509 "y": 42.3,
510 },
511 time.Unix(123456789, 123456789),
512 ),
513 precision: time.Millisecond,
514 output: []byte("cpu x=3i,y=42.3 123456789123\n"),
515 },
516 {
517 name: "seconds precision",
518 input: NewMockMetric(
519 "cpu",
520 map[string]string{},
521 map[string]interface{}{
522 "x": 3,
523 "y": 42.3,
524 },
525 time.Unix(123456789, 123456789),
526 ),
527 precision: time.Second,
528 output: []byte("cpu x=3i,y=42.3 123456789\n"),
498529 },
499530 }
500531
507538 serializer.SetFieldSortOrder(SortFields)
508539 serializer.SetFieldTypeSupport(tt.typeSupport)
509540 serializer.FailOnFieldErr(tt.failOnFieldErr)
510 _, err := serializer.Encode(tt.input)
511 require.Equal(t, tt.err, err)
512 require.Equal(t, string(tt.output), buf.String())
541 serializer.SetPrecision(tt.precision)
542 i, err := serializer.Encode(tt.input)
543 if tt.err != err {
544 t.Fatalf("expected error %v, but got %v", tt.err, err)
545 }
546 if i != len(buf.Bytes()) {
547 t.Fatalf("expected i: %v, but got: %v", len(buf.Bytes()), i)
548 }
549 if string(tt.output) != buf.String() {
550 t.Fatalf("expected output %v, but got %v", tt.output, buf.String())
551 }
513552 })
514553 }
554 }
555
556 func TestWriter(t *testing.T) {
557 type args struct {
558 name []byte
559 ts time.Time
560 tagKeys, tagVals, fieldKeys [][]byte
561 fieldVals []interface{}
562 }
563 btests := make([]struct {
564 name string
565 maxBytes int
566 typeSupport FieldTypeSupport
567 failOnFieldErr bool
568 fields args
569 err error
570 output []byte
571 precision time.Duration
572 }, len(tests))
573 for i, tt := range tests {
574 btests[i].name = tt.name
575 btests[i].maxBytes = tt.maxBytes
576 btests[i].typeSupport = tt.typeSupport
577 btests[i].failOnFieldErr = tt.failOnFieldErr
578 btests[i].err = tt.err
579 btests[i].output = tt.output
580 btests[i].precision = tt.precision
581 btests[i].fields.name = []byte(tt.input.Name())
582 btests[i].fields.ts = tt.input.Time()
583 btests[i].fields.fieldKeys, btests[i].fields.fieldVals = fieldsToBytes(tt.input.FieldList())
584 btests[i].fields.tagKeys, btests[i].fields.tagVals = tagsToBytes(tt.input.TagList())
585 }
586 for _, tt := range btests {
587 t.Run(tt.name, func(t *testing.T) {
588 if t.Name() == "TestWriter/split_fields_overflow" {
589 t.Skip("https://github.com/influxdata/line-protocol/issues/9")
590 }
591 buf := &bytes.Buffer{}
592 serializer := NewEncoder(buf)
593 serializer.SetMaxLineBytes(tt.maxBytes)
594 serializer.SetFieldSortOrder(SortFields)
595 serializer.SetFieldTypeSupport(tt.typeSupport)
596 serializer.FailOnFieldErr(tt.failOnFieldErr)
597 serializer.SetPrecision(tt.precision)
598 _, err := serializer.Write(tt.fields.name, tt.fields.ts, tt.fields.tagKeys, tt.fields.tagVals, tt.fields.fieldKeys, tt.fields.fieldVals)
599 if tt.err != err {
600 t.Fatalf("expected error %v, but got %v", tt.err, err)
601 }
602 if string(tt.output) != buf.String() {
603 t.Fatalf("expected output %s, but got %s", tt.output, buf.String())
604 }
605 })
606 }
607 }
608
609 func fieldsToBytes(tg []*Field) ([][]byte, []interface{}) {
610 b := make([][]byte, len(tg))
611 v := make([]interface{}, len(tg))
612 for i := range tg {
613 b[i] = []byte(tg[i].Key)
614 v[i] = tg[i].Value
615 }
616 return b, v
617 }
618
619 func tagsToBytes(tg []*Tag) ([][]byte, [][]byte) {
620 b := make([][]byte, len(tg))
621 v := make([][]byte, len(tg))
622 for i := range tg {
623 b[i] = []byte(tg[i].Key)
624 v[i] = []byte(tg[i].Value)
625 }
626 return b, v
627
515628 }
516629
517630 func BenchmarkSerializer(b *testing.B) {
529642 })
530643 }
531644 }
645
646 func BenchmarkWriter(b *testing.B) {
647 type fields struct {
648 name []byte
649 ts time.Time
650 tagKeys, tagVals, fieldKeys [][]byte
651 fieldVals []interface{}
652 }
653 benches := make([]struct {
654 name string
655 maxBytes int
656 typeSupport FieldTypeSupport
657 failOnFieldErr bool
658 fields fields
659 }, len(tests))
660 for i, tt := range tests {
661 benches[i].name = tt.name
662 benches[i].maxBytes = tt.maxBytes
663 benches[i].typeSupport = tt.typeSupport
664 benches[i].failOnFieldErr = tt.failOnFieldErr
665 benches[i].fields.name = []byte(tt.input.Name())
666 benches[i].fields.ts = tt.input.Time()
667 benches[i].fields.fieldKeys, benches[i].fields.fieldVals = fieldsToBytes(tt.input.FieldList())
668 benches[i].fields.tagKeys, benches[i].fields.tagVals = tagsToBytes(tt.input.TagList())
669 }
670 b.ResetTimer()
671
672 for _, tt := range benches {
673 b.Run(tt.name, func(b *testing.B) {
674 buf := &bytes.Buffer{}
675 serializer := NewEncoder(buf)
676 serializer.SetMaxLineBytes(tt.maxBytes)
677 serializer.SetFieldTypeSupport(tt.typeSupport)
678 var i int
679 var err error
680 for n := 0; n < b.N; n++ {
681 i, err = serializer.Write(tt.fields.name, tt.fields.ts, tt.fields.tagKeys, tt.fields.tagVals, tt.fields.fieldKeys, tt.fields.fieldVals)
682 _ = err
683 _ = i
684 }
685 _ = buf
686 })
687 }
688 }
00 package protocol
11
22 import (
3 "bytes"
4 "reflect"
5 "strconv"
36 "strings"
7 "unicode/utf8"
8 "unsafe"
49 )
510
611 const (
1015 )
1116
1217 var (
13 escaper = strings.NewReplacer(
18 stringEscaper = strings.NewReplacer(
1419 "\t", `\t`,
1520 "\n", `\n`,
1621 "\f", `\f`,
3944 )
4045 )
4146
47 var (
48 unescaper = strings.NewReplacer(
49 `\,`, `,`,
50 `\"`, `"`, // ???
51 `\ `, ` `,
52 `\=`, `=`,
53 )
54
55 nameUnescaper = strings.NewReplacer(
56 `\,`, `,`,
57 `\ `, ` `,
58 )
59
60 stringFieldUnescaper = strings.NewReplacer(
61 `\"`, `"`,
62 `\\`, `\`,
63 )
64 )
65
4266 // The various escape functions allocate, I'd like to fix that.
4367 // TODO: make escape not allocate
4468
4569 // Escape a tagkey, tagvalue, or fieldkey
4670 func escape(s string) string {
4771 if strings.ContainsAny(s, escapes) {
48 return escaper.Replace(s)
72 return stringEscaper.Replace(s)
4973 }
5074 return s
5175 }
6589 }
6690 return s
6791 }
92
93 const (
94 utf8mask = byte(0x3F)
95 utf8bytex = byte(0x80) // 1000 0000
96 utf8len2 = byte(0xC0) // 1100 0000
97 utf8len3 = byte(0xE0) // 1110 0000
98 utf8len4 = byte(0xF0) // 1111 0000
99 )
100
101 func escapeBytes(dest *[]byte, b []byte) {
102 if bytes.ContainsAny(b, escapes) {
103 var r rune
104 for i, j := 0, 0; i < len(b); i += j {
105 r, j = utf8.DecodeRune(b[i:])
106 switch {
107 case r == '\t':
108 *dest = append(*dest, `\t`...)
109 case r == '\n':
110 *dest = append(*dest, `\n`...)
111 case r == '\f':
112 *dest = append(*dest, `\f`...)
113 case r == '\r':
114 *dest = append(*dest, `\r`...)
115 case r == ',':
116 *dest = append(*dest, `\,`...)
117 case r == ' ':
118 *dest = append(*dest, `\ `...)
119 case r == '=':
120 *dest = append(*dest, `\=`...)
121 case r <= 1<<7-1:
122 *dest = append(*dest, byte(r))
123 case r <= 1<<11-1:
124 *dest = append(*dest, utf8len2|byte(r>>6), utf8bytex|byte(r)&utf8mask)
125 case r <= 1<<16-1:
126 *dest = append(*dest, utf8len3|byte(r>>12), utf8bytex|byte(r>>6)&utf8mask, utf8bytex|byte(r)&utf8mask)
127 default:
128 *dest = append(*dest, utf8len4|byte(r>>18), utf8bytex|byte(r>>12)&utf8mask, utf8bytex|byte(r>>6)&utf8mask, utf8bytex|byte(r)&utf8mask)
129 }
130 }
131 return
132 }
133 *dest = append(*dest, b...)
134 }
135
136 // Escape a measurement name
137 func nameEscapeBytes(dest *[]byte, b []byte) {
138 if bytes.ContainsAny(b, nameEscapes) {
139 var r rune
140 for i, j := 0, 0; i < len(b); i += j {
141 r, j = utf8.DecodeRune(b[i:])
142 switch {
143 case r == '\t':
144 *dest = append(*dest, `\t`...)
145 case r == '\n':
146 *dest = append(*dest, `\n`...)
147 case r == '\f':
148 *dest = append(*dest, `\f`...)
149 case r == '\r':
150 *dest = append(*dest, `\r`...)
151 case r == ',':
152 *dest = append(*dest, `\,`...)
153 case r == ' ':
154 *dest = append(*dest, `\ `...)
155 case r == '\\':
156 *dest = append(*dest, `\\`...)
157 case r <= 1<<7-1:
158 *dest = append(*dest, byte(r))
159 case r <= 1<<11-1:
160 *dest = append(*dest, utf8len2|byte(r>>6), utf8bytex|byte(r)&utf8mask)
161 case r <= 1<<16-1:
162 *dest = append(*dest, utf8len3|byte(r>>12), utf8bytex|byte(r>>6)&utf8mask, utf8bytex|byte(r)&utf8mask)
163 default:
164 *dest = append(*dest, utf8len4|byte(r>>18), utf8bytex|byte(r>>12)&utf8mask, utf8bytex|byte(r>>6)&utf8mask, utf8bytex|byte(r)&utf8mask)
165 }
166 }
167 return
168 }
169 *dest = append(*dest, b...)
170 }
171
172 func stringFieldEscapeBytes(dest *[]byte, b []byte) {
173 if bytes.ContainsAny(b, stringFieldEscapes) {
174 var r rune
175 for i, j := 0, 0; i < len(b); i += j {
176 r, j = utf8.DecodeRune(b[i:])
177 switch {
178 case r == '\t':
179 *dest = append(*dest, `\t`...)
180 case r == '\n':
181 *dest = append(*dest, `\n`...)
182 case r == '\f':
183 *dest = append(*dest, `\f`...)
184 case r == '\r':
185 *dest = append(*dest, `\r`...)
186 case r == ',':
187 *dest = append(*dest, `\,`...)
188 case r == ' ':
189 *dest = append(*dest, `\ `...)
190 case r == '\\':
191 *dest = append(*dest, `\\`...)
192 case r <= 1<<7-1:
193 *dest = append(*dest, byte(r))
194 case r <= 1<<11-1:
195 *dest = append(*dest, utf8len2|byte(r>>6), utf8bytex|byte(r)&utf8mask)
196 case r <= 1<<16-1:
197 *dest = append(*dest, utf8len3|byte(r>>12), utf8bytex|byte(r>>6)&utf8mask, utf8bytex|byte(r)&utf8mask)
198 default:
199 *dest = append(*dest, utf8len4|byte(r>>18), utf8bytex|byte(r>>12)&utf8mask, utf8bytex|byte(r>>6)&utf8mask, utf8bytex|byte(r)&utf8mask)
200 }
201 }
202 return
203 }
204 *dest = append(*dest, b...)
205 }
206
207 func unescape(b []byte) string {
208 if bytes.ContainsAny(b, escapes) {
209 return unescaper.Replace(unsafeBytesToString(b))
210 }
211 return string(b)
212 }
213
214 func nameUnescape(b []byte) string {
215 if bytes.ContainsAny(b, nameEscapes) {
216 return nameUnescaper.Replace(unsafeBytesToString(b))
217 }
218 return string(b)
219 }
220
221 // unsafeBytesToString converts a []byte to a string without a heap allocation.
222 //
223 // It is unsafe, and is intended to prepare input to short-lived functions
224 // that require strings.
225 func unsafeBytesToString(in []byte) string {
226 src := *(*reflect.SliceHeader)(unsafe.Pointer(&in))
227 dst := reflect.StringHeader{
228 Data: src.Data,
229 Len: src.Len,
230 }
231 s := *(*string)(unsafe.Pointer(&dst))
232 return s
233 }
234
235 // parseIntBytes is a zero-alloc wrapper around strconv.ParseInt.
236 func parseIntBytes(b []byte, base int, bitSize int) (i int64, err error) {
237 s := unsafeBytesToString(b)
238 return strconv.ParseInt(s, base, bitSize)
239 }
240
241 // parseUintBytes is a zero-alloc wrapper around strconv.ParseUint.
242 func parseUintBytes(b []byte, base int, bitSize int) (i uint64, err error) {
243 s := unsafeBytesToString(b)
244 return strconv.ParseUint(s, base, bitSize)
245 }
246
247 // parseFloatBytes is a zero-alloc wrapper around strconv.ParseFloat.
248 func parseFloatBytes(b []byte, bitSize int) (float64, error) {
249 s := unsafeBytesToString(b)
250 return strconv.ParseFloat(s, bitSize)
251 }
252
253 // parseBoolBytes is a zero-alloc wrapper around strconv.ParseBool.
254 func parseBoolBytes(b []byte) (bool, error) {
255 return strconv.ParseBool(unsafeBytesToString(b))
256 }
257
258 func stringFieldUnescape(b []byte) string {
259 if bytes.ContainsAny(b, stringFieldEscapes) {
260 return stringFieldUnescaper.Replace(unsafeBytesToString(b))
261 }
262 return string(b)
263 }
0 package protocol
1
2 import (
3 "testing"
4 )
5
6 func BenchmarkStringEscFunc4(b *testing.B) {
7 s := "h\tello ⛵ \t \t"
8 for i := 0; i < b.N; i++ {
9 b := escape(s)
10 _ = b
11 }
12
13 }
14
15 func BenchmarkEscFunc4(b *testing.B) {
16 s := []byte("h\tello ⛵ \t \t")
17 dest := make([]byte, 32)
18 for i := 0; i < b.N; i++ {
19 escapeBytes(&dest, s)
20 dest = dest[:0]
21 }
22 }
23
24 func TestBytesEscape(t *testing.T) {
25 cases := []struct {
26 // we use strings in test because its easier to read and write them for humans
27 name string
28 arg string
29 want string
30 }{
31 {
32 name: "sailboat",
33 arg: `⛵`,
34 want: `⛵`,
35 },
36 {
37 name: "sentence",
38 arg: `hello I like to ⛵but do not like ☠`,
39 want: `hello\ I\ like\ to\ ⛵but\ do\ not\ like\ ☠`,
40 },
41 {
42 name: "escapes",
43 arg: "\t\n\f\r ,=",
44 want: `\t\n\f\r\ \,\=`,
45 },
46 {
47 name: "nameEscapes",
48 arg: "\t\n\f\r ,",
49 want: `\t\n\f\r\ \,`,
50 },
51 {
52 name: "stringFieldEscapes",
53 arg: "\t\n\f\r\\\"",
54 want: `\t\n\f\r\"`,
55 },
56 }
57 got := []byte{}
58 for _, x := range cases {
59 escapeBytes(&got, []byte(x.arg))
60 if string(got) != string(x.want) {
61 t.Fatalf("did not escape %s properly, expected %s got %s", x.name, x.want, got)
62 }
63 got = got[:0]
64 }
65 }
0 module github.com/influxdata/line-protocol
1
2 go 1.13
(New empty file)
0 package protocol
1
2 import (
3 "bytes"
4 "errors"
5 "strconv"
6 "time"
7 )
8
9 // MetricHandler implements the Handler interface and produces Metric.
10 type MetricHandler struct {
11 timePrecision time.Duration
12 timeFunc TimeFunc
13 metric MutableMetric
14 }
15
16 func NewMetricHandler() *MetricHandler {
17 return &MetricHandler{
18 timePrecision: time.Nanosecond,
19 timeFunc: time.Now,
20 }
21 }
22
23 func (h *MetricHandler) SetTimePrecision(p time.Duration) {
24 h.timePrecision = p
25 // When the timestamp is omitted from the metric, the timestamp
26 // comes from the server clock, truncated to the nearest unit of
27 // measurement provided in precision.
28 //
29 // When a timestamp is provided in the metric, precsision is
30 // overloaded to hold the unit of measurement of the timestamp.
31 }
32
33 func (h *MetricHandler) SetTimeFunc(f TimeFunc) {
34 h.timeFunc = f
35 }
36
37 func (h *MetricHandler) Metric() (Metric, error) {
38 if h.metric.Time().IsZero() {
39 h.metric.SetTime(h.timeFunc().Truncate(h.timePrecision))
40 }
41 return h.metric, nil
42 }
43
44 func (h *MetricHandler) SetMeasurement(name []byte) error {
45 var err error
46 h.metric, err = New(nameUnescape(name),
47 nil, nil, time.Time{})
48 return err
49 }
50
51 func (h *MetricHandler) AddTag(key []byte, value []byte) error {
52 tk := unescape(key)
53 tv := unescape(value)
54 h.metric.AddTag(tk, tv)
55 return nil
56 }
57
58 func (h *MetricHandler) AddInt(key []byte, value []byte) error {
59 fk := unescape(key)
60 fv, err := parseIntBytes(bytes.TrimSuffix(value, []byte("i")), 10, 64)
61 if err != nil {
62 if numerr, ok := err.(*strconv.NumError); ok {
63 return numerr.Err
64 }
65 return err
66 }
67 h.metric.AddField(fk, fv)
68 return nil
69 }
70
71 func (h *MetricHandler) AddUint(key []byte, value []byte) error {
72 fk := unescape(key)
73 fv, err := parseUintBytes(bytes.TrimSuffix(value, []byte("u")), 10, 64)
74 if err != nil {
75 if numerr, ok := err.(*strconv.NumError); ok {
76 return numerr.Err
77 }
78 return err
79 }
80 h.metric.AddField(fk, fv)
81 return nil
82 }
83
84 func (h *MetricHandler) AddFloat(key []byte, value []byte) error {
85 fk := unescape(key)
86 fv, err := parseFloatBytes(value, 64)
87 if err != nil {
88 if numerr, ok := err.(*strconv.NumError); ok {
89 return numerr.Err
90 }
91 return err
92 }
93 h.metric.AddField(fk, fv)
94 return nil
95 }
96
97 func (h *MetricHandler) AddString(key []byte, value []byte) error {
98 fk := unescape(key)
99 fv := stringFieldUnescape(value)
100 h.metric.AddField(fk, fv)
101 return nil
102 }
103
104 func (h *MetricHandler) AddBool(key []byte, value []byte) error {
105 fk := unescape(key)
106 fv, err := parseBoolBytes(value)
107 if err != nil {
108 return errors.New("unparseable bool")
109 }
110 h.metric.AddField(fk, fv)
111 return nil
112 }
113
114 func (h *MetricHandler) SetTimestamp(tm []byte) error {
115 v, err := parseIntBytes(tm, 10, 64)
116 if err != nil {
117 if numerr, ok := err.(*strconv.NumError); ok {
118 return numerr.Err
119 }
120 return err
121 }
122
123 //time precision is overloaded to mean time unit here
124 ns := v * int64(h.timePrecision)
125 h.metric.SetTime(time.Unix(0, ns))
126 return nil
127 }
0 //line machine.go.rl:1
1 package protocol
2
3 import (
4 "errors"
5 "io"
6 )
7
8 var (
9 ErrNameParse = errors.New("expected measurement name")
10 ErrFieldParse = errors.New("expected field")
11 ErrTagParse = errors.New("expected tag")
12 ErrTimestampParse = errors.New("expected timestamp")
13 ErrParse = errors.New("parse error")
14 EOF = errors.New("EOF")
15 )
16
17 //line machine.go.rl:310
18
19 //line machine.go:25
20 const LineProtocol_start int = 47
21 const LineProtocol_first_final int = 47
22 const LineProtocol_error int = 0
23
24 const LineProtocol_en_main int = 47
25 const LineProtocol_en_discard_line int = 35
26 const LineProtocol_en_align int = 86
27 const LineProtocol_en_series int = 38
28
29 //line machine.go.rl:313
30
31 type Handler interface {
32 SetMeasurement(name []byte) error
33 AddTag(key []byte, value []byte) error
34 AddInt(key []byte, value []byte) error
35 AddUint(key []byte, value []byte) error
36 AddFloat(key []byte, value []byte) error
37 AddString(key []byte, value []byte) error
38 AddBool(key []byte, value []byte) error
39 SetTimestamp(tm []byte) error
40 }
41
42 type machine struct {
43 data []byte
44 cs int
45 p, pe, eof int
46 pb int
47 lineno int
48 sol int
49 handler Handler
50 initState int
51 key []byte
52 beginMetric bool
53 finishMetric bool
54 }
55
56 func NewMachine(handler Handler) *machine {
57 m := &machine{
58 handler: handler,
59 initState: LineProtocol_en_align,
60 }
61
62 //line machine.go.rl:346
63
64 //line machine.go.rl:347
65
66 //line machine.go.rl:348
67
68 //line machine.go.rl:349
69
70 //line machine.go.rl:350
71
72 //line machine.go.rl:351
73
74 //line machine.go:82
75 {
76 (m.cs) = LineProtocol_start
77 }
78
79 //line machine.go.rl:352
80
81 return m
82 }
83
84 func NewSeriesMachine(handler Handler) *machine {
85 m := &machine{
86 handler: handler,
87 initState: LineProtocol_en_series,
88 }
89
90 //line machine.go.rl:363
91
92 //line machine.go.rl:364
93
94 //line machine.go.rl:365
95
96 //line machine.go.rl:366
97
98 //line machine.go.rl:367
99
100 //line machine.go:109
101 {
102 (m.cs) = LineProtocol_start
103 }
104
105 //line machine.go.rl:368
106
107 return m
108 }
109
110 func (m *machine) SetData(data []byte) {
111 m.data = data
112 m.p = 0
113 m.pb = 0
114 m.lineno = 1
115 m.sol = 0
116 m.pe = len(data)
117 m.eof = len(data)
118 m.key = nil
119 m.beginMetric = false
120 m.finishMetric = false
121
122 //line machine.go:132
123 {
124 (m.cs) = LineProtocol_start
125 }
126
127 //line machine.go.rl:385
128 m.cs = m.initState
129 }
130
131 // Next parses the next metric line and returns nil if it was successfully
132 // processed. If the line contains a syntax error an error is returned,
133 // otherwise if the end of file is reached before finding a metric line then
134 // EOF is returned.
135 func (m *machine) Next() error {
136 if m.p == m.pe && m.pe == m.eof {
137 return EOF
138 }
139
140 m.key = nil
141 m.beginMetric = false
142 m.finishMetric = false
143
144 return m.exec()
145 }
146
147 func (m *machine) exec() error {
148 var err error
149
150 //line machine.go:160
151 {
152 if (m.p) == (m.pe) {
153 goto _test_eof
154 }
155 goto _resume
156
157 _again:
158 switch m.cs {
159 case 47:
160 goto st47
161 case 1:
162 goto st1
163 case 2:
164 goto st2
165 case 3:
166 goto st3
167 case 0:
168 goto st0
169 case 4:
170 goto st4
171 case 5:
172 goto st5
173 case 6:
174 goto st6
175 case 7:
176 goto st7
177 case 48:
178 goto st48
179 case 49:
180 goto st49
181 case 50:
182 goto st50
183 case 8:
184 goto st8
185 case 9:
186 goto st9
187 case 10:
188 goto st10
189 case 11:
190 goto st11
191 case 51:
192 goto st51
193 case 52:
194 goto st52
195 case 53:
196 goto st53
197 case 54:
198 goto st54
199 case 55:
200 goto st55
201 case 56:
202 goto st56
203 case 57:
204 goto st57
205 case 58:
206 goto st58
207 case 59:
208 goto st59
209 case 60:
210 goto st60
211 case 61:
212 goto st61
213 case 62:
214 goto st62
215 case 63:
216 goto st63
217 case 64:
218 goto st64
219 case 65:
220 goto st65
221 case 66:
222 goto st66
223 case 67:
224 goto st67
225 case 68:
226 goto st68
227 case 69:
228 goto st69
229 case 70:
230 goto st70
231 case 12:
232 goto st12
233 case 13:
234 goto st13
235 case 14:
236 goto st14
237 case 15:
238 goto st15
239 case 16:
240 goto st16
241 case 71:
242 goto st71
243 case 17:
244 goto st17
245 case 18:
246 goto st18
247 case 72:
248 goto st72
249 case 73:
250 goto st73
251 case 74:
252 goto st74
253 case 75:
254 goto st75
255 case 76:
256 goto st76
257 case 77:
258 goto st77
259 case 78:
260 goto st78
261 case 79:
262 goto st79
263 case 80:
264 goto st80
265 case 19:
266 goto st19
267 case 20:
268 goto st20
269 case 21:
270 goto st21
271 case 81:
272 goto st81
273 case 22:
274 goto st22
275 case 23:
276 goto st23
277 case 24:
278 goto st24
279 case 82:
280 goto st82
281 case 25:
282 goto st25
283 case 26:
284 goto st26
285 case 83:
286 goto st83
287 case 84:
288 goto st84
289 case 27:
290 goto st27
291 case 28:
292 goto st28
293 case 29:
294 goto st29
295 case 30:
296 goto st30
297 case 31:
298 goto st31
299 case 32:
300 goto st32
301 case 33:
302 goto st33
303 case 34:
304 goto st34
305 case 35:
306 goto st35
307 case 85:
308 goto st85
309 case 38:
310 goto st38
311 case 87:
312 goto st87
313 case 88:
314 goto st88
315 case 39:
316 goto st39
317 case 40:
318 goto st40
319 case 41:
320 goto st41
321 case 42:
322 goto st42
323 case 89:
324 goto st89
325 case 43:
326 goto st43
327 case 90:
328 goto st90
329 case 44:
330 goto st44
331 case 45:
332 goto st45
333 case 46:
334 goto st46
335 case 86:
336 goto st86
337 case 36:
338 goto st36
339 case 37:
340 goto st37
341 }
342
343 if (m.p)++; (m.p) == (m.pe) {
344 goto _test_eof
345 }
346 _resume:
347 switch m.cs {
348 case 47:
349 goto st_case_47
350 case 1:
351 goto st_case_1
352 case 2:
353 goto st_case_2
354 case 3:
355 goto st_case_3
356 case 0:
357 goto st_case_0
358 case 4:
359 goto st_case_4
360 case 5:
361 goto st_case_5
362 case 6:
363 goto st_case_6
364 case 7:
365 goto st_case_7
366 case 48:
367 goto st_case_48
368 case 49:
369 goto st_case_49
370 case 50:
371 goto st_case_50
372 case 8:
373 goto st_case_8
374 case 9:
375 goto st_case_9
376 case 10:
377 goto st_case_10
378 case 11:
379 goto st_case_11
380 case 51:
381 goto st_case_51
382 case 52:
383 goto st_case_52
384 case 53:
385 goto st_case_53
386 case 54:
387 goto st_case_54
388 case 55:
389 goto st_case_55
390 case 56:
391 goto st_case_56
392 case 57:
393 goto st_case_57
394 case 58:
395 goto st_case_58
396 case 59:
397 goto st_case_59
398 case 60:
399 goto st_case_60
400 case 61:
401 goto st_case_61
402 case 62:
403 goto st_case_62
404 case 63:
405 goto st_case_63
406 case 64:
407 goto st_case_64
408 case 65:
409 goto st_case_65
410 case 66:
411 goto st_case_66
412 case 67:
413 goto st_case_67
414 case 68:
415 goto st_case_68
416 case 69:
417 goto st_case_69
418 case 70:
419 goto st_case_70
420 case 12:
421 goto st_case_12
422 case 13:
423 goto st_case_13
424 case 14:
425 goto st_case_14
426 case 15:
427 goto st_case_15
428 case 16:
429 goto st_case_16
430 case 71:
431 goto st_case_71
432 case 17:
433 goto st_case_17
434 case 18:
435 goto st_case_18
436 case 72:
437 goto st_case_72
438 case 73:
439 goto st_case_73
440 case 74:
441 goto st_case_74
442 case 75:
443 goto st_case_75
444 case 76:
445 goto st_case_76
446 case 77:
447 goto st_case_77
448 case 78:
449 goto st_case_78
450 case 79:
451 goto st_case_79
452 case 80:
453 goto st_case_80
454 case 19:
455 goto st_case_19
456 case 20:
457 goto st_case_20
458 case 21:
459 goto st_case_21
460 case 81:
461 goto st_case_81
462 case 22:
463 goto st_case_22
464 case 23:
465 goto st_case_23
466 case 24:
467 goto st_case_24
468 case 82:
469 goto st_case_82
470 case 25:
471 goto st_case_25
472 case 26:
473 goto st_case_26
474 case 83:
475 goto st_case_83
476 case 84:
477 goto st_case_84
478 case 27:
479 goto st_case_27
480 case 28:
481 goto st_case_28
482 case 29:
483 goto st_case_29
484 case 30:
485 goto st_case_30
486 case 31:
487 goto st_case_31
488 case 32:
489 goto st_case_32
490 case 33:
491 goto st_case_33
492 case 34:
493 goto st_case_34
494 case 35:
495 goto st_case_35
496 case 85:
497 goto st_case_85
498 case 38:
499 goto st_case_38
500 case 87:
501 goto st_case_87
502 case 88:
503 goto st_case_88
504 case 39:
505 goto st_case_39
506 case 40:
507 goto st_case_40
508 case 41:
509 goto st_case_41
510 case 42:
511 goto st_case_42
512 case 89:
513 goto st_case_89
514 case 43:
515 goto st_case_43
516 case 90:
517 goto st_case_90
518 case 44:
519 goto st_case_44
520 case 45:
521 goto st_case_45
522 case 46:
523 goto st_case_46
524 case 86:
525 goto st_case_86
526 case 36:
527 goto st_case_36
528 case 37:
529 goto st_case_37
530 }
531 goto st_out
532 st47:
533 if (m.p)++; (m.p) == (m.pe) {
534 goto _test_eof47
535 }
536 st_case_47:
537 switch (m.data)[(m.p)] {
538 case 10:
539 goto tr33
540 case 13:
541 goto tr33
542 case 32:
543 goto tr82
544 case 35:
545 goto tr33
546 case 44:
547 goto tr33
548 case 92:
549 goto tr83
550 }
551 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
552 goto tr82
553 }
554 goto tr81
555 tr31:
556 //line machine.go.rl:20
557
558 m.pb = m.p
559
560 goto st1
561 tr81:
562 //line machine.go.rl:74
563
564 m.beginMetric = true
565
566 //line machine.go.rl:20
567
568 m.pb = m.p
569
570 goto st1
571 st1:
572 if (m.p)++; (m.p) == (m.pe) {
573 goto _test_eof1
574 }
575 st_case_1:
576 //line machine.go:586
577 switch (m.data)[(m.p)] {
578 case 10:
579 goto tr2
580 case 13:
581 goto tr2
582 case 32:
583 goto tr1
584 case 44:
585 goto tr3
586 case 92:
587 goto st9
588 }
589 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
590 goto tr1
591 }
592 goto st1
593 tr1:
594 (m.cs) = 2
595 //line machine.go.rl:78
596
597 err = m.handler.SetMeasurement(m.text())
598 if err != nil {
599 (m.p)--
600
601 (m.cs) = 35
602 {
603 (m.p)++
604 goto _out
605 }
606 }
607
608 goto _again
609 tr58:
610 (m.cs) = 2
611 //line machine.go.rl:91
612
613 err = m.handler.AddTag(m.key, m.text())
614 if err != nil {
615 (m.p)--
616
617 (m.cs) = 35
618 {
619 (m.p)++
620 goto _out
621 }
622 }
623
624 goto _again
625 st2:
626 if (m.p)++; (m.p) == (m.pe) {
627 goto _test_eof2
628 }
629 st_case_2:
630 //line machine.go:634
631 switch (m.data)[(m.p)] {
632 case 10:
633 goto tr7
634 case 13:
635 goto tr7
636 case 32:
637 goto st2
638 case 44:
639 goto tr7
640 case 61:
641 goto tr7
642 case 92:
643 goto tr8
644 }
645 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
646 goto st2
647 }
648 goto tr5
649 tr5:
650 //line machine.go.rl:20
651
652 m.pb = m.p
653
654 goto st3
655 st3:
656 if (m.p)++; (m.p) == (m.pe) {
657 goto _test_eof3
658 }
659 st_case_3:
660 //line machine.go:664
661 switch (m.data)[(m.p)] {
662 case 32:
663 goto tr7
664 case 44:
665 goto tr7
666 case 61:
667 goto tr10
668 case 92:
669 goto st13
670 }
671 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
672 goto tr7
673 }
674 goto st3
675 tr2:
676 (m.cs) = 0
677 //line machine.go.rl:38
678
679 err = ErrTagParse
680 (m.p)--
681
682 (m.cs) = 35
683 {
684 (m.p)++
685 goto _out
686 }
687
688 goto _again
689 tr7:
690 (m.cs) = 0
691 //line machine.go.rl:31
692
693 err = ErrFieldParse
694 (m.p)--
695
696 (m.cs) = 35
697 {
698 (m.p)++
699 goto _out
700 }
701
702 goto _again
703 tr33:
704 (m.cs) = 0
705 //line machine.go.rl:24
706
707 err = ErrNameParse
708 (m.p)--
709
710 (m.cs) = 35
711 {
712 (m.p)++
713 goto _out
714 }
715
716 goto _again
717 tr37:
718 (m.cs) = 0
719 //line machine.go.rl:45
720
721 err = ErrTimestampParse
722 (m.p)--
723
724 (m.cs) = 35
725 {
726 (m.p)++
727 goto _out
728 }
729
730 goto _again
731 tr84:
732 (m.cs) = 0
733 //line machine.go.rl:31
734
735 err = ErrFieldParse
736 (m.p)--
737
738 (m.cs) = 35
739 {
740 (m.p)++
741 goto _out
742 }
743
744 //line machine.go.rl:45
745
746 err = ErrTimestampParse
747 (m.p)--
748
749 (m.cs) = 35
750 {
751 (m.p)++
752 goto _out
753 }
754
755 goto _again
756 tr137:
757 //line machine.go.rl:65
758
759 (m.p)--
760
761 {
762 goto st47
763 }
764
765 goto st0
766 //line machine.go:750
767 st_case_0:
768 st0:
769 (m.cs) = 0
770 goto _out
771 tr10:
772 //line machine.go.rl:100
773
774 m.key = m.text()
775
776 goto st4
777 st4:
778 if (m.p)++; (m.p) == (m.pe) {
779 goto _test_eof4
780 }
781 st_case_4:
782 //line machine.go:766
783 switch (m.data)[(m.p)] {
784 case 34:
785 goto st5
786 case 45:
787 goto tr13
788 case 46:
789 goto tr14
790 case 48:
791 goto tr15
792 case 70:
793 goto tr17
794 case 84:
795 goto tr18
796 case 102:
797 goto tr19
798 case 116:
799 goto tr20
800 }
801 if 49 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
802 goto tr16
803 }
804 goto tr7
805 st5:
806 if (m.p)++; (m.p) == (m.pe) {
807 goto _test_eof5
808 }
809 st_case_5:
810 switch (m.data)[(m.p)] {
811 case 10:
812 goto tr22
813 case 12:
814 goto tr7
815 case 13:
816 goto tr23
817 case 34:
818 goto tr24
819 case 92:
820 goto tr25
821 }
822 goto tr21
823 tr21:
824 //line machine.go.rl:20
825
826 m.pb = m.p
827
828 goto st6
829 tr22:
830 //line machine.go.rl:20
831
832 m.pb = m.p
833
834 //line machine.go.rl:158
835
836 m.lineno++
837 m.sol = m.p
838 m.sol++ // next char will be the first column in the line
839
840 goto st6
841 tr27:
842 //line machine.go.rl:158
843
844 m.lineno++
845 m.sol = m.p
846 m.sol++ // next char will be the first column in the line
847
848 goto st6
849 st6:
850 if (m.p)++; (m.p) == (m.pe) {
851 goto _test_eof6
852 }
853 st_case_6:
854 //line machine.go:838
855 switch (m.data)[(m.p)] {
856 case 10:
857 goto tr27
858 case 12:
859 goto tr7
860 case 13:
861 goto st7
862 case 34:
863 goto tr29
864 case 92:
865 goto st14
866 }
867 goto st6
868 tr23:
869 //line machine.go.rl:20
870
871 m.pb = m.p
872
873 goto st7
874 st7:
875 if (m.p)++; (m.p) == (m.pe) {
876 goto _test_eof7
877 }
878 st_case_7:
879 //line machine.go:863
880 if (m.data)[(m.p)] == 10 {
881 goto tr27
882 }
883 goto tr7
884 tr24:
885 (m.cs) = 48
886 //line machine.go.rl:20
887
888 m.pb = m.p
889
890 //line machine.go.rl:140
891
892 err = m.handler.AddString(m.key, m.text())
893 if err != nil {
894 (m.p)--
895
896 (m.cs) = 35
897 {
898 (m.p)++
899 goto _out
900 }
901 }
902
903 goto _again
904 tr29:
905 (m.cs) = 48
906 //line machine.go.rl:140
907
908 err = m.handler.AddString(m.key, m.text())
909 if err != nil {
910 (m.p)--
911
912 (m.cs) = 35
913 {
914 (m.p)++
915 goto _out
916 }
917 }
918
919 goto _again
920 st48:
921 if (m.p)++; (m.p) == (m.pe) {
922 goto _test_eof48
923 }
924 st_case_48:
925 //line machine.go:903
926 switch (m.data)[(m.p)] {
927 case 10:
928 goto tr36
929 case 13:
930 goto st10
931 case 32:
932 goto st49
933 case 44:
934 goto st12
935 }
936 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
937 goto st49
938 }
939 goto tr84
940 tr112:
941 (m.cs) = 49
942 //line machine.go.rl:122
943
944 err = m.handler.AddFloat(m.key, m.text())
945 if err != nil {
946 (m.p)--
947
948 (m.cs) = 35
949 {
950 (m.p)++
951 goto _out
952 }
953 }
954
955 goto _again
956 tr119:
957 (m.cs) = 49
958 //line machine.go.rl:104
959
960 err = m.handler.AddInt(m.key, m.text())
961 if err != nil {
962 (m.p)--
963
964 (m.cs) = 35
965 {
966 (m.p)++
967 goto _out
968 }
969 }
970
971 goto _again
972 tr124:
973 (m.cs) = 49
974 //line machine.go.rl:113
975
976 err = m.handler.AddUint(m.key, m.text())
977 if err != nil {
978 (m.p)--
979
980 (m.cs) = 35
981 {
982 (m.p)++
983 goto _out
984 }
985 }
986
987 goto _again
988 tr129:
989 (m.cs) = 49
990 //line machine.go.rl:131
991
992 err = m.handler.AddBool(m.key, m.text())
993 if err != nil {
994 (m.p)--
995
996 (m.cs) = 35
997 {
998 (m.p)++
999 goto _out
1000 }
1001 }
1002
1003 goto _again
1004 st49:
1005 if (m.p)++; (m.p) == (m.pe) {
1006 goto _test_eof49
1007 }
1008 st_case_49:
1009 //line machine.go:975
1010 switch (m.data)[(m.p)] {
1011 case 10:
1012 goto tr36
1013 case 13:
1014 goto st10
1015 case 32:
1016 goto st49
1017 case 45:
1018 goto tr88
1019 }
1020 switch {
1021 case (m.data)[(m.p)] > 12:
1022 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1023 goto tr89
1024 }
1025 case (m.data)[(m.p)] >= 9:
1026 goto st49
1027 }
1028 goto tr37
1029 tr36:
1030 //line machine.go.rl:158
1031
1032 m.lineno++
1033 m.sol = m.p
1034 m.sol++ // next char will be the first column in the line
1035
1036 goto st50
1037 tr91:
1038 (m.cs) = 50
1039 //line machine.go.rl:149
1040
1041 err = m.handler.SetTimestamp(m.text())
1042 if err != nil {
1043 (m.p)--
1044
1045 (m.cs) = 35
1046 {
1047 (m.p)++
1048 goto _out
1049 }
1050 }
1051
1052 //line machine.go.rl:158
1053
1054 m.lineno++
1055 m.sol = m.p
1056 m.sol++ // next char will be the first column in the line
1057
1058 goto _again
1059 tr113:
1060 (m.cs) = 50
1061 //line machine.go.rl:122
1062
1063 err = m.handler.AddFloat(m.key, m.text())
1064 if err != nil {
1065 (m.p)--
1066
1067 (m.cs) = 35
1068 {
1069 (m.p)++
1070 goto _out
1071 }
1072 }
1073
1074 //line machine.go.rl:158
1075
1076 m.lineno++
1077 m.sol = m.p
1078 m.sol++ // next char will be the first column in the line
1079
1080 goto _again
1081 tr120:
1082 (m.cs) = 50
1083 //line machine.go.rl:104
1084
1085 err = m.handler.AddInt(m.key, m.text())
1086 if err != nil {
1087 (m.p)--
1088
1089 (m.cs) = 35
1090 {
1091 (m.p)++
1092 goto _out
1093 }
1094 }
1095
1096 //line machine.go.rl:158
1097
1098 m.lineno++
1099 m.sol = m.p
1100 m.sol++ // next char will be the first column in the line
1101
1102 goto _again
1103 tr125:
1104 (m.cs) = 50
1105 //line machine.go.rl:113
1106
1107 err = m.handler.AddUint(m.key, m.text())
1108 if err != nil {
1109 (m.p)--
1110
1111 (m.cs) = 35
1112 {
1113 (m.p)++
1114 goto _out
1115 }
1116 }
1117
1118 //line machine.go.rl:158
1119
1120 m.lineno++
1121 m.sol = m.p
1122 m.sol++ // next char will be the first column in the line
1123
1124 goto _again
1125 tr130:
1126 (m.cs) = 50
1127 //line machine.go.rl:131
1128
1129 err = m.handler.AddBool(m.key, m.text())
1130 if err != nil {
1131 (m.p)--
1132
1133 (m.cs) = 35
1134 {
1135 (m.p)++
1136 goto _out
1137 }
1138 }
1139
1140 //line machine.go.rl:158
1141
1142 m.lineno++
1143 m.sol = m.p
1144 m.sol++ // next char will be the first column in the line
1145
1146 goto _again
1147 st50:
1148 //line machine.go.rl:164
1149
1150 m.finishMetric = true
1151 (m.cs) = 86
1152 {
1153 (m.p)++
1154 goto _out
1155 }
1156
1157 if (m.p)++; (m.p) == (m.pe) {
1158 goto _test_eof50
1159 }
1160 st_case_50:
1161 //line machine.go:1109
1162 switch (m.data)[(m.p)] {
1163 case 10:
1164 goto tr33
1165 case 13:
1166 goto tr33
1167 case 32:
1168 goto st8
1169 case 35:
1170 goto tr33
1171 case 44:
1172 goto tr33
1173 case 92:
1174 goto tr34
1175 }
1176 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
1177 goto st8
1178 }
1179 goto tr31
1180 tr82:
1181 //line machine.go.rl:74
1182
1183 m.beginMetric = true
1184
1185 goto st8
1186 st8:
1187 if (m.p)++; (m.p) == (m.pe) {
1188 goto _test_eof8
1189 }
1190 st_case_8:
1191 //line machine.go:1139
1192 switch (m.data)[(m.p)] {
1193 case 10:
1194 goto tr33
1195 case 13:
1196 goto tr33
1197 case 32:
1198 goto st8
1199 case 35:
1200 goto tr33
1201 case 44:
1202 goto tr33
1203 case 92:
1204 goto tr34
1205 }
1206 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
1207 goto st8
1208 }
1209 goto tr31
1210 tr34:
1211 //line machine.go.rl:20
1212
1213 m.pb = m.p
1214
1215 goto st9
1216 tr83:
1217 //line machine.go.rl:74
1218
1219 m.beginMetric = true
1220
1221 //line machine.go.rl:20
1222
1223 m.pb = m.p
1224
1225 goto st9
1226 st9:
1227 if (m.p)++; (m.p) == (m.pe) {
1228 goto _test_eof9
1229 }
1230 st_case_9:
1231 //line machine.go:1179
1232 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
1233 goto st0
1234 }
1235 goto st1
1236 tr92:
1237 (m.cs) = 10
1238 //line machine.go.rl:149
1239
1240 err = m.handler.SetTimestamp(m.text())
1241 if err != nil {
1242 (m.p)--
1243
1244 (m.cs) = 35
1245 {
1246 (m.p)++
1247 goto _out
1248 }
1249 }
1250
1251 goto _again
1252 tr114:
1253 (m.cs) = 10
1254 //line machine.go.rl:122
1255
1256 err = m.handler.AddFloat(m.key, m.text())
1257 if err != nil {
1258 (m.p)--
1259
1260 (m.cs) = 35
1261 {
1262 (m.p)++
1263 goto _out
1264 }
1265 }
1266
1267 goto _again
1268 tr121:
1269 (m.cs) = 10
1270 //line machine.go.rl:104
1271
1272 err = m.handler.AddInt(m.key, m.text())
1273 if err != nil {
1274 (m.p)--
1275
1276 (m.cs) = 35
1277 {
1278 (m.p)++
1279 goto _out
1280 }
1281 }
1282
1283 goto _again
1284 tr126:
1285 (m.cs) = 10
1286 //line machine.go.rl:113
1287
1288 err = m.handler.AddUint(m.key, m.text())
1289 if err != nil {
1290 (m.p)--
1291
1292 (m.cs) = 35
1293 {
1294 (m.p)++
1295 goto _out
1296 }
1297 }
1298
1299 goto _again
1300 tr131:
1301 (m.cs) = 10
1302 //line machine.go.rl:131
1303
1304 err = m.handler.AddBool(m.key, m.text())
1305 if err != nil {
1306 (m.p)--
1307
1308 (m.cs) = 35
1309 {
1310 (m.p)++
1311 goto _out
1312 }
1313 }
1314
1315 goto _again
1316 st10:
1317 if (m.p)++; (m.p) == (m.pe) {
1318 goto _test_eof10
1319 }
1320 st_case_10:
1321 //line machine.go:1254
1322 if (m.data)[(m.p)] == 10 {
1323 goto tr36
1324 }
1325 goto st0
1326 tr88:
1327 //line machine.go.rl:20
1328
1329 m.pb = m.p
1330
1331 goto st11
1332 st11:
1333 if (m.p)++; (m.p) == (m.pe) {
1334 goto _test_eof11
1335 }
1336 st_case_11:
1337 //line machine.go:1270
1338 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1339 goto st51
1340 }
1341 goto tr37
1342 tr89:
1343 //line machine.go.rl:20
1344
1345 m.pb = m.p
1346
1347 goto st51
1348 st51:
1349 if (m.p)++; (m.p) == (m.pe) {
1350 goto _test_eof51
1351 }
1352 st_case_51:
1353 //line machine.go:1286
1354 switch (m.data)[(m.p)] {
1355 case 10:
1356 goto tr91
1357 case 13:
1358 goto tr92
1359 case 32:
1360 goto tr90
1361 }
1362 switch {
1363 case (m.data)[(m.p)] > 12:
1364 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1365 goto st53
1366 }
1367 case (m.data)[(m.p)] >= 9:
1368 goto tr90
1369 }
1370 goto tr37
1371 tr90:
1372 (m.cs) = 52
1373 //line machine.go.rl:149
1374
1375 err = m.handler.SetTimestamp(m.text())
1376 if err != nil {
1377 (m.p)--
1378
1379 (m.cs) = 35
1380 {
1381 (m.p)++
1382 goto _out
1383 }
1384 }
1385
1386 goto _again
1387 st52:
1388 if (m.p)++; (m.p) == (m.pe) {
1389 goto _test_eof52
1390 }
1391 st_case_52:
1392 //line machine.go:1322
1393 switch (m.data)[(m.p)] {
1394 case 10:
1395 goto tr36
1396 case 13:
1397 goto st10
1398 case 32:
1399 goto st52
1400 }
1401 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
1402 goto st52
1403 }
1404 goto st0
1405 st53:
1406 if (m.p)++; (m.p) == (m.pe) {
1407 goto _test_eof53
1408 }
1409 st_case_53:
1410 switch (m.data)[(m.p)] {
1411 case 10:
1412 goto tr91
1413 case 13:
1414 goto tr92
1415 case 32:
1416 goto tr90
1417 }
1418 switch {
1419 case (m.data)[(m.p)] > 12:
1420 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1421 goto st54
1422 }
1423 case (m.data)[(m.p)] >= 9:
1424 goto tr90
1425 }
1426 goto tr37
1427 st54:
1428 if (m.p)++; (m.p) == (m.pe) {
1429 goto _test_eof54
1430 }
1431 st_case_54:
1432 switch (m.data)[(m.p)] {
1433 case 10:
1434 goto tr91
1435 case 13:
1436 goto tr92
1437 case 32:
1438 goto tr90
1439 }
1440 switch {
1441 case (m.data)[(m.p)] > 12:
1442 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1443 goto st55
1444 }
1445 case (m.data)[(m.p)] >= 9:
1446 goto tr90
1447 }
1448 goto tr37
1449 st55:
1450 if (m.p)++; (m.p) == (m.pe) {
1451 goto _test_eof55
1452 }
1453 st_case_55:
1454 switch (m.data)[(m.p)] {
1455 case 10:
1456 goto tr91
1457 case 13:
1458 goto tr92
1459 case 32:
1460 goto tr90
1461 }
1462 switch {
1463 case (m.data)[(m.p)] > 12:
1464 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1465 goto st56
1466 }
1467 case (m.data)[(m.p)] >= 9:
1468 goto tr90
1469 }
1470 goto tr37
1471 st56:
1472 if (m.p)++; (m.p) == (m.pe) {
1473 goto _test_eof56
1474 }
1475 st_case_56:
1476 switch (m.data)[(m.p)] {
1477 case 10:
1478 goto tr91
1479 case 13:
1480 goto tr92
1481 case 32:
1482 goto tr90
1483 }
1484 switch {
1485 case (m.data)[(m.p)] > 12:
1486 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1487 goto st57
1488 }
1489 case (m.data)[(m.p)] >= 9:
1490 goto tr90
1491 }
1492 goto tr37
1493 st57:
1494 if (m.p)++; (m.p) == (m.pe) {
1495 goto _test_eof57
1496 }
1497 st_case_57:
1498 switch (m.data)[(m.p)] {
1499 case 10:
1500 goto tr91
1501 case 13:
1502 goto tr92
1503 case 32:
1504 goto tr90
1505 }
1506 switch {
1507 case (m.data)[(m.p)] > 12:
1508 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1509 goto st58
1510 }
1511 case (m.data)[(m.p)] >= 9:
1512 goto tr90
1513 }
1514 goto tr37
1515 st58:
1516 if (m.p)++; (m.p) == (m.pe) {
1517 goto _test_eof58
1518 }
1519 st_case_58:
1520 switch (m.data)[(m.p)] {
1521 case 10:
1522 goto tr91
1523 case 13:
1524 goto tr92
1525 case 32:
1526 goto tr90
1527 }
1528 switch {
1529 case (m.data)[(m.p)] > 12:
1530 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1531 goto st59
1532 }
1533 case (m.data)[(m.p)] >= 9:
1534 goto tr90
1535 }
1536 goto tr37
1537 st59:
1538 if (m.p)++; (m.p) == (m.pe) {
1539 goto _test_eof59
1540 }
1541 st_case_59:
1542 switch (m.data)[(m.p)] {
1543 case 10:
1544 goto tr91
1545 case 13:
1546 goto tr92
1547 case 32:
1548 goto tr90
1549 }
1550 switch {
1551 case (m.data)[(m.p)] > 12:
1552 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1553 goto st60
1554 }
1555 case (m.data)[(m.p)] >= 9:
1556 goto tr90
1557 }
1558 goto tr37
1559 st60:
1560 if (m.p)++; (m.p) == (m.pe) {
1561 goto _test_eof60
1562 }
1563 st_case_60:
1564 switch (m.data)[(m.p)] {
1565 case 10:
1566 goto tr91
1567 case 13:
1568 goto tr92
1569 case 32:
1570 goto tr90
1571 }
1572 switch {
1573 case (m.data)[(m.p)] > 12:
1574 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1575 goto st61
1576 }
1577 case (m.data)[(m.p)] >= 9:
1578 goto tr90
1579 }
1580 goto tr37
1581 st61:
1582 if (m.p)++; (m.p) == (m.pe) {
1583 goto _test_eof61
1584 }
1585 st_case_61:
1586 switch (m.data)[(m.p)] {
1587 case 10:
1588 goto tr91
1589 case 13:
1590 goto tr92
1591 case 32:
1592 goto tr90
1593 }
1594 switch {
1595 case (m.data)[(m.p)] > 12:
1596 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1597 goto st62
1598 }
1599 case (m.data)[(m.p)] >= 9:
1600 goto tr90
1601 }
1602 goto tr37
1603 st62:
1604 if (m.p)++; (m.p) == (m.pe) {
1605 goto _test_eof62
1606 }
1607 st_case_62:
1608 switch (m.data)[(m.p)] {
1609 case 10:
1610 goto tr91
1611 case 13:
1612 goto tr92
1613 case 32:
1614 goto tr90
1615 }
1616 switch {
1617 case (m.data)[(m.p)] > 12:
1618 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1619 goto st63
1620 }
1621 case (m.data)[(m.p)] >= 9:
1622 goto tr90
1623 }
1624 goto tr37
1625 st63:
1626 if (m.p)++; (m.p) == (m.pe) {
1627 goto _test_eof63
1628 }
1629 st_case_63:
1630 switch (m.data)[(m.p)] {
1631 case 10:
1632 goto tr91
1633 case 13:
1634 goto tr92
1635 case 32:
1636 goto tr90
1637 }
1638 switch {
1639 case (m.data)[(m.p)] > 12:
1640 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1641 goto st64
1642 }
1643 case (m.data)[(m.p)] >= 9:
1644 goto tr90
1645 }
1646 goto tr37
1647 st64:
1648 if (m.p)++; (m.p) == (m.pe) {
1649 goto _test_eof64
1650 }
1651 st_case_64:
1652 switch (m.data)[(m.p)] {
1653 case 10:
1654 goto tr91
1655 case 13:
1656 goto tr92
1657 case 32:
1658 goto tr90
1659 }
1660 switch {
1661 case (m.data)[(m.p)] > 12:
1662 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1663 goto st65
1664 }
1665 case (m.data)[(m.p)] >= 9:
1666 goto tr90
1667 }
1668 goto tr37
1669 st65:
1670 if (m.p)++; (m.p) == (m.pe) {
1671 goto _test_eof65
1672 }
1673 st_case_65:
1674 switch (m.data)[(m.p)] {
1675 case 10:
1676 goto tr91
1677 case 13:
1678 goto tr92
1679 case 32:
1680 goto tr90
1681 }
1682 switch {
1683 case (m.data)[(m.p)] > 12:
1684 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1685 goto st66
1686 }
1687 case (m.data)[(m.p)] >= 9:
1688 goto tr90
1689 }
1690 goto tr37
1691 st66:
1692 if (m.p)++; (m.p) == (m.pe) {
1693 goto _test_eof66
1694 }
1695 st_case_66:
1696 switch (m.data)[(m.p)] {
1697 case 10:
1698 goto tr91
1699 case 13:
1700 goto tr92
1701 case 32:
1702 goto tr90
1703 }
1704 switch {
1705 case (m.data)[(m.p)] > 12:
1706 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1707 goto st67
1708 }
1709 case (m.data)[(m.p)] >= 9:
1710 goto tr90
1711 }
1712 goto tr37
1713 st67:
1714 if (m.p)++; (m.p) == (m.pe) {
1715 goto _test_eof67
1716 }
1717 st_case_67:
1718 switch (m.data)[(m.p)] {
1719 case 10:
1720 goto tr91
1721 case 13:
1722 goto tr92
1723 case 32:
1724 goto tr90
1725 }
1726 switch {
1727 case (m.data)[(m.p)] > 12:
1728 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1729 goto st68
1730 }
1731 case (m.data)[(m.p)] >= 9:
1732 goto tr90
1733 }
1734 goto tr37
1735 st68:
1736 if (m.p)++; (m.p) == (m.pe) {
1737 goto _test_eof68
1738 }
1739 st_case_68:
1740 switch (m.data)[(m.p)] {
1741 case 10:
1742 goto tr91
1743 case 13:
1744 goto tr92
1745 case 32:
1746 goto tr90
1747 }
1748 switch {
1749 case (m.data)[(m.p)] > 12:
1750 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1751 goto st69
1752 }
1753 case (m.data)[(m.p)] >= 9:
1754 goto tr90
1755 }
1756 goto tr37
1757 st69:
1758 if (m.p)++; (m.p) == (m.pe) {
1759 goto _test_eof69
1760 }
1761 st_case_69:
1762 switch (m.data)[(m.p)] {
1763 case 10:
1764 goto tr91
1765 case 13:
1766 goto tr92
1767 case 32:
1768 goto tr90
1769 }
1770 switch {
1771 case (m.data)[(m.p)] > 12:
1772 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1773 goto st70
1774 }
1775 case (m.data)[(m.p)] >= 9:
1776 goto tr90
1777 }
1778 goto tr37
1779 st70:
1780 if (m.p)++; (m.p) == (m.pe) {
1781 goto _test_eof70
1782 }
1783 st_case_70:
1784 switch (m.data)[(m.p)] {
1785 case 10:
1786 goto tr91
1787 case 13:
1788 goto tr92
1789 case 32:
1790 goto tr90
1791 }
1792 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
1793 goto tr90
1794 }
1795 goto tr37
1796 tr115:
1797 (m.cs) = 12
1798 //line machine.go.rl:122
1799
1800 err = m.handler.AddFloat(m.key, m.text())
1801 if err != nil {
1802 (m.p)--
1803
1804 (m.cs) = 35
1805 {
1806 (m.p)++
1807 goto _out
1808 }
1809 }
1810
1811 goto _again
1812 tr122:
1813 (m.cs) = 12
1814 //line machine.go.rl:104
1815
1816 err = m.handler.AddInt(m.key, m.text())
1817 if err != nil {
1818 (m.p)--
1819
1820 (m.cs) = 35
1821 {
1822 (m.p)++
1823 goto _out
1824 }
1825 }
1826
1827 goto _again
1828 tr127:
1829 (m.cs) = 12
1830 //line machine.go.rl:113
1831
1832 err = m.handler.AddUint(m.key, m.text())
1833 if err != nil {
1834 (m.p)--
1835
1836 (m.cs) = 35
1837 {
1838 (m.p)++
1839 goto _out
1840 }
1841 }
1842
1843 goto _again
1844 tr132:
1845 (m.cs) = 12
1846 //line machine.go.rl:131
1847
1848 err = m.handler.AddBool(m.key, m.text())
1849 if err != nil {
1850 (m.p)--
1851
1852 (m.cs) = 35
1853 {
1854 (m.p)++
1855 goto _out
1856 }
1857 }
1858
1859 goto _again
1860 st12:
1861 if (m.p)++; (m.p) == (m.pe) {
1862 goto _test_eof12
1863 }
1864 st_case_12:
1865 //line machine.go:1783
1866 switch (m.data)[(m.p)] {
1867 case 32:
1868 goto tr7
1869 case 44:
1870 goto tr7
1871 case 61:
1872 goto tr7
1873 case 92:
1874 goto tr8
1875 }
1876 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
1877 goto tr7
1878 }
1879 goto tr5
1880 tr8:
1881 //line machine.go.rl:20
1882
1883 m.pb = m.p
1884
1885 goto st13
1886 st13:
1887 if (m.p)++; (m.p) == (m.pe) {
1888 goto _test_eof13
1889 }
1890 st_case_13:
1891 //line machine.go:1809
1892 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
1893 goto tr7
1894 }
1895 goto st3
1896 tr25:
1897 //line machine.go.rl:20
1898
1899 m.pb = m.p
1900
1901 goto st14
1902 st14:
1903 if (m.p)++; (m.p) == (m.pe) {
1904 goto _test_eof14
1905 }
1906 st_case_14:
1907 //line machine.go:1825
1908 switch (m.data)[(m.p)] {
1909 case 34:
1910 goto st6
1911 case 92:
1912 goto st6
1913 }
1914 goto tr7
1915 tr13:
1916 //line machine.go.rl:20
1917
1918 m.pb = m.p
1919
1920 goto st15
1921 st15:
1922 if (m.p)++; (m.p) == (m.pe) {
1923 goto _test_eof15
1924 }
1925 st_case_15:
1926 //line machine.go:1844
1927 switch (m.data)[(m.p)] {
1928 case 46:
1929 goto st16
1930 case 48:
1931 goto st73
1932 }
1933 if 49 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1934 goto st76
1935 }
1936 goto tr7
1937 tr14:
1938 //line machine.go.rl:20
1939
1940 m.pb = m.p
1941
1942 goto st16
1943 st16:
1944 if (m.p)++; (m.p) == (m.pe) {
1945 goto _test_eof16
1946 }
1947 st_case_16:
1948 //line machine.go:1866
1949 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1950 goto st71
1951 }
1952 goto tr7
1953 st71:
1954 if (m.p)++; (m.p) == (m.pe) {
1955 goto _test_eof71
1956 }
1957 st_case_71:
1958 switch (m.data)[(m.p)] {
1959 case 10:
1960 goto tr113
1961 case 13:
1962 goto tr114
1963 case 32:
1964 goto tr112
1965 case 44:
1966 goto tr115
1967 case 69:
1968 goto st17
1969 case 101:
1970 goto st17
1971 }
1972 switch {
1973 case (m.data)[(m.p)] > 12:
1974 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1975 goto st71
1976 }
1977 case (m.data)[(m.p)] >= 9:
1978 goto tr112
1979 }
1980 goto tr84
1981 st17:
1982 if (m.p)++; (m.p) == (m.pe) {
1983 goto _test_eof17
1984 }
1985 st_case_17:
1986 switch (m.data)[(m.p)] {
1987 case 34:
1988 goto st18
1989 case 43:
1990 goto st18
1991 case 45:
1992 goto st18
1993 }
1994 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
1995 goto st72
1996 }
1997 goto tr7
1998 st18:
1999 if (m.p)++; (m.p) == (m.pe) {
2000 goto _test_eof18
2001 }
2002 st_case_18:
2003 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
2004 goto st72
2005 }
2006 goto tr7
2007 st72:
2008 if (m.p)++; (m.p) == (m.pe) {
2009 goto _test_eof72
2010 }
2011 st_case_72:
2012 switch (m.data)[(m.p)] {
2013 case 10:
2014 goto tr113
2015 case 13:
2016 goto tr114
2017 case 32:
2018 goto tr112
2019 case 44:
2020 goto tr115
2021 }
2022 switch {
2023 case (m.data)[(m.p)] > 12:
2024 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
2025 goto st72
2026 }
2027 case (m.data)[(m.p)] >= 9:
2028 goto tr112
2029 }
2030 goto tr84
2031 st73:
2032 if (m.p)++; (m.p) == (m.pe) {
2033 goto _test_eof73
2034 }
2035 st_case_73:
2036 switch (m.data)[(m.p)] {
2037 case 10:
2038 goto tr113
2039 case 13:
2040 goto tr114
2041 case 32:
2042 goto tr112
2043 case 44:
2044 goto tr115
2045 case 46:
2046 goto st71
2047 case 69:
2048 goto st17
2049 case 101:
2050 goto st17
2051 case 105:
2052 goto st75
2053 }
2054 switch {
2055 case (m.data)[(m.p)] > 12:
2056 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
2057 goto st74
2058 }
2059 case (m.data)[(m.p)] >= 9:
2060 goto tr112
2061 }
2062 goto tr84
2063 st74:
2064 if (m.p)++; (m.p) == (m.pe) {
2065 goto _test_eof74
2066 }
2067 st_case_74:
2068 switch (m.data)[(m.p)] {
2069 case 10:
2070 goto tr113
2071 case 13:
2072 goto tr114
2073 case 32:
2074 goto tr112
2075 case 44:
2076 goto tr115
2077 case 46:
2078 goto st71
2079 case 69:
2080 goto st17
2081 case 101:
2082 goto st17
2083 }
2084 switch {
2085 case (m.data)[(m.p)] > 12:
2086 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
2087 goto st74
2088 }
2089 case (m.data)[(m.p)] >= 9:
2090 goto tr112
2091 }
2092 goto tr84
2093 st75:
2094 if (m.p)++; (m.p) == (m.pe) {
2095 goto _test_eof75
2096 }
2097 st_case_75:
2098 switch (m.data)[(m.p)] {
2099 case 10:
2100 goto tr120
2101 case 13:
2102 goto tr121
2103 case 32:
2104 goto tr119
2105 case 44:
2106 goto tr122
2107 }
2108 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2109 goto tr119
2110 }
2111 goto tr84
2112 st76:
2113 if (m.p)++; (m.p) == (m.pe) {
2114 goto _test_eof76
2115 }
2116 st_case_76:
2117 switch (m.data)[(m.p)] {
2118 case 10:
2119 goto tr113
2120 case 13:
2121 goto tr114
2122 case 32:
2123 goto tr112
2124 case 44:
2125 goto tr115
2126 case 46:
2127 goto st71
2128 case 69:
2129 goto st17
2130 case 101:
2131 goto st17
2132 case 105:
2133 goto st75
2134 }
2135 switch {
2136 case (m.data)[(m.p)] > 12:
2137 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
2138 goto st76
2139 }
2140 case (m.data)[(m.p)] >= 9:
2141 goto tr112
2142 }
2143 goto tr84
2144 tr15:
2145 //line machine.go.rl:20
2146
2147 m.pb = m.p
2148
2149 goto st77
2150 st77:
2151 if (m.p)++; (m.p) == (m.pe) {
2152 goto _test_eof77
2153 }
2154 st_case_77:
2155 //line machine.go:2073
2156 switch (m.data)[(m.p)] {
2157 case 10:
2158 goto tr113
2159 case 13:
2160 goto tr114
2161 case 32:
2162 goto tr112
2163 case 44:
2164 goto tr115
2165 case 46:
2166 goto st71
2167 case 69:
2168 goto st17
2169 case 101:
2170 goto st17
2171 case 105:
2172 goto st75
2173 case 117:
2174 goto st78
2175 }
2176 switch {
2177 case (m.data)[(m.p)] > 12:
2178 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
2179 goto st74
2180 }
2181 case (m.data)[(m.p)] >= 9:
2182 goto tr112
2183 }
2184 goto tr84
2185 st78:
2186 if (m.p)++; (m.p) == (m.pe) {
2187 goto _test_eof78
2188 }
2189 st_case_78:
2190 switch (m.data)[(m.p)] {
2191 case 10:
2192 goto tr125
2193 case 13:
2194 goto tr126
2195 case 32:
2196 goto tr124
2197 case 44:
2198 goto tr127
2199 }
2200 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2201 goto tr124
2202 }
2203 goto tr84
2204 tr16:
2205 //line machine.go.rl:20
2206
2207 m.pb = m.p
2208
2209 goto st79
2210 st79:
2211 if (m.p)++; (m.p) == (m.pe) {
2212 goto _test_eof79
2213 }
2214 st_case_79:
2215 //line machine.go:2133
2216 switch (m.data)[(m.p)] {
2217 case 10:
2218 goto tr113
2219 case 13:
2220 goto tr114
2221 case 32:
2222 goto tr112
2223 case 44:
2224 goto tr115
2225 case 46:
2226 goto st71
2227 case 69:
2228 goto st17
2229 case 101:
2230 goto st17
2231 case 105:
2232 goto st75
2233 case 117:
2234 goto st78
2235 }
2236 switch {
2237 case (m.data)[(m.p)] > 12:
2238 if 48 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 57 {
2239 goto st79
2240 }
2241 case (m.data)[(m.p)] >= 9:
2242 goto tr112
2243 }
2244 goto tr84
2245 tr17:
2246 //line machine.go.rl:20
2247
2248 m.pb = m.p
2249
2250 goto st80
2251 st80:
2252 if (m.p)++; (m.p) == (m.pe) {
2253 goto _test_eof80
2254 }
2255 st_case_80:
2256 //line machine.go:2174
2257 switch (m.data)[(m.p)] {
2258 case 10:
2259 goto tr130
2260 case 13:
2261 goto tr131
2262 case 32:
2263 goto tr129
2264 case 44:
2265 goto tr132
2266 case 65:
2267 goto st19
2268 case 97:
2269 goto st22
2270 }
2271 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2272 goto tr129
2273 }
2274 goto tr84
2275 st19:
2276 if (m.p)++; (m.p) == (m.pe) {
2277 goto _test_eof19
2278 }
2279 st_case_19:
2280 if (m.data)[(m.p)] == 76 {
2281 goto st20
2282 }
2283 goto tr7
2284 st20:
2285 if (m.p)++; (m.p) == (m.pe) {
2286 goto _test_eof20
2287 }
2288 st_case_20:
2289 if (m.data)[(m.p)] == 83 {
2290 goto st21
2291 }
2292 goto tr7
2293 st21:
2294 if (m.p)++; (m.p) == (m.pe) {
2295 goto _test_eof21
2296 }
2297 st_case_21:
2298 if (m.data)[(m.p)] == 69 {
2299 goto st81
2300 }
2301 goto tr7
2302 st81:
2303 if (m.p)++; (m.p) == (m.pe) {
2304 goto _test_eof81
2305 }
2306 st_case_81:
2307 switch (m.data)[(m.p)] {
2308 case 10:
2309 goto tr130
2310 case 13:
2311 goto tr131
2312 case 32:
2313 goto tr129
2314 case 44:
2315 goto tr132
2316 }
2317 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2318 goto tr129
2319 }
2320 goto tr84
2321 st22:
2322 if (m.p)++; (m.p) == (m.pe) {
2323 goto _test_eof22
2324 }
2325 st_case_22:
2326 if (m.data)[(m.p)] == 108 {
2327 goto st23
2328 }
2329 goto tr7
2330 st23:
2331 if (m.p)++; (m.p) == (m.pe) {
2332 goto _test_eof23
2333 }
2334 st_case_23:
2335 if (m.data)[(m.p)] == 115 {
2336 goto st24
2337 }
2338 goto tr7
2339 st24:
2340 if (m.p)++; (m.p) == (m.pe) {
2341 goto _test_eof24
2342 }
2343 st_case_24:
2344 if (m.data)[(m.p)] == 101 {
2345 goto st81
2346 }
2347 goto tr7
2348 tr18:
2349 //line machine.go.rl:20
2350
2351 m.pb = m.p
2352
2353 goto st82
2354 st82:
2355 if (m.p)++; (m.p) == (m.pe) {
2356 goto _test_eof82
2357 }
2358 st_case_82:
2359 //line machine.go:2277
2360 switch (m.data)[(m.p)] {
2361 case 10:
2362 goto tr130
2363 case 13:
2364 goto tr131
2365 case 32:
2366 goto tr129
2367 case 44:
2368 goto tr132
2369 case 82:
2370 goto st25
2371 case 114:
2372 goto st26
2373 }
2374 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2375 goto tr129
2376 }
2377 goto tr84
2378 st25:
2379 if (m.p)++; (m.p) == (m.pe) {
2380 goto _test_eof25
2381 }
2382 st_case_25:
2383 if (m.data)[(m.p)] == 85 {
2384 goto st21
2385 }
2386 goto tr7
2387 st26:
2388 if (m.p)++; (m.p) == (m.pe) {
2389 goto _test_eof26
2390 }
2391 st_case_26:
2392 if (m.data)[(m.p)] == 117 {
2393 goto st24
2394 }
2395 goto tr7
2396 tr19:
2397 //line machine.go.rl:20
2398
2399 m.pb = m.p
2400
2401 goto st83
2402 st83:
2403 if (m.p)++; (m.p) == (m.pe) {
2404 goto _test_eof83
2405 }
2406 st_case_83:
2407 //line machine.go:2325
2408 switch (m.data)[(m.p)] {
2409 case 10:
2410 goto tr130
2411 case 13:
2412 goto tr131
2413 case 32:
2414 goto tr129
2415 case 44:
2416 goto tr132
2417 case 97:
2418 goto st22
2419 }
2420 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2421 goto tr129
2422 }
2423 goto tr84
2424 tr20:
2425 //line machine.go.rl:20
2426
2427 m.pb = m.p
2428
2429 goto st84
2430 st84:
2431 if (m.p)++; (m.p) == (m.pe) {
2432 goto _test_eof84
2433 }
2434 st_case_84:
2435 //line machine.go:2353
2436 switch (m.data)[(m.p)] {
2437 case 10:
2438 goto tr130
2439 case 13:
2440 goto tr131
2441 case 32:
2442 goto tr129
2443 case 44:
2444 goto tr132
2445 case 114:
2446 goto st26
2447 }
2448 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2449 goto tr129
2450 }
2451 goto tr84
2452 tr3:
2453 (m.cs) = 27
2454 //line machine.go.rl:78
2455
2456 err = m.handler.SetMeasurement(m.text())
2457 if err != nil {
2458 (m.p)--
2459
2460 (m.cs) = 35
2461 {
2462 (m.p)++
2463 goto _out
2464 }
2465 }
2466
2467 goto _again
2468 tr59:
2469 (m.cs) = 27
2470 //line machine.go.rl:91
2471
2472 err = m.handler.AddTag(m.key, m.text())
2473 if err != nil {
2474 (m.p)--
2475
2476 (m.cs) = 35
2477 {
2478 (m.p)++
2479 goto _out
2480 }
2481 }
2482
2483 goto _again
2484 st27:
2485 if (m.p)++; (m.p) == (m.pe) {
2486 goto _test_eof27
2487 }
2488 st_case_27:
2489 //line machine.go:2401
2490 switch (m.data)[(m.p)] {
2491 case 32:
2492 goto tr2
2493 case 44:
2494 goto tr2
2495 case 61:
2496 goto tr2
2497 case 92:
2498 goto tr51
2499 }
2500 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2501 goto tr2
2502 }
2503 goto tr50
2504 tr50:
2505 //line machine.go.rl:20
2506
2507 m.pb = m.p
2508
2509 goto st28
2510 st28:
2511 if (m.p)++; (m.p) == (m.pe) {
2512 goto _test_eof28
2513 }
2514 st_case_28:
2515 //line machine.go:2427
2516 switch (m.data)[(m.p)] {
2517 case 32:
2518 goto tr2
2519 case 44:
2520 goto tr2
2521 case 61:
2522 goto tr53
2523 case 92:
2524 goto st33
2525 }
2526 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2527 goto tr2
2528 }
2529 goto st28
2530 tr53:
2531 //line machine.go.rl:87
2532
2533 m.key = m.text()
2534
2535 goto st29
2536 st29:
2537 if (m.p)++; (m.p) == (m.pe) {
2538 goto _test_eof29
2539 }
2540 st_case_29:
2541 //line machine.go:2453
2542 switch (m.data)[(m.p)] {
2543 case 32:
2544 goto tr2
2545 case 44:
2546 goto tr2
2547 case 61:
2548 goto tr2
2549 case 92:
2550 goto tr56
2551 }
2552 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2553 goto tr2
2554 }
2555 goto tr55
2556 tr55:
2557 //line machine.go.rl:20
2558
2559 m.pb = m.p
2560
2561 goto st30
2562 st30:
2563 if (m.p)++; (m.p) == (m.pe) {
2564 goto _test_eof30
2565 }
2566 st_case_30:
2567 //line machine.go:2479
2568 switch (m.data)[(m.p)] {
2569 case 10:
2570 goto tr2
2571 case 13:
2572 goto tr2
2573 case 32:
2574 goto tr58
2575 case 44:
2576 goto tr59
2577 case 61:
2578 goto tr2
2579 case 92:
2580 goto st31
2581 }
2582 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2583 goto tr58
2584 }
2585 goto st30
2586 tr56:
2587 //line machine.go.rl:20
2588
2589 m.pb = m.p
2590
2591 goto st31
2592 st31:
2593 if (m.p)++; (m.p) == (m.pe) {
2594 goto _test_eof31
2595 }
2596 st_case_31:
2597 //line machine.go:2509
2598 if (m.data)[(m.p)] == 92 {
2599 goto st32
2600 }
2601 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2602 goto tr2
2603 }
2604 goto st30
2605 st32:
2606 //line machine.go.rl:240
2607 (m.p)--
2608
2609 if (m.p)++; (m.p) == (m.pe) {
2610 goto _test_eof32
2611 }
2612 st_case_32:
2613 //line machine.go:2525
2614 switch (m.data)[(m.p)] {
2615 case 10:
2616 goto tr2
2617 case 13:
2618 goto tr2
2619 case 32:
2620 goto tr58
2621 case 44:
2622 goto tr59
2623 case 61:
2624 goto tr2
2625 case 92:
2626 goto st31
2627 }
2628 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2629 goto tr58
2630 }
2631 goto st30
2632 tr51:
2633 //line machine.go.rl:20
2634
2635 m.pb = m.p
2636
2637 goto st33
2638 st33:
2639 if (m.p)++; (m.p) == (m.pe) {
2640 goto _test_eof33
2641 }
2642 st_case_33:
2643 //line machine.go:2555
2644 if (m.data)[(m.p)] == 92 {
2645 goto st34
2646 }
2647 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2648 goto tr2
2649 }
2650 goto st28
2651 st34:
2652 //line machine.go.rl:240
2653 (m.p)--
2654
2655 if (m.p)++; (m.p) == (m.pe) {
2656 goto _test_eof34
2657 }
2658 st_case_34:
2659 //line machine.go:2571
2660 switch (m.data)[(m.p)] {
2661 case 32:
2662 goto tr2
2663 case 44:
2664 goto tr2
2665 case 61:
2666 goto tr53
2667 case 92:
2668 goto st33
2669 }
2670 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2671 goto tr2
2672 }
2673 goto st28
2674 st35:
2675 if (m.p)++; (m.p) == (m.pe) {
2676 goto _test_eof35
2677 }
2678 st_case_35:
2679 if (m.data)[(m.p)] == 10 {
2680 goto tr64
2681 }
2682 goto st35
2683 tr64:
2684 //line machine.go.rl:158
2685
2686 m.lineno++
2687 m.sol = m.p
2688 m.sol++ // next char will be the first column in the line
2689
2690 //line machine.go.rl:70
2691
2692 {
2693 goto st86
2694 }
2695
2696 goto st85
2697 st85:
2698 if (m.p)++; (m.p) == (m.pe) {
2699 goto _test_eof85
2700 }
2701 st_case_85:
2702 //line machine.go:2612
2703 goto st0
2704 st38:
2705 if (m.p)++; (m.p) == (m.pe) {
2706 goto _test_eof38
2707 }
2708 st_case_38:
2709 switch (m.data)[(m.p)] {
2710 case 32:
2711 goto tr33
2712 case 35:
2713 goto tr33
2714 case 44:
2715 goto tr33
2716 case 92:
2717 goto tr68
2718 }
2719 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2720 goto tr33
2721 }
2722 goto tr67
2723 tr67:
2724 //line machine.go.rl:74
2725
2726 m.beginMetric = true
2727
2728 //line machine.go.rl:20
2729
2730 m.pb = m.p
2731
2732 goto st87
2733 st87:
2734 if (m.p)++; (m.p) == (m.pe) {
2735 goto _test_eof87
2736 }
2737 st_case_87:
2738 //line machine.go:2648
2739 switch (m.data)[(m.p)] {
2740 case 10:
2741 goto tr140
2742 case 13:
2743 goto tr141
2744 case 32:
2745 goto tr2
2746 case 44:
2747 goto tr142
2748 case 92:
2749 goto st46
2750 }
2751 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2752 goto tr2
2753 }
2754 goto st87
2755 tr69:
2756 //line machine.go.rl:158
2757
2758 m.lineno++
2759 m.sol = m.p
2760 m.sol++ // next char will be the first column in the line
2761
2762 goto st88
2763 tr140:
2764 (m.cs) = 88
2765 //line machine.go.rl:78
2766
2767 err = m.handler.SetMeasurement(m.text())
2768 if err != nil {
2769 (m.p)--
2770
2771 (m.cs) = 35
2772 {
2773 (m.p)++
2774 goto _out
2775 }
2776 }
2777
2778 //line machine.go.rl:158
2779
2780 m.lineno++
2781 m.sol = m.p
2782 m.sol++ // next char will be the first column in the line
2783
2784 goto _again
2785 tr144:
2786 (m.cs) = 88
2787 //line machine.go.rl:91
2788
2789 err = m.handler.AddTag(m.key, m.text())
2790 if err != nil {
2791 (m.p)--
2792
2793 (m.cs) = 35
2794 {
2795 (m.p)++
2796 goto _out
2797 }
2798 }
2799
2800 //line machine.go.rl:158
2801
2802 m.lineno++
2803 m.sol = m.p
2804 m.sol++ // next char will be the first column in the line
2805
2806 goto _again
2807 st88:
2808 //line machine.go.rl:164
2809
2810 m.finishMetric = true
2811 (m.cs) = 86
2812 {
2813 (m.p)++
2814 goto _out
2815 }
2816
2817 if (m.p)++; (m.p) == (m.pe) {
2818 goto _test_eof88
2819 }
2820 st_case_88:
2821 //line machine.go:2722
2822 goto st0
2823 tr141:
2824 (m.cs) = 39
2825 //line machine.go.rl:78
2826
2827 err = m.handler.SetMeasurement(m.text())
2828 if err != nil {
2829 (m.p)--
2830
2831 (m.cs) = 35
2832 {
2833 (m.p)++
2834 goto _out
2835 }
2836 }
2837
2838 goto _again
2839 tr145:
2840 (m.cs) = 39
2841 //line machine.go.rl:91
2842
2843 err = m.handler.AddTag(m.key, m.text())
2844 if err != nil {
2845 (m.p)--
2846
2847 (m.cs) = 35
2848 {
2849 (m.p)++
2850 goto _out
2851 }
2852 }
2853
2854 goto _again
2855 st39:
2856 if (m.p)++; (m.p) == (m.pe) {
2857 goto _test_eof39
2858 }
2859 st_case_39:
2860 //line machine.go:2755
2861 if (m.data)[(m.p)] == 10 {
2862 goto tr69
2863 }
2864 goto st0
2865 tr142:
2866 (m.cs) = 40
2867 //line machine.go.rl:78
2868
2869 err = m.handler.SetMeasurement(m.text())
2870 if err != nil {
2871 (m.p)--
2872
2873 (m.cs) = 35
2874 {
2875 (m.p)++
2876 goto _out
2877 }
2878 }
2879
2880 goto _again
2881 tr146:
2882 (m.cs) = 40
2883 //line machine.go.rl:91
2884
2885 err = m.handler.AddTag(m.key, m.text())
2886 if err != nil {
2887 (m.p)--
2888
2889 (m.cs) = 35
2890 {
2891 (m.p)++
2892 goto _out
2893 }
2894 }
2895
2896 goto _again
2897 st40:
2898 if (m.p)++; (m.p) == (m.pe) {
2899 goto _test_eof40
2900 }
2901 st_case_40:
2902 //line machine.go:2791
2903 switch (m.data)[(m.p)] {
2904 case 32:
2905 goto tr2
2906 case 44:
2907 goto tr2
2908 case 61:
2909 goto tr2
2910 case 92:
2911 goto tr71
2912 }
2913 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2914 goto tr2
2915 }
2916 goto tr70
2917 tr70:
2918 //line machine.go.rl:20
2919
2920 m.pb = m.p
2921
2922 goto st41
2923 st41:
2924 if (m.p)++; (m.p) == (m.pe) {
2925 goto _test_eof41
2926 }
2927 st_case_41:
2928 //line machine.go:2817
2929 switch (m.data)[(m.p)] {
2930 case 32:
2931 goto tr2
2932 case 44:
2933 goto tr2
2934 case 61:
2935 goto tr73
2936 case 92:
2937 goto st44
2938 }
2939 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2940 goto tr2
2941 }
2942 goto st41
2943 tr73:
2944 //line machine.go.rl:87
2945
2946 m.key = m.text()
2947
2948 goto st42
2949 st42:
2950 if (m.p)++; (m.p) == (m.pe) {
2951 goto _test_eof42
2952 }
2953 st_case_42:
2954 //line machine.go:2843
2955 switch (m.data)[(m.p)] {
2956 case 32:
2957 goto tr2
2958 case 44:
2959 goto tr2
2960 case 61:
2961 goto tr2
2962 case 92:
2963 goto tr76
2964 }
2965 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
2966 goto tr2
2967 }
2968 goto tr75
2969 tr75:
2970 //line machine.go.rl:20
2971
2972 m.pb = m.p
2973
2974 goto st89
2975 st89:
2976 if (m.p)++; (m.p) == (m.pe) {
2977 goto _test_eof89
2978 }
2979 st_case_89:
2980 //line machine.go:2869
2981 switch (m.data)[(m.p)] {
2982 case 10:
2983 goto tr144
2984 case 13:
2985 goto tr145
2986 case 32:
2987 goto tr2
2988 case 44:
2989 goto tr146
2990 case 61:
2991 goto tr2
2992 case 92:
2993 goto st43
2994 }
2995 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
2996 goto tr2
2997 }
2998 goto st89
2999 tr76:
3000 //line machine.go.rl:20
3001
3002 m.pb = m.p
3003
3004 goto st43
3005 st43:
3006 if (m.p)++; (m.p) == (m.pe) {
3007 goto _test_eof43
3008 }
3009 st_case_43:
3010 //line machine.go:2899
3011 if (m.data)[(m.p)] == 92 {
3012 goto st90
3013 }
3014 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
3015 goto tr2
3016 }
3017 goto st89
3018 st90:
3019 //line machine.go.rl:240
3020 (m.p)--
3021
3022 if (m.p)++; (m.p) == (m.pe) {
3023 goto _test_eof90
3024 }
3025 st_case_90:
3026 //line machine.go:2915
3027 switch (m.data)[(m.p)] {
3028 case 10:
3029 goto tr144
3030 case 13:
3031 goto tr145
3032 case 32:
3033 goto tr2
3034 case 44:
3035 goto tr146
3036 case 61:
3037 goto tr2
3038 case 92:
3039 goto st43
3040 }
3041 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
3042 goto tr2
3043 }
3044 goto st89
3045 tr71:
3046 //line machine.go.rl:20
3047
3048 m.pb = m.p
3049
3050 goto st44
3051 st44:
3052 if (m.p)++; (m.p) == (m.pe) {
3053 goto _test_eof44
3054 }
3055 st_case_44:
3056 //line machine.go:2945
3057 if (m.data)[(m.p)] == 92 {
3058 goto st45
3059 }
3060 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
3061 goto tr2
3062 }
3063 goto st41
3064 st45:
3065 //line machine.go.rl:240
3066 (m.p)--
3067
3068 if (m.p)++; (m.p) == (m.pe) {
3069 goto _test_eof45
3070 }
3071 st_case_45:
3072 //line machine.go:2961
3073 switch (m.data)[(m.p)] {
3074 case 32:
3075 goto tr2
3076 case 44:
3077 goto tr2
3078 case 61:
3079 goto tr73
3080 case 92:
3081 goto st44
3082 }
3083 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
3084 goto tr2
3085 }
3086 goto st41
3087 tr68:
3088 //line machine.go.rl:74
3089
3090 m.beginMetric = true
3091
3092 //line machine.go.rl:20
3093
3094 m.pb = m.p
3095
3096 goto st46
3097 st46:
3098 if (m.p)++; (m.p) == (m.pe) {
3099 goto _test_eof46
3100 }
3101 st_case_46:
3102 //line machine.go:2991
3103 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 13 {
3104 goto st0
3105 }
3106 goto st87
3107 tr65:
3108 //line machine.go.rl:158
3109
3110 m.lineno++
3111 m.sol = m.p
3112 m.sol++ // next char will be the first column in the line
3113
3114 goto st86
3115 st86:
3116 if (m.p)++; (m.p) == (m.pe) {
3117 goto _test_eof86
3118 }
3119 st_case_86:
3120 //line machine.go:3009
3121 switch (m.data)[(m.p)] {
3122 case 10:
3123 goto tr65
3124 case 13:
3125 goto st36
3126 case 32:
3127 goto st86
3128 case 35:
3129 goto st37
3130 }
3131 if 9 <= (m.data)[(m.p)] && (m.data)[(m.p)] <= 12 {
3132 goto st86
3133 }
3134 goto tr137
3135 st36:
3136 if (m.p)++; (m.p) == (m.pe) {
3137 goto _test_eof36
3138 }
3139 st_case_36:
3140 if (m.data)[(m.p)] == 10 {
3141 goto tr65
3142 }
3143 goto st0
3144 st37:
3145 if (m.p)++; (m.p) == (m.pe) {
3146 goto _test_eof37
3147 }
3148 st_case_37:
3149 if (m.data)[(m.p)] == 10 {
3150 goto tr65
3151 }
3152 goto st37
3153 st_out:
3154 _test_eof47:
3155 (m.cs) = 47
3156 goto _test_eof
3157 _test_eof1:
3158 (m.cs) = 1
3159 goto _test_eof
3160 _test_eof2:
3161 (m.cs) = 2
3162 goto _test_eof
3163 _test_eof3:
3164 (m.cs) = 3
3165 goto _test_eof
3166 _test_eof4:
3167 (m.cs) = 4
3168 goto _test_eof
3169 _test_eof5:
3170 (m.cs) = 5
3171 goto _test_eof
3172 _test_eof6:
3173 (m.cs) = 6
3174 goto _test_eof
3175 _test_eof7:
3176 (m.cs) = 7
3177 goto _test_eof
3178 _test_eof48:
3179 (m.cs) = 48
3180 goto _test_eof
3181 _test_eof49:
3182 (m.cs) = 49
3183 goto _test_eof
3184 _test_eof50:
3185 (m.cs) = 50
3186 goto _test_eof
3187 _test_eof8:
3188 (m.cs) = 8
3189 goto _test_eof
3190 _test_eof9:
3191 (m.cs) = 9
3192 goto _test_eof
3193 _test_eof10:
3194 (m.cs) = 10
3195 goto _test_eof
3196 _test_eof11:
3197 (m.cs) = 11
3198 goto _test_eof
3199 _test_eof51:
3200 (m.cs) = 51
3201 goto _test_eof
3202 _test_eof52:
3203 (m.cs) = 52
3204 goto _test_eof
3205 _test_eof53:
3206 (m.cs) = 53
3207 goto _test_eof
3208 _test_eof54:
3209 (m.cs) = 54
3210 goto _test_eof
3211 _test_eof55:
3212 (m.cs) = 55
3213 goto _test_eof
3214 _test_eof56:
3215 (m.cs) = 56
3216 goto _test_eof
3217 _test_eof57:
3218 (m.cs) = 57
3219 goto _test_eof
3220 _test_eof58:
3221 (m.cs) = 58
3222 goto _test_eof
3223 _test_eof59:
3224 (m.cs) = 59
3225 goto _test_eof
3226 _test_eof60:
3227 (m.cs) = 60
3228 goto _test_eof
3229 _test_eof61:
3230 (m.cs) = 61
3231 goto _test_eof
3232 _test_eof62:
3233 (m.cs) = 62
3234 goto _test_eof
3235 _test_eof63:
3236 (m.cs) = 63
3237 goto _test_eof
3238 _test_eof64:
3239 (m.cs) = 64
3240 goto _test_eof
3241 _test_eof65:
3242 (m.cs) = 65
3243 goto _test_eof
3244 _test_eof66:
3245 (m.cs) = 66
3246 goto _test_eof
3247 _test_eof67:
3248 (m.cs) = 67
3249 goto _test_eof
3250 _test_eof68:
3251 (m.cs) = 68
3252 goto _test_eof
3253 _test_eof69:
3254 (m.cs) = 69
3255 goto _test_eof
3256 _test_eof70:
3257 (m.cs) = 70
3258 goto _test_eof
3259 _test_eof12:
3260 (m.cs) = 12
3261 goto _test_eof
3262 _test_eof13:
3263 (m.cs) = 13
3264 goto _test_eof
3265 _test_eof14:
3266 (m.cs) = 14
3267 goto _test_eof
3268 _test_eof15:
3269 (m.cs) = 15
3270 goto _test_eof
3271 _test_eof16:
3272 (m.cs) = 16
3273 goto _test_eof
3274 _test_eof71:
3275 (m.cs) = 71
3276 goto _test_eof
3277 _test_eof17:
3278 (m.cs) = 17
3279 goto _test_eof
3280 _test_eof18:
3281 (m.cs) = 18
3282 goto _test_eof
3283 _test_eof72:
3284 (m.cs) = 72
3285 goto _test_eof
3286 _test_eof73:
3287 (m.cs) = 73
3288 goto _test_eof
3289 _test_eof74:
3290 (m.cs) = 74
3291 goto _test_eof
3292 _test_eof75:
3293 (m.cs) = 75
3294 goto _test_eof
3295 _test_eof76:
3296 (m.cs) = 76
3297 goto _test_eof
3298 _test_eof77:
3299 (m.cs) = 77
3300 goto _test_eof
3301 _test_eof78:
3302 (m.cs) = 78
3303 goto _test_eof
3304 _test_eof79:
3305 (m.cs) = 79
3306 goto _test_eof
3307 _test_eof80:
3308 (m.cs) = 80
3309 goto _test_eof
3310 _test_eof19:
3311 (m.cs) = 19
3312 goto _test_eof
3313 _test_eof20:
3314 (m.cs) = 20
3315 goto _test_eof
3316 _test_eof21:
3317 (m.cs) = 21
3318 goto _test_eof
3319 _test_eof81:
3320 (m.cs) = 81
3321 goto _test_eof
3322 _test_eof22:
3323 (m.cs) = 22
3324 goto _test_eof
3325 _test_eof23:
3326 (m.cs) = 23
3327 goto _test_eof
3328 _test_eof24:
3329 (m.cs) = 24
3330 goto _test_eof
3331 _test_eof82:
3332 (m.cs) = 82
3333 goto _test_eof
3334 _test_eof25:
3335 (m.cs) = 25
3336 goto _test_eof
3337 _test_eof26:
3338 (m.cs) = 26
3339 goto _test_eof
3340 _test_eof83:
3341 (m.cs) = 83
3342 goto _test_eof
3343 _test_eof84:
3344 (m.cs) = 84
3345 goto _test_eof
3346 _test_eof27:
3347 (m.cs) = 27
3348 goto _test_eof
3349 _test_eof28:
3350 (m.cs) = 28
3351 goto _test_eof
3352 _test_eof29:
3353 (m.cs) = 29
3354 goto _test_eof
3355 _test_eof30:
3356 (m.cs) = 30
3357 goto _test_eof
3358 _test_eof31:
3359 (m.cs) = 31
3360 goto _test_eof
3361 _test_eof32:
3362 (m.cs) = 32
3363 goto _test_eof
3364 _test_eof33:
3365 (m.cs) = 33
3366 goto _test_eof
3367 _test_eof34:
3368 (m.cs) = 34
3369 goto _test_eof
3370 _test_eof35:
3371 (m.cs) = 35
3372 goto _test_eof
3373 _test_eof85:
3374 (m.cs) = 85
3375 goto _test_eof
3376 _test_eof38:
3377 (m.cs) = 38
3378 goto _test_eof
3379 _test_eof87:
3380 (m.cs) = 87
3381 goto _test_eof
3382 _test_eof88:
3383 (m.cs) = 88
3384 goto _test_eof
3385 _test_eof39:
3386 (m.cs) = 39
3387 goto _test_eof
3388 _test_eof40:
3389 (m.cs) = 40
3390 goto _test_eof
3391 _test_eof41:
3392 (m.cs) = 41
3393 goto _test_eof
3394 _test_eof42:
3395 (m.cs) = 42
3396 goto _test_eof
3397 _test_eof89:
3398 (m.cs) = 89
3399 goto _test_eof
3400 _test_eof43:
3401 (m.cs) = 43
3402 goto _test_eof
3403 _test_eof90:
3404 (m.cs) = 90
3405 goto _test_eof
3406 _test_eof44:
3407 (m.cs) = 44
3408 goto _test_eof
3409 _test_eof45:
3410 (m.cs) = 45
3411 goto _test_eof
3412 _test_eof46:
3413 (m.cs) = 46
3414 goto _test_eof
3415 _test_eof86:
3416 (m.cs) = 86
3417 goto _test_eof
3418 _test_eof36:
3419 (m.cs) = 36
3420 goto _test_eof
3421 _test_eof37:
3422 (m.cs) = 37
3423 goto _test_eof
3424
3425 _test_eof:
3426 {
3427 }
3428 if (m.p) == (m.eof) {
3429 switch m.cs {
3430 case 8, 38:
3431 //line machine.go.rl:24
3432
3433 err = ErrNameParse
3434 (m.p)--
3435
3436 (m.cs) = 35
3437 {
3438 (m.p)++
3439 (m.cs) = 0
3440 goto _out
3441 }
3442
3443 case 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26:
3444 //line machine.go.rl:31
3445
3446 err = ErrFieldParse
3447 (m.p)--
3448
3449 (m.cs) = 35
3450 {
3451 (m.p)++
3452 (m.cs) = 0
3453 goto _out
3454 }
3455
3456 case 27, 28, 29, 31, 33, 34, 40, 41, 42, 43, 44, 45:
3457 //line machine.go.rl:38
3458
3459 err = ErrTagParse
3460 (m.p)--
3461
3462 (m.cs) = 35
3463 {
3464 (m.p)++
3465 (m.cs) = 0
3466 goto _out
3467 }
3468
3469 case 11:
3470 //line machine.go.rl:45
3471
3472 err = ErrTimestampParse
3473 (m.p)--
3474
3475 (m.cs) = 35
3476 {
3477 (m.p)++
3478 (m.cs) = 0
3479 goto _out
3480 }
3481
3482 case 87:
3483 //line machine.go.rl:78
3484
3485 err = m.handler.SetMeasurement(m.text())
3486 if err != nil {
3487 (m.p)--
3488
3489 (m.cs) = 35
3490 {
3491 (m.p)++
3492 (m.cs) = 0
3493 goto _out
3494 }
3495 }
3496
3497 case 89, 90:
3498 //line machine.go.rl:91
3499
3500 err = m.handler.AddTag(m.key, m.text())
3501 if err != nil {
3502 (m.p)--
3503
3504 (m.cs) = 35
3505 {
3506 (m.p)++
3507 (m.cs) = 0
3508 goto _out
3509 }
3510 }
3511
3512 case 48, 49, 50, 52:
3513 //line machine.go.rl:170
3514
3515 m.finishMetric = true
3516
3517 case 47:
3518 //line machine.go.rl:74
3519
3520 m.beginMetric = true
3521
3522 //line machine.go.rl:170
3523
3524 m.finishMetric = true
3525
3526 case 1:
3527 //line machine.go.rl:78
3528
3529 err = m.handler.SetMeasurement(m.text())
3530 if err != nil {
3531 (m.p)--
3532
3533 (m.cs) = 35
3534 {
3535 (m.p)++
3536 (m.cs) = 0
3537 goto _out
3538 }
3539 }
3540
3541 //line machine.go.rl:38
3542
3543 err = ErrTagParse
3544 (m.p)--
3545
3546 (m.cs) = 35
3547 {
3548 (m.p)++
3549 (m.cs) = 0
3550 goto _out
3551 }
3552
3553 case 30, 32:
3554 //line machine.go.rl:91
3555
3556 err = m.handler.AddTag(m.key, m.text())
3557 if err != nil {
3558 (m.p)--
3559
3560 (m.cs) = 35
3561 {
3562 (m.p)++
3563 (m.cs) = 0
3564 goto _out
3565 }
3566 }
3567
3568 //line machine.go.rl:38
3569
3570 err = ErrTagParse
3571 (m.p)--
3572
3573 (m.cs) = 35
3574 {
3575 (m.p)++
3576 (m.cs) = 0
3577 goto _out
3578 }
3579
3580 case 75:
3581 //line machine.go.rl:104
3582
3583 err = m.handler.AddInt(m.key, m.text())
3584 if err != nil {
3585 (m.p)--
3586
3587 (m.cs) = 35
3588 {
3589 (m.p)++
3590 (m.cs) = 0
3591 goto _out
3592 }
3593 }
3594
3595 //line machine.go.rl:170
3596
3597 m.finishMetric = true
3598
3599 case 78:
3600 //line machine.go.rl:113
3601
3602 err = m.handler.AddUint(m.key, m.text())
3603 if err != nil {
3604 (m.p)--
3605
3606 (m.cs) = 35
3607 {
3608 (m.p)++
3609 (m.cs) = 0
3610 goto _out
3611 }
3612 }
3613
3614 //line machine.go.rl:170
3615
3616 m.finishMetric = true
3617
3618 case 71, 72, 73, 74, 76, 77, 79:
3619 //line machine.go.rl:122
3620
3621 err = m.handler.AddFloat(m.key, m.text())
3622 if err != nil {
3623 (m.p)--
3624
3625 (m.cs) = 35
3626 {
3627 (m.p)++
3628 (m.cs) = 0
3629 goto _out
3630 }
3631 }
3632
3633 //line machine.go.rl:170
3634
3635 m.finishMetric = true
3636
3637 case 80, 81, 82, 83, 84:
3638 //line machine.go.rl:131
3639
3640 err = m.handler.AddBool(m.key, m.text())
3641 if err != nil {
3642 (m.p)--
3643
3644 (m.cs) = 35
3645 {
3646 (m.p)++
3647 (m.cs) = 0
3648 goto _out
3649 }
3650 }
3651
3652 //line machine.go.rl:170
3653
3654 m.finishMetric = true
3655
3656 case 51, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70:
3657 //line machine.go.rl:149
3658
3659 err = m.handler.SetTimestamp(m.text())
3660 if err != nil {
3661 (m.p)--
3662
3663 (m.cs) = 35
3664 {
3665 (m.p)++
3666 (m.cs) = 0
3667 goto _out
3668 }
3669 }
3670
3671 //line machine.go.rl:170
3672
3673 m.finishMetric = true
3674
3675 //line machine.go:3322
3676 }
3677 }
3678
3679 _out:
3680 {
3681 }
3682 }
3683
3684 //line machine.go.rl:407
3685
3686 if err != nil {
3687 return err
3688 }
3689
3690 // This would indicate an error in the machine that was reported with a
3691 // more specific error. We return a generic error but this should
3692 // possibly be a panic.
3693 if m.cs == 0 {
3694 m.cs = LineProtocol_en_discard_line
3695 return ErrParse
3696 }
3697
3698 // If we haven't found a metric line yet and we reached the EOF, report it
3699 // now. This happens when the data ends with a comment or whitespace.
3700 //
3701 // Otherwise we have successfully parsed a metric line, so if we are at
3702 // the EOF we will report it the next call.
3703 if !m.beginMetric && m.p == m.pe && m.pe == m.eof {
3704 return EOF
3705 }
3706
3707 return nil
3708 }
3709
3710 // Position returns the current byte offset into the data.
3711 func (m *machine) Position() int {
3712 return m.p
3713 }
3714
3715 // LineOffset returns the byte offset of the current line.
3716 func (m *machine) LineOffset() int {
3717 return m.sol
3718 }
3719
3720 // LineNumber returns the current line number. Lines are counted based on the
3721 // regular expression `\r?\n`.
3722 func (m *machine) LineNumber() int {
3723 return m.lineno
3724 }
3725
3726 // Column returns the current column.
3727 func (m *machine) Column() int {
3728 lineOffset := m.p - m.sol
3729 return lineOffset + 1
3730 }
3731
3732 func (m *machine) text() []byte {
3733 return m.data[m.pb:m.p]
3734 }
3735
3736 type streamMachine struct {
3737 machine *machine
3738 reader io.Reader
3739 }
3740
3741 func NewStreamMachine(r io.Reader, handler Handler) *streamMachine {
3742 m := &streamMachine{
3743 machine: NewMachine(handler),
3744 reader: r,
3745 }
3746
3747 m.machine.SetData(make([]byte, 1024))
3748 m.machine.pe = 0
3749 m.machine.eof = -1
3750 return m
3751 }
3752
3753 func (m *streamMachine) Next() error {
3754 // Check if we are already at EOF, this should only happen if called again
3755 // after already returning EOF.
3756 if m.machine.p == m.machine.pe && m.machine.pe == m.machine.eof {
3757 return EOF
3758 }
3759
3760 copy(m.machine.data, m.machine.data[m.machine.p:])
3761 m.machine.pe = m.machine.pe - m.machine.p
3762 m.machine.sol = m.machine.sol - m.machine.p
3763 m.machine.pb = 0
3764 m.machine.p = 0
3765 m.machine.eof = -1
3766
3767 m.machine.key = nil
3768 m.machine.beginMetric = false
3769 m.machine.finishMetric = false
3770
3771 for {
3772 // Expand the buffer if it is full
3773 if m.machine.pe == len(m.machine.data) {
3774 expanded := make([]byte, 2*len(m.machine.data))
3775 copy(expanded, m.machine.data)
3776 m.machine.data = expanded
3777 }
3778
3779 n, err := m.reader.Read(m.machine.data[m.machine.pe:])
3780 if n == 0 && err == io.EOF {
3781 m.machine.eof = m.machine.pe
3782 } else if err != nil && err != io.EOF {
3783 return err
3784 }
3785
3786 m.machine.pe += n
3787
3788 err = m.machine.exec()
3789 if err != nil {
3790 return err
3791 }
3792
3793 // If we have successfully parsed a full metric line break out
3794 if m.machine.finishMetric {
3795 break
3796 }
3797
3798 }
3799
3800 return nil
3801 }
3802
3803 // Position returns the current byte offset into the data.
3804 func (m *streamMachine) Position() int {
3805 return m.machine.Position()
3806 }
3807
3808 // LineOffset returns the byte offset of the current line.
3809 func (m *streamMachine) LineOffset() int {
3810 return m.machine.LineOffset()
3811 }
3812
3813 // LineNumber returns the current line number. Lines are counted based on the
3814 // regular expression `\r?\n`.
3815 func (m *streamMachine) LineNumber() int {
3816 return m.machine.LineNumber()
3817 }
3818
3819 // Column returns the current column.
3820 func (m *streamMachine) Column() int {
3821 return m.machine.Column()
3822 }
3823
3824 // LineText returns the text of the current line that has been parsed so far.
3825 func (m *streamMachine) LineText() string {
3826 return string(m.machine.data[0:m.machine.p])
3827 }
0 package protocol
1
2 import (
3 "errors"
4 "io"
5 )
6
7 var (
8 ErrNameParse = errors.New("expected measurement name")
9 ErrFieldParse = errors.New("expected field")
10 ErrTagParse = errors.New("expected tag")
11 ErrTimestampParse = errors.New("expected timestamp")
12 ErrParse = errors.New("parse error")
13 EOF = errors.New("EOF")
14 )
15
16 %%{
17 machine LineProtocol;
18
19 action begin {
20 m.pb = m.p
21 }
22
23 action name_error {
24 err = ErrNameParse
25 fhold;
26 fnext discard_line;
27 fbreak;
28 }
29
30 action field_error {
31 err = ErrFieldParse
32 fhold;
33 fnext discard_line;
34 fbreak;
35 }
36
37 action tagset_error {
38 err = ErrTagParse
39 fhold;
40 fnext discard_line;
41 fbreak;
42 }
43
44 action timestamp_error {
45 err = ErrTimestampParse
46 fhold;
47 fnext discard_line;
48 fbreak;
49 }
50
51 action parse_error {
52 err = ErrParse
53 fhold;
54 fnext discard_line;
55 fbreak;
56 }
57
58 action align_error {
59 err = ErrParse
60 fnext discard_line;
61 fbreak;
62 }
63
64 action hold_recover {
65 fhold;
66 fgoto main;
67 }
68
69 action goto_align {
70 fgoto align;
71 }
72
73 action begin_metric {
74 m.beginMetric = true
75 }
76
77 action name {
78 err = m.handler.SetMeasurement(m.text())
79 if err != nil {
80 fhold;
81 fnext discard_line;
82 fbreak;
83 }
84 }
85
86 action tagkey {
87 m.key = m.text()
88 }
89
90 action tagvalue {
91 err = m.handler.AddTag(m.key, m.text())
92 if err != nil {
93 fhold;
94 fnext discard_line;
95 fbreak;
96 }
97 }
98
99 action fieldkey {
100 m.key = m.text()
101 }
102
103 action integer {
104 err = m.handler.AddInt(m.key, m.text())
105 if err != nil {
106 fhold;
107 fnext discard_line;
108 fbreak;
109 }
110 }
111
112 action unsigned {
113 err = m.handler.AddUint(m.key, m.text())
114 if err != nil {
115 fhold;
116 fnext discard_line;
117 fbreak;
118 }
119 }
120
121 action float {
122 err = m.handler.AddFloat(m.key, m.text())
123 if err != nil {
124 fhold;
125 fnext discard_line;
126 fbreak;
127 }
128 }
129
130 action bool {
131 err = m.handler.AddBool(m.key, m.text())
132 if err != nil {
133 fhold;
134 fnext discard_line;
135 fbreak;
136 }
137 }
138
139 action string {
140 err = m.handler.AddString(m.key, m.text())
141 if err != nil {
142 fhold;
143 fnext discard_line;
144 fbreak;
145 }
146 }
147
148 action timestamp {
149 err = m.handler.SetTimestamp(m.text())
150 if err != nil {
151 fhold;
152 fnext discard_line;
153 fbreak;
154 }
155 }
156
157 action incr_newline {
158 m.lineno++
159 m.sol = m.p
160 m.sol++ // next char will be the first column in the line
161 }
162
163 action eol {
164 m.finishMetric = true
165 fnext align;
166 fbreak;
167 }
168
169 action finish_metric {
170 m.finishMetric = true
171 }
172
173 ws =
174 [\t\v\f ];
175
176 newline =
177 '\r'? '\n' >incr_newline;
178
179 non_zero_digit =
180 [1-9];
181
182 integer =
183 '-'? ( digit | ( non_zero_digit digit* ) );
184
185 unsigned =
186 ( digit | ( non_zero_digit digit* ) );
187
188 number =
189 '-'? (digit+ ('.' digit*)? | '.' digit+);
190
191 scientific =
192 number 'e'i ["\-+"]? digit+;
193
194 timestamp =
195 ('-'? digit{1,19}) >begin %timestamp;
196
197 fieldkeychar =
198 [^\t\n\v\f\r ,=\\] | ( '\\' [^\t\n\v\f\r] );
199
200 fieldkey =
201 fieldkeychar+ >begin %fieldkey;
202
203 fieldfloat =
204 (scientific | number) >begin %float;
205
206 fieldinteger =
207 (integer 'i') >begin %integer;
208
209 fieldunsigned =
210 (unsigned 'u') >begin %unsigned;
211
212 false =
213 "false" | "FALSE" | "False" | "F" | "f";
214
215 true =
216 "true" | "TRUE" | "True" | "T" | "t";
217
218 fieldbool =
219 (true | false) >begin %bool;
220
221 fieldstringchar =
222 [^\f\r\n\\"] | '\\' [\\"] | newline;
223
224 fieldstring =
225 fieldstringchar* >begin %string;
226
227 fieldstringquoted =
228 '"' fieldstring '"';
229
230 fieldvalue = fieldinteger | fieldunsigned | fieldfloat | fieldstringquoted | fieldbool;
231
232 field =
233 fieldkey '=' fieldvalue;
234
235 fieldset =
236 field ( ',' field )*;
237
238 tagchar =
239 [^\t\n\v\f\r ,=\\] | ( '\\' [^\t\n\v\f\r\\] ) | '\\\\' %to{ fhold; };
240
241 tagkey =
242 tagchar+ >begin %tagkey;
243
244 tagvalue =
245 tagchar+ >begin %eof(tagvalue) %tagvalue;
246
247 tagset =
248 ((',' tagkey '=' tagvalue) $err(tagset_error))*;
249
250 measurement_chars =
251 [^\t\n\v\f\r ,\\] | ( '\\' [^\t\n\v\f\r] );
252
253 measurement_start =
254 measurement_chars - '#';
255
256 measurement =
257 (measurement_start measurement_chars*) >begin %eof(name) %name;
258
259 eol_break =
260 newline %to(eol)
261 ;
262
263 metric =
264 measurement >err(name_error)
265 tagset
266 ws+ fieldset $err(field_error)
267 (ws+ timestamp)? $err(timestamp_error)
268 ;
269
270 line_with_term =
271 ws* metric ws* eol_break
272 ;
273
274 line_without_term =
275 ws* metric ws*
276 ;
277
278 main :=
279 (line_with_term*
280 (line_with_term | line_without_term?)
281 ) >begin_metric %eof(finish_metric)
282 ;
283
284 # The discard_line machine discards the current line. Useful for recovering
285 # on the next line when an error occurs.
286 discard_line :=
287 (any -- newline)* newline @goto_align;
288
289 commentline =
290 ws* '#' (any -- newline)* newline;
291
292 emptyline =
293 ws* newline;
294
295 # The align machine scans forward to the start of the next line. This machine
296 # is used to skip over whitespace and comments, keeping this logic out of the
297 # main machine.
298 #
299 # Skip valid lines that don't contain line protocol, any other data will move
300 # control to the main parser via the err action.
301 align :=
302 (emptyline | commentline | ws+)* %err(hold_recover);
303
304 # Series is a machine for matching measurement+tagset
305 series :=
306 (measurement >err(name_error) tagset eol_break?)
307 >begin_metric
308 ;
309 }%%
310
311 %% write data;
312
313 type Handler interface {
314 SetMeasurement(name []byte) error
315 AddTag(key []byte, value []byte) error
316 AddInt(key []byte, value []byte) error
317 AddUint(key []byte, value []byte) error
318 AddFloat(key []byte, value []byte) error
319 AddString(key []byte, value []byte) error
320 AddBool(key []byte, value []byte) error
321 SetTimestamp(tm []byte) error
322 }
323
324 type machine struct {
325 data []byte
326 cs int
327 p, pe, eof int
328 pb int
329 lineno int
330 sol int
331 handler Handler
332 initState int
333 key []byte
334 beginMetric bool
335 finishMetric bool
336 }
337
338 func NewMachine(handler Handler) *machine {
339 m := &machine{
340 handler: handler,
341 initState: LineProtocol_en_align,
342 }
343
344 %% access m.;
345 %% variable p m.p;
346 %% variable cs m.cs;
347 %% variable pe m.pe;
348 %% variable eof m.eof;
349 %% variable data m.data;
350 %% write init;
351
352 return m
353 }
354
355 func NewSeriesMachine(handler Handler) *machine {
356 m := &machine{
357 handler: handler,
358 initState: LineProtocol_en_series,
359 }
360
361 %% access m.;
362 %% variable p m.p;
363 %% variable pe m.pe;
364 %% variable eof m.eof;
365 %% variable data m.data;
366 %% write init;
367
368 return m
369 }
370
371 func (m *machine) SetData(data []byte) {
372 m.data = data
373 m.p = 0
374 m.pb = 0
375 m.lineno = 1
376 m.sol = 0
377 m.pe = len(data)
378 m.eof = len(data)
379 m.key = nil
380 m.beginMetric = false
381 m.finishMetric = false
382
383 %% write init;
384 m.cs = m.initState
385 }
386
387 // Next parses the next metric line and returns nil if it was successfully
388 // processed. If the line contains a syntax error an error is returned,
389 // otherwise if the end of file is reached before finding a metric line then
390 // EOF is returned.
391 func (m *machine) Next() error {
392 if m.p == m.pe && m.pe == m.eof {
393 return EOF
394 }
395
396 m.key = nil
397 m.beginMetric = false
398 m.finishMetric = false
399
400 return m.exec()
401 }
402
403 func (m *machine) exec() error {
404 var err error
405 %% write exec;
406
407 if err != nil {
408 return err
409 }
410
411 // This would indicate an error in the machine that was reported with a
412 // more specific error. We return a generic error but this should
413 // possibly be a panic.
414 if m.cs == %%{ write error; }%% {
415 m.cs = LineProtocol_en_discard_line
416 return ErrParse
417 }
418
419 // If we haven't found a metric line yet and we reached the EOF, report it
420 // now. This happens when the data ends with a comment or whitespace.
421 //
422 // Otherwise we have successfully parsed a metric line, so if we are at
423 // the EOF we will report it the next call.
424 if !m.beginMetric && m.p == m.pe && m.pe == m.eof {
425 return EOF
426 }
427
428 return nil
429 }
430
431 // Position returns the current byte offset into the data.
432 func (m *machine) Position() int {
433 return m.p
434 }
435
436 // LineOffset returns the byte offset of the current line.
437 func (m *machine) LineOffset() int {
438 return m.sol
439 }
440
441 // LineNumber returns the current line number. Lines are counted based on the
442 // regular expression `\r?\n`.
443 func (m *machine) LineNumber() int {
444 return m.lineno
445 }
446
447 // Column returns the current column.
448 func (m *machine) Column() int {
449 lineOffset := m.p - m.sol
450 return lineOffset + 1
451 }
452
453 func (m *machine) text() []byte {
454 return m.data[m.pb:m.p]
455 }
456
457 type streamMachine struct {
458 machine *machine
459 reader io.Reader
460 }
461
462 func NewStreamMachine(r io.Reader, handler Handler) *streamMachine {
463 m := &streamMachine{
464 machine: NewMachine(handler),
465 reader: r,
466 }
467
468 m.machine.SetData(make([]byte, 1024))
469 m.machine.pe = 0
470 m.machine.eof = -1
471 return m
472 }
473
474 func (m *streamMachine) Next() error {
475 // Check if we are already at EOF, this should only happen if called again
476 // after already returning EOF.
477 if m.machine.p == m.machine.pe && m.machine.pe == m.machine.eof {
478 return EOF
479 }
480
481 copy(m.machine.data, m.machine.data[m.machine.p:])
482 m.machine.pe = m.machine.pe - m.machine.p
483 m.machine.sol = m.machine.sol - m.machine.p
484 m.machine.pb = 0
485 m.machine.p = 0
486 m.machine.eof = -1
487
488 m.machine.key = nil
489 m.machine.beginMetric = false
490 m.machine.finishMetric = false
491
492 for {
493 // Expand the buffer if it is full
494 if m.machine.pe == len(m.machine.data) {
495 expanded := make([]byte, 2 * len(m.machine.data))
496 copy(expanded, m.machine.data)
497 m.machine.data = expanded
498 }
499
500 n, err := m.reader.Read(m.machine.data[m.machine.pe:])
501 if n == 0 && err == io.EOF {
502 m.machine.eof = m.machine.pe
503 } else if err != nil && err != io.EOF {
504 return err
505 }
506
507 m.machine.pe += n
508
509 err = m.machine.exec()
510 if err != nil {
511 return err
512 }
513
514 // If we have successfully parsed a full metric line break out
515 if m.machine.finishMetric {
516 break
517 }
518
519 }
520
521 return nil
522 }
523
524 // Position returns the current byte offset into the data.
525 func (m *streamMachine) Position() int {
526 return m.machine.Position()
527 }
528
529 // LineOffset returns the byte offset of the current line.
530 func (m *streamMachine) LineOffset() int {
531 return m.machine.LineOffset()
532 }
533
534 // LineNumber returns the current line number. Lines are counted based on the
535 // regular expression `\r?\n`.
536 func (m *streamMachine) LineNumber() int {
537 return m.machine.LineNumber()
538 }
539
540 // Column returns the current column.
541 func (m *streamMachine) Column() int {
542 return m.machine.Column()
543 }
544
545 // LineText returns the text of the current line that has been parsed so far.
546 func (m *streamMachine) LineText() string {
547 return string(m.machine.data[0:m.machine.p])
548 }
0 package protocol_test
1
2 import (
3 "bytes"
4 "errors"
5 "fmt"
6 "io"
7 "testing"
8
9 protocol "github.com/influxdata/line-protocol"
10 )
11
12 type TestingHandler struct {
13 results []Result
14 }
15
16 func (h *TestingHandler) SetMeasurement(name []byte) error {
17 n := make([]byte, len(name))
18 copy(n, name)
19
20 mname := Result{
21 Name: Measurement,
22 Value: n,
23 }
24 h.results = append(h.results, mname)
25 return nil
26 }
27
28 func (h *TestingHandler) AddTag(key []byte, value []byte) error {
29 k := make([]byte, len(key))
30 copy(k, key)
31 v := make([]byte, len(value))
32 copy(v, value)
33
34 tagkey := Result{
35 Name: TagKey,
36 Value: k,
37 }
38 tagvalue := Result{
39 Name: TagValue,
40 Value: v,
41 }
42 h.results = append(h.results, tagkey, tagvalue)
43 return nil
44 }
45
46 func (h *TestingHandler) AddInt(key []byte, value []byte) error {
47 k := make([]byte, len(key))
48 copy(k, key)
49 v := make([]byte, len(value))
50 copy(v, value)
51
52 fieldkey := Result{
53 Name: FieldKey,
54 Value: k,
55 }
56 fieldvalue := Result{
57 Name: FieldInt,
58 Value: v,
59 }
60 h.results = append(h.results, fieldkey, fieldvalue)
61 return nil
62 }
63
64 func (h *TestingHandler) AddUint(key []byte, value []byte) error {
65 k := make([]byte, len(key))
66 copy(k, key)
67 v := make([]byte, len(value))
68 copy(v, value)
69
70 fieldkey := Result{
71 Name: FieldKey,
72 Value: key,
73 }
74 fieldvalue := Result{
75 Name: FieldUint,
76 Value: value,
77 }
78 h.results = append(h.results, fieldkey, fieldvalue)
79 return nil
80 }
81
82 func (h *TestingHandler) AddFloat(key []byte, value []byte) error {
83 k := make([]byte, len(key))
84 copy(k, key)
85 v := make([]byte, len(value))
86 copy(v, value)
87
88 fieldkey := Result{
89 Name: FieldKey,
90 Value: k,
91 }
92 fieldvalue := Result{
93 Name: FieldFloat,
94 Value: v,
95 }
96 h.results = append(h.results, fieldkey, fieldvalue)
97 return nil
98 }
99
100 func (h *TestingHandler) AddString(key []byte, value []byte) error {
101 k := make([]byte, len(key))
102 copy(k, key)
103 v := make([]byte, len(value))
104 copy(v, value)
105
106 fieldkey := Result{
107 Name: FieldKey,
108 Value: k,
109 }
110 fieldvalue := Result{
111 Name: FieldString,
112 Value: v,
113 }
114 h.results = append(h.results, fieldkey, fieldvalue)
115 return nil
116 }
117
118 func (h *TestingHandler) AddBool(key []byte, value []byte) error {
119 k := make([]byte, len(key))
120 copy(k, key)
121 v := make([]byte, len(value))
122 copy(v, value)
123
124 fieldkey := Result{
125 Name: FieldKey,
126 Value: k,
127 }
128 fieldvalue := Result{
129 Name: FieldBool,
130 Value: v,
131 }
132 h.results = append(h.results, fieldkey, fieldvalue)
133 return nil
134 }
135
136 func (h *TestingHandler) SetTimestamp(tm []byte) error {
137 t := make([]byte, len(tm))
138 copy(t, tm)
139
140 timestamp := Result{
141 Name: Timestamp,
142 Value: t,
143 }
144 h.results = append(h.results, timestamp)
145 return nil
146 }
147
148 func (h *TestingHandler) Result(err error) {
149 var res Result
150 if err == nil {
151 res = Result{
152 Name: Success,
153 }
154 } else {
155 res = Result{
156 Name: Error,
157 err: err,
158 }
159 }
160 h.results = append(h.results, res)
161 }
162
163 func (h *TestingHandler) Results() []Result {
164 return h.results
165 }
166
167 type BenchmarkingHandler struct {
168 }
169
170 func (h *BenchmarkingHandler) SetMeasurement(name []byte) error {
171 return nil
172 }
173
174 func (h *BenchmarkingHandler) AddTag(key []byte, value []byte) error {
175 return nil
176 }
177
178 func (h *BenchmarkingHandler) AddInt(key []byte, value []byte) error {
179 return nil
180 }
181
182 func (h *BenchmarkingHandler) AddUint(key []byte, value []byte) error {
183 return nil
184 }
185
186 func (h *BenchmarkingHandler) AddFloat(key []byte, value []byte) error {
187 return nil
188 }
189
190 func (h *BenchmarkingHandler) AddString(key []byte, value []byte) error {
191 return nil
192 }
193
194 func (h *BenchmarkingHandler) AddBool(key []byte, value []byte) error {
195 return nil
196 }
197
198 func (h *BenchmarkingHandler) SetTimestamp(tm []byte) error {
199 return nil
200 }
201
202 type TokenType int
203
204 const (
205 NoMatch TokenType = iota
206 Measurement
207 TagKey
208 TagValue
209 FieldKey
210 FieldString
211 FieldInt
212 FieldUint
213 FieldFloat
214 FieldBool
215 Timestamp
216 EOL
217 EOF
218 Punc
219 WhiteSpace
220 Success
221 Error
222 )
223
224 func (t TokenType) String() string {
225 switch t {
226 case NoMatch:
227 return "NoMatch"
228 case Measurement:
229 return "Measurement"
230 case TagKey:
231 return "TagKey"
232 case TagValue:
233 return "TagValue"
234 case FieldKey:
235 return "FieldKey"
236 case FieldInt:
237 return "FieldInt"
238 case FieldUint:
239 return "FieldUint"
240 case FieldFloat:
241 return "FieldFloat"
242 case FieldString:
243 return "FieldString"
244 case FieldBool:
245 return "FieldBool"
246 case Timestamp:
247 return "Timestamp"
248 case EOL:
249 return "EOL"
250 case EOF:
251 return "EOF"
252 case Punc:
253 return "Punc"
254 case WhiteSpace:
255 return "WhiteSpace"
256 case Success:
257 return "Success"
258 case Error:
259 return "Error"
260 default:
261 panic("Unknown TokenType")
262 }
263 }
264
265 type Result struct {
266 Name TokenType
267 Value []byte
268 err error
269 }
270
271 func (r Result) String() string {
272 return fmt.Sprintf("(%s, %q, %v)", r.Name, r.Value, r.err)
273 }
274
275 var tests = []struct {
276 name string
277 input []byte
278 results []Result
279 err error
280 }{
281 {
282 name: "empty string",
283 input: []byte(""),
284 results: nil,
285 },
286 {
287 name: "minimal",
288 input: []byte("cpu value=42"),
289 results: []Result{
290 {
291 Name: Measurement,
292 Value: []byte("cpu"),
293 },
294 {
295 Name: FieldKey,
296 Value: []byte("value"),
297 },
298 {
299 Name: FieldFloat,
300 Value: []byte("42"),
301 },
302 {
303 Name: Success,
304 },
305 },
306 },
307 {
308 name: "newline",
309 input: []byte("cpu value=42\n"),
310 results: []Result{
311 {
312 Name: Measurement,
313 Value: []byte("cpu"),
314 },
315 {
316 Name: FieldKey,
317 Value: []byte("value"),
318 },
319 {
320 Name: FieldFloat,
321 Value: []byte("42"),
322 },
323 {
324 Name: Success,
325 },
326 },
327 },
328 {
329 name: "minimal with timestamp",
330 input: []byte("cpu value=42 1516241192000000000"),
331 results: []Result{
332 {
333 Name: Measurement,
334 Value: []byte("cpu"),
335 },
336 {
337 Name: FieldKey,
338 Value: []byte("value"),
339 },
340 {
341 Name: FieldFloat,
342 Value: []byte("42"),
343 },
344 {
345 Name: Timestamp,
346 Value: []byte("1516241192000000000"),
347 },
348 {
349 Name: Success,
350 },
351 },
352 },
353 {
354 name: "measurement escape non-special",
355 input: []byte(`c\pu value=42`),
356 results: []Result{
357 {
358 Name: Measurement,
359 Value: []byte(`c\pu`),
360 },
361 {
362 Name: FieldKey,
363 Value: []byte("value"),
364 },
365 {
366 Name: FieldFloat,
367 Value: []byte("42"),
368 },
369 {
370 Name: Success,
371 },
372 },
373 },
374 {
375 name: "measurement escaped trailing backslash",
376 input: []byte(`cpu\\ value=42`),
377 results: []Result{
378 {
379 Name: Measurement,
380 Value: []byte(`cpu\\`),
381 },
382 {
383 Name: FieldKey,
384 Value: []byte("value"),
385 },
386 {
387 Name: FieldFloat,
388 Value: []byte("42"),
389 },
390 {
391 Name: Success,
392 },
393 },
394 },
395 {
396 name: "single char measurement",
397 input: []byte("c value=42"),
398 results: []Result{
399 {
400 Name: Measurement,
401 Value: []byte("c"),
402 },
403 {
404 Name: FieldKey,
405 Value: []byte("value"),
406 },
407 {
408 Name: FieldFloat,
409 Value: []byte("42"),
410 },
411 {
412 Name: Success,
413 },
414 },
415 },
416 {
417 name: "escape backslash in measurement",
418 input: []byte(`cp\\u value=42`),
419 results: []Result{
420 {
421 Name: Measurement,
422 Value: []byte(`cp\\u`),
423 },
424 {
425 Name: FieldKey,
426 Value: []byte("value"),
427 },
428 {
429 Name: FieldFloat,
430 Value: []byte("42"),
431 },
432 {
433 Name: Success,
434 },
435 },
436 },
437 {
438 name: "measurement escape space",
439 input: []byte(`cpu\ abc value=42`),
440 results: []Result{
441 {
442 Name: Measurement,
443 Value: []byte(`cpu\ abc`),
444 },
445 {
446 Name: FieldKey,
447 Value: []byte("value"),
448 },
449 {
450 Name: FieldFloat,
451 Value: []byte("42"),
452 },
453 {
454 Name: Success,
455 },
456 },
457 },
458 {
459 name: "scientific float",
460 input: []byte("cpu value=42e0"),
461 results: []Result{
462 {
463 Name: Measurement,
464 Value: []byte("cpu"),
465 },
466 {
467 Name: FieldKey,
468 Value: []byte("value"),
469 },
470 {
471 Name: FieldFloat,
472 Value: []byte("42e0"),
473 },
474 {
475 Name: Success,
476 },
477 },
478 },
479 {
480 name: "scientific float negative mantissa",
481 input: []byte("cpu value=-42e0"),
482 results: []Result{
483 {
484 Name: Measurement,
485 Value: []byte("cpu"),
486 },
487 {
488 Name: FieldKey,
489 Value: []byte("value"),
490 },
491 {
492 Name: FieldFloat,
493 Value: []byte("-42e0"),
494 },
495 {
496 Name: Success,
497 },
498 },
499 },
500 {
501 name: "scientific float negative exponent",
502 input: []byte("cpu value=42e-1"),
503 results: []Result{
504 {
505 Name: Measurement,
506 Value: []byte("cpu"),
507 },
508 {
509 Name: FieldKey,
510 Value: []byte("value"),
511 },
512 {
513 Name: FieldFloat,
514 Value: []byte("42e-1"),
515 },
516 {
517 Name: Success,
518 },
519 },
520 },
521 {
522 name: "scientific float big e",
523 input: []byte("cpu value=42E0"),
524 results: []Result{
525 {
526 Name: Measurement,
527 Value: []byte("cpu"),
528 },
529 {
530 Name: FieldKey,
531 Value: []byte("value"),
532 },
533 {
534 Name: FieldFloat,
535 Value: []byte("42E0"),
536 },
537 {
538 Name: Success,
539 },
540 },
541 },
542 {
543 name: "scientific float missing exponent",
544 input: []byte("cpu value=42E"),
545 results: []Result{
546 {
547 Name: Measurement,
548 Value: []byte("cpu"),
549 },
550 {
551 Name: Error,
552 err: protocol.ErrFieldParse,
553 },
554 },
555 },
556 {
557 name: "float with decimal",
558 input: []byte("cpu value=42.2"),
559 results: []Result{
560 {
561 Name: Measurement,
562 Value: []byte("cpu"),
563 },
564 {
565 Name: FieldKey,
566 Value: []byte("value"),
567 },
568 {
569 Name: FieldFloat,
570 Value: []byte("42.2"),
571 },
572 {
573 Name: Success,
574 },
575 },
576 },
577 {
578 name: "negative float",
579 input: []byte("cpu value=-42"),
580 results: []Result{
581 {
582 Name: Measurement,
583 Value: []byte("cpu"),
584 },
585 {
586 Name: FieldKey,
587 Value: []byte("value"),
588 },
589 {
590 Name: FieldFloat,
591 Value: []byte("-42"),
592 },
593 {
594 Name: Success,
595 },
596 },
597 },
598 {
599 name: "float without integer digits",
600 input: []byte("cpu value=.42"),
601 results: []Result{
602 {
603 Name: Measurement,
604 Value: []byte("cpu"),
605 },
606 {
607 Name: FieldKey,
608 Value: []byte("value"),
609 },
610 {
611 Name: FieldFloat,
612 Value: []byte(".42"),
613 },
614 {
615 Name: Success,
616 },
617 },
618 },
619 {
620 name: "float without integer digits negative",
621 input: []byte("cpu value=-.42"),
622 results: []Result{
623 {
624 Name: Measurement,
625 Value: []byte("cpu"),
626 },
627 {
628 Name: FieldKey,
629 Value: []byte("value"),
630 },
631 {
632 Name: FieldFloat,
633 Value: []byte("-.42"),
634 },
635 {
636 Name: Success,
637 },
638 },
639 },
640 {
641 name: "float with multiple leading 0",
642 input: []byte("cpu value=00.42"),
643 results: []Result{
644 {
645 Name: Measurement,
646 Value: []byte("cpu"),
647 },
648 {
649 Name: FieldKey,
650 Value: []byte("value"),
651 },
652 {
653 Name: FieldFloat,
654 Value: []byte("00.42"),
655 },
656 {
657 Name: Success,
658 },
659 },
660 },
661 {
662 name: "invalid float with only dot",
663 input: []byte("cpu value=."),
664 results: []Result{
665 {
666 Name: Measurement,
667 Value: []byte("cpu"),
668 },
669 {
670 Name: Error,
671 err: protocol.ErrFieldParse,
672 },
673 },
674 },
675 {
676 name: "multiple fields",
677 input: []byte("cpu x=42,y=42"),
678 results: []Result{
679 {
680 Name: Measurement,
681 Value: []byte("cpu"),
682 },
683 {
684 Name: FieldKey,
685 Value: []byte("x"),
686 },
687 {
688 Name: FieldFloat,
689 Value: []byte("42"),
690 },
691 {
692 Name: FieldKey,
693 Value: []byte("y"),
694 },
695 {
696 Name: FieldFloat,
697 Value: []byte("42"),
698 },
699 {
700 Name: Success,
701 },
702 },
703 },
704 {
705 name: "integer field",
706 input: []byte("cpu value=42i"),
707 results: []Result{
708 {
709 Name: Measurement,
710 Value: []byte("cpu"),
711 },
712 {
713 Name: FieldKey,
714 Value: []byte("value"),
715 },
716 {
717 Name: FieldInt,
718 Value: []byte("42i"),
719 },
720 {
721 Name: Success,
722 },
723 },
724 },
725 {
726 name: "negative integer field",
727 input: []byte("cpu value=-42i"),
728 results: []Result{
729 {
730 Name: Measurement,
731 Value: []byte("cpu"),
732 },
733 {
734 Name: FieldKey,
735 Value: []byte("value"),
736 },
737 {
738 Name: FieldInt,
739 Value: []byte("-42i"),
740 },
741 {
742 Name: Success,
743 },
744 },
745 },
746 {
747 name: "zero integer field",
748 input: []byte("cpu value=0i"),
749 results: []Result{
750 {
751 Name: Measurement,
752 Value: []byte("cpu"),
753 },
754 {
755 Name: FieldKey,
756 Value: []byte("value"),
757 },
758 {
759 Name: FieldInt,
760 Value: []byte("0i"),
761 },
762 {
763 Name: Success,
764 },
765 },
766 },
767 {
768 name: "negative zero integer field",
769 input: []byte("cpu value=-0i"),
770 results: []Result{
771 {
772 Name: Measurement,
773 Value: []byte("cpu"),
774 },
775 {
776 Name: FieldKey,
777 Value: []byte("value"),
778 },
779 {
780 Name: FieldInt,
781 Value: []byte("-0i"),
782 },
783 {
784 Name: Success,
785 },
786 },
787 },
788 {
789 name: "integer field overflow okay",
790 input: []byte("cpu value=9223372036854775808i"),
791 results: []Result{
792 {
793 Name: Measurement,
794 Value: []byte("cpu"),
795 },
796 {
797 Name: FieldKey,
798 Value: []byte("value"),
799 },
800 {
801 Name: FieldInt,
802 Value: []byte("9223372036854775808i"),
803 },
804 {
805 Name: Success,
806 },
807 },
808 },
809 {
810 name: "invalid field",
811 input: []byte("cpu value=howdy"),
812 results: []Result{
813 {
814 Name: Measurement,
815 Value: []byte("cpu"),
816 },
817 {
818 Name: Error,
819 err: protocol.ErrFieldParse,
820 },
821 },
822 },
823 {
824 name: "string field",
825 input: []byte("cpu value=\"42\""),
826 results: []Result{
827 {
828 Name: Measurement,
829 Value: []byte("cpu"),
830 },
831 {
832 Name: FieldKey,
833 Value: []byte("value"),
834 },
835 {
836 Name: FieldString,
837 Value: []byte("42"),
838 },
839 {
840 Name: Success,
841 },
842 },
843 },
844 {
845 name: "newline in string field",
846 input: []byte("cpu value=\"4\n2\""),
847 results: []Result{
848 {
849 Name: Measurement,
850 Value: []byte("cpu"),
851 },
852 {
853 Name: FieldKey,
854 Value: []byte("value"),
855 },
856 {
857 Name: FieldString,
858 Value: []byte("4\n2"),
859 },
860 {
861 Name: Success,
862 },
863 },
864 },
865 {
866 name: "bool field",
867 input: []byte("cpu value=true"),
868 results: []Result{
869 {
870 Name: Measurement,
871 Value: []byte("cpu"),
872 },
873 {
874 Name: FieldKey,
875 Value: []byte("value"),
876 },
877 {
878 Name: FieldBool,
879 Value: []byte("true"),
880 },
881 {
882 Name: Success,
883 },
884 },
885 },
886 {
887 name: "tag",
888 input: []byte("cpu,host=localhost value=42"),
889 results: []Result{
890 {
891 Name: Measurement,
892 Value: []byte("cpu"),
893 },
894 {
895 Name: TagKey,
896 Value: []byte("host"),
897 },
898 {
899 Name: TagValue,
900 Value: []byte("localhost"),
901 },
902 {
903 Name: FieldKey,
904 Value: []byte("value"),
905 },
906 {
907 Name: FieldFloat,
908 Value: []byte("42"),
909 },
910 {
911 Name: Success,
912 },
913 },
914 },
915 {
916 name: "tag key escape space",
917 input: []byte("cpu,h\\ ost=localhost value=42"),
918 results: []Result{
919 {
920 Name: Measurement,
921 Value: []byte("cpu"),
922 },
923 {
924 Name: TagKey,
925 Value: []byte(`h\ ost`),
926 },
927 {
928 Name: TagValue,
929 Value: []byte("localhost"),
930 },
931 {
932 Name: FieldKey,
933 Value: []byte("value"),
934 },
935 {
936 Name: FieldFloat,
937 Value: []byte("42"),
938 },
939 {
940 Name: Success,
941 },
942 },
943 },
944 {
945 name: "tag key escape comma",
946 input: []byte("cpu,h\\,ost=localhost value=42"),
947 results: []Result{
948 {
949 Name: Measurement,
950 Value: []byte("cpu"),
951 },
952 {
953 Name: TagKey,
954 Value: []byte(`h\,ost`),
955 },
956 {
957 Name: TagValue,
958 Value: []byte("localhost"),
959 },
960 {
961 Name: FieldKey,
962 Value: []byte("value"),
963 },
964 {
965 Name: FieldFloat,
966 Value: []byte("42"),
967 },
968 {
969 Name: Success,
970 },
971 },
972 },
973 {
974 name: "tag key escape equal",
975 input: []byte("cpu,h\\=ost=localhost value=42"),
976 results: []Result{
977 {
978 Name: Measurement,
979 Value: []byte("cpu"),
980 },
981 {
982 Name: TagKey,
983 Value: []byte(`h\=ost`),
984 },
985 {
986 Name: TagValue,
987 Value: []byte("localhost"),
988 },
989 {
990 Name: FieldKey,
991 Value: []byte("value"),
992 },
993 {
994 Name: FieldFloat,
995 Value: []byte("42"),
996 },
997 {
998 Name: Success,
999 },
1000 },
1001 },
1002 {
1003 name: "multiple tags",
1004 input: []byte("cpu,host=localhost,cpu=cpu0 value=42"),
1005 results: []Result{
1006 {
1007 Name: Measurement,
1008 Value: []byte("cpu"),
1009 },
1010 {
1011 Name: TagKey,
1012 Value: []byte("host"),
1013 },
1014 {
1015 Name: TagValue,
1016 Value: []byte("localhost"),
1017 },
1018 {
1019 Name: TagKey,
1020 Value: []byte("cpu"),
1021 },
1022 {
1023 Name: TagValue,
1024 Value: []byte("cpu0"),
1025 },
1026 {
1027 Name: FieldKey,
1028 Value: []byte("value"),
1029 },
1030 {
1031 Name: FieldFloat,
1032 Value: []byte("42"),
1033 },
1034 {
1035 Name: Success,
1036 },
1037 },
1038 },
1039 {
1040 name: "tag value escape space",
1041 input: []byte(`cpu,host=two\ words value=42`),
1042 results: []Result{
1043 {
1044 Name: Measurement,
1045 Value: []byte("cpu"),
1046 },
1047 {
1048 Name: TagKey,
1049 Value: []byte("host"),
1050 },
1051 {
1052 Name: TagValue,
1053 Value: []byte(`two\ words`),
1054 },
1055 {
1056 Name: FieldKey,
1057 Value: []byte("value"),
1058 },
1059 {
1060 Name: FieldFloat,
1061 Value: []byte("42"),
1062 },
1063 {
1064 Name: Success,
1065 },
1066 },
1067 },
1068 {
1069 name: "tag value double escape space",
1070 input: []byte(`cpu,host=two\\ words value=42`),
1071 results: []Result{
1072 {
1073 Name: Measurement,
1074 Value: []byte("cpu"),
1075 },
1076 {
1077 Name: TagKey,
1078 Value: []byte("host"),
1079 },
1080 {
1081 Name: TagValue,
1082 Value: []byte(`two\\ words`),
1083 },
1084 {
1085 Name: FieldKey,
1086 Value: []byte("value"),
1087 },
1088 {
1089 Name: FieldFloat,
1090 Value: []byte("42"),
1091 },
1092 {
1093 Name: Success,
1094 },
1095 },
1096 },
1097 {
1098 name: "tag value triple escape space",
1099 input: []byte(`cpu,host=two\\\ words value=42`),
1100 results: []Result{
1101 {
1102 Name: Measurement,
1103 Value: []byte("cpu"),
1104 },
1105 {
1106 Name: TagKey,
1107 Value: []byte("host"),
1108 },
1109 {
1110 Name: TagValue,
1111 Value: []byte(`two\\\ words`),
1112 },
1113 {
1114 Name: FieldKey,
1115 Value: []byte("value"),
1116 },
1117 {
1118 Name: FieldFloat,
1119 Value: []byte("42"),
1120 },
1121 {
1122 Name: Success,
1123 },
1124 },
1125 },
1126 {
1127 name: "tag invalid missing separator",
1128 input: []byte("cpu,xyzzy value=42"),
1129 results: []Result{
1130 {
1131 Name: Measurement,
1132 Value: []byte("cpu"),
1133 },
1134 {
1135 Name: Error,
1136 err: protocol.ErrTagParse,
1137 },
1138 },
1139 },
1140 {
1141 name: "tag invalid missing value",
1142 input: []byte("cpu,xyzzy= value=42"),
1143 results: []Result{
1144 {
1145 Name: Measurement,
1146 Value: []byte("cpu"),
1147 },
1148 {
1149 Name: Error,
1150 err: protocol.ErrTagParse,
1151 },
1152 },
1153 },
1154 {
1155 name: "tag invalid unescaped space",
1156 input: []byte("cpu,h ost=localhost value=42"),
1157 results: []Result{
1158 {
1159 Name: Measurement,
1160 Value: []byte("cpu"),
1161 },
1162 {
1163 Name: Error,
1164 err: protocol.ErrTagParse,
1165 },
1166 },
1167 },
1168 {
1169 name: "tag invalid unescaped comma",
1170 input: []byte("cpu,h,ost=localhost value=42"),
1171 results: []Result{
1172 {
1173 Name: Measurement,
1174 Value: []byte("cpu"),
1175 },
1176 {
1177 Name: Error,
1178 err: protocol.ErrTagParse,
1179 },
1180 },
1181 },
1182 {
1183 name: "tag invalid unescaped equals",
1184 input: []byte("cpu,h=ost=localhost value=42"),
1185 results: []Result{
1186 {
1187 Name: Measurement,
1188 Value: []byte("cpu"),
1189 },
1190 {
1191 Name: Error,
1192 err: protocol.ErrTagParse,
1193 },
1194 },
1195 },
1196 {
1197 name: "timestamp negative",
1198 input: []byte("cpu value=42 -1"),
1199 results: []Result{
1200 {
1201 Name: Measurement,
1202 Value: []byte("cpu"),
1203 },
1204 {
1205 Name: FieldKey,
1206 Value: []byte("value"),
1207 },
1208 {
1209 Name: FieldFloat,
1210 Value: []byte("42"),
1211 },
1212 {
1213 Name: Timestamp,
1214 Value: []byte("-1"),
1215 },
1216 {
1217 Name: Success,
1218 },
1219 },
1220 },
1221 {
1222 name: "timestamp zero",
1223 input: []byte("cpu value=42 0"),
1224 results: []Result{
1225 {
1226 Name: Measurement,
1227 Value: []byte("cpu"),
1228 },
1229 {
1230 Name: FieldKey,
1231 Value: []byte("value"),
1232 },
1233 {
1234 Name: FieldFloat,
1235 Value: []byte("42"),
1236 },
1237 {
1238 Name: Timestamp,
1239 Value: []byte("0"),
1240 },
1241 {
1242 Name: Success,
1243 },
1244 },
1245 },
1246 {
1247 name: "multiline",
1248 input: []byte("cpu value=42\n\n\n\ncpu value=43"),
1249 results: []Result{
1250 {
1251 Name: Measurement,
1252 Value: []byte("cpu"),
1253 },
1254 {
1255 Name: FieldKey,
1256 Value: []byte("value"),
1257 },
1258 {
1259 Name: FieldFloat,
1260 Value: []byte("42"),
1261 },
1262 {
1263 Name: Success,
1264 },
1265 {
1266 Name: Measurement,
1267 Value: []byte("cpu"),
1268 },
1269 {
1270 Name: FieldKey,
1271 Value: []byte("value"),
1272 },
1273 {
1274 Name: FieldFloat,
1275 Value: []byte("43"),
1276 },
1277 {
1278 Name: Success,
1279 },
1280 },
1281 },
1282 {
1283 name: "error recovery",
1284 input: []byte("cpu value=howdy,value2=42\ncpu\ncpu value=42"),
1285 results: []Result{
1286 {
1287 Name: Measurement,
1288 Value: []byte("cpu"),
1289 },
1290 {
1291 Name: Error,
1292 err: protocol.ErrFieldParse,
1293 },
1294 {
1295 Name: Error,
1296 err: protocol.ErrTagParse,
1297 },
1298 {
1299 Name: Measurement,
1300 Value: []byte("cpu"),
1301 },
1302 {
1303 Name: FieldKey,
1304 Value: []byte("value"),
1305 },
1306 {
1307 Name: FieldFloat,
1308 Value: []byte("42"),
1309 },
1310 {
1311 Name: Success,
1312 },
1313 },
1314 },
1315 {
1316 name: "line whitespace",
1317 input: []byte(" cpu value=42 1516241192000000000 \n\n cpu value=42"),
1318 results: []Result{
1319 {
1320 Name: Measurement,
1321 Value: []byte("cpu"),
1322 },
1323 {
1324 Name: FieldKey,
1325 Value: []byte("value"),
1326 },
1327 {
1328 Name: FieldFloat,
1329 Value: []byte("42"),
1330 },
1331 {
1332 Name: Timestamp,
1333 Value: []byte("1516241192000000000"),
1334 },
1335 {
1336 Name: Success,
1337 },
1338 {
1339 Name: Measurement,
1340 Value: []byte("cpu"),
1341 },
1342 {
1343 Name: FieldKey,
1344 Value: []byte("value"),
1345 },
1346 {
1347 Name: FieldFloat,
1348 Value: []byte("42"),
1349 },
1350 {
1351 Name: Success,
1352 },
1353 },
1354 },
1355 {
1356 name: "leading newline",
1357 input: []byte("\ncpu value=42"),
1358 results: []Result{
1359 {
1360 Name: Measurement,
1361 Value: []byte("cpu"),
1362 },
1363 {
1364 Name: FieldKey,
1365 Value: []byte("value"),
1366 },
1367 {
1368 Name: FieldFloat,
1369 Value: []byte("42"),
1370 },
1371 {
1372 Name: Success,
1373 },
1374 },
1375 },
1376 {
1377 name: "invalid missing field value",
1378 input: []byte("cpu value="),
1379 results: []Result{
1380 {
1381 Name: Measurement,
1382 Value: []byte("cpu"),
1383 },
1384 {
1385 Name: Error,
1386 err: protocol.ErrFieldParse,
1387 },
1388 },
1389 },
1390 {
1391 name: "invalid eof field key",
1392 input: []byte("cpu value"),
1393 results: []Result{
1394 {
1395 Name: Measurement,
1396 Value: []byte("cpu"),
1397 },
1398 {
1399 Name: Error,
1400 err: protocol.ErrFieldParse,
1401 },
1402 },
1403 },
1404 {
1405 name: "invalid measurement only",
1406 input: []byte("cpu"),
1407 results: []Result{
1408 {
1409 Name: Measurement,
1410 Value: []byte("cpu"),
1411 },
1412 {
1413 Name: Error,
1414 err: protocol.ErrTagParse,
1415 },
1416 },
1417 },
1418 {
1419 name: "invalid measurement char",
1420 input: []byte(","),
1421 results: []Result{
1422 {
1423 Name: Error,
1424 err: protocol.ErrNameParse,
1425 },
1426 },
1427 },
1428 {
1429 name: "invalid missing tag",
1430 input: []byte("cpu, value=42"),
1431 results: []Result{
1432 {
1433 Name: Measurement,
1434 Value: []byte("cpu"),
1435 },
1436 {
1437 Name: Error,
1438 err: protocol.ErrTagParse,
1439 },
1440 },
1441 },
1442 {
1443 name: "invalid missing field",
1444 input: []byte("cpu,x=y "),
1445 results: []Result{
1446 {
1447 Name: Measurement,
1448 Value: []byte("cpu"),
1449 },
1450 {
1451 Name: TagKey,
1452 Value: []byte("x"),
1453 },
1454 {
1455 Name: TagValue,
1456 Value: []byte("y"),
1457 },
1458 {
1459 Name: Error,
1460 err: protocol.ErrFieldParse,
1461 },
1462 },
1463 },
1464 {
1465 name: "invalid too many fields",
1466 input: []byte("cpu value=42 value=43"),
1467 results: []Result{
1468 {
1469 Name: Measurement,
1470 Value: []byte("cpu"),
1471 },
1472 {
1473 Name: FieldKey,
1474 Value: []byte("value"),
1475 },
1476 {
1477 Name: FieldFloat,
1478 Value: []byte("42"),
1479 },
1480 {
1481 Name: Error,
1482 err: protocol.ErrTimestampParse,
1483 },
1484 },
1485 },
1486 {
1487 name: "invalid timestamp too long",
1488 input: []byte("cpu value=42 12345678901234567890"),
1489 results: []Result{
1490 {
1491 Name: Measurement,
1492 Value: []byte("cpu"),
1493 },
1494 {
1495 Name: FieldKey,
1496 Value: []byte("value"),
1497 },
1498 {
1499 Name: FieldFloat,
1500 Value: []byte("42"),
1501 },
1502 {
1503 Name: Error,
1504 err: protocol.ErrTimestampParse,
1505 },
1506 },
1507 },
1508 {
1509 name: "invalid open string field",
1510 input: []byte(`cpu value="42 12345678901234567890`),
1511 results: []Result{
1512 {
1513 Name: Measurement,
1514 Value: []byte("cpu"),
1515 },
1516 {
1517 Name: Error,
1518 err: protocol.ErrFieldParse,
1519 },
1520 },
1521 },
1522 {
1523 name: "invalid field value",
1524 input: []byte("cpu value=howdy"),
1525 results: []Result{
1526 {
1527 Name: Measurement,
1528 Value: []byte("cpu"),
1529 },
1530 {
1531 Name: Error,
1532 err: protocol.ErrFieldParse,
1533 },
1534 },
1535 },
1536 {
1537 name: "invalid quoted timestamp",
1538 input: []byte("cpu value=42 \"12345678901234567890\""),
1539 results: []Result{
1540 {
1541 Name: Measurement,
1542 Value: []byte("cpu"),
1543 },
1544 {
1545 Name: FieldKey,
1546 Value: []byte("value"),
1547 },
1548 {
1549 Name: FieldFloat,
1550 Value: []byte("42"),
1551 },
1552 {
1553 Name: Error,
1554 err: protocol.ErrTimestampParse,
1555 },
1556 },
1557 },
1558 {
1559 name: "comment only",
1560 input: []byte("# blah blah"),
1561 results: []Result(nil),
1562 },
1563 {
1564 name: "commented line",
1565 input: []byte("# blah blah\ncpu value=42"),
1566 results: []Result{
1567 {
1568 Name: Measurement,
1569 Value: []byte("cpu"),
1570 },
1571 {
1572 Name: FieldKey,
1573 Value: []byte("value"),
1574 },
1575 {
1576 Name: FieldFloat,
1577 Value: []byte("42"),
1578 },
1579 {
1580 Name: Success,
1581 },
1582 },
1583 },
1584 {
1585 name: "middle comment",
1586 input: []byte("cpu value=42\n# blah blah\ncpu value=42"),
1587 results: []Result{
1588 {
1589 Name: Measurement,
1590 Value: []byte("cpu"),
1591 },
1592 {
1593 Name: FieldKey,
1594 Value: []byte("value"),
1595 },
1596 {
1597 Name: FieldFloat,
1598 Value: []byte("42"),
1599 },
1600 {
1601 Name: Success,
1602 },
1603 {
1604 Name: Measurement,
1605 Value: []byte("cpu"),
1606 },
1607 {
1608 Name: FieldKey,
1609 Value: []byte("value"),
1610 },
1611 {
1612 Name: FieldFloat,
1613 Value: []byte("42"),
1614 },
1615 {
1616 Name: Success,
1617 },
1618 },
1619 },
1620 {
1621 name: "end with comment",
1622 input: []byte("cpu value=42\n# blah blah"),
1623 results: []Result{
1624 {
1625 Name: Measurement,
1626 Value: []byte("cpu"),
1627 },
1628 {
1629 Name: FieldKey,
1630 Value: []byte("value"),
1631 },
1632 {
1633 Name: FieldFloat,
1634 Value: []byte("42"),
1635 },
1636 {
1637 Name: Success,
1638 },
1639 },
1640 },
1641 {
1642 name: "end with comment and whitespace",
1643 input: []byte("cpu value=42\n# blah blah\n\n "),
1644 results: []Result{
1645 {
1646 Name: Measurement,
1647 Value: []byte("cpu"),
1648 },
1649 {
1650 Name: FieldKey,
1651 Value: []byte("value"),
1652 },
1653 {
1654 Name: FieldFloat,
1655 Value: []byte("42"),
1656 },
1657 {
1658 Name: Success,
1659 },
1660 },
1661 },
1662 {
1663 name: "unicode",
1664 input: []byte("cpu ☺=42"),
1665 results: []Result{
1666 {
1667 Name: Measurement,
1668 Value: []byte("cpu"),
1669 },
1670 {
1671 Name: FieldKey,
1672 Value: []byte("☺"),
1673 },
1674 {
1675 Name: FieldFloat,
1676 Value: []byte("42"),
1677 },
1678 {
1679 Name: Success,
1680 },
1681 },
1682 },
1683 }
1684
1685 func TestMachine(t *testing.T) {
1686 for _, tt := range tests {
1687 t.Run(tt.name, func(t *testing.T) {
1688 handler := &TestingHandler{}
1689 fsm := protocol.NewMachine(handler)
1690 fsm.SetData(tt.input)
1691
1692 for i := 0; i < 20; i++ {
1693 err := fsm.Next()
1694 if err != nil && err == protocol.EOF {
1695 break
1696 }
1697 handler.Result(err)
1698 }
1699
1700 results := handler.Results()
1701
1702 if len(tt.results) != len(results) {
1703 t.Errorf("unexpected difference in result lengths = %d, want %v", len(tt.results), len(results))
1704 return
1705 }
1706 for i := range tt.results {
1707 if tt.results[i].String() != results[i].String() {
1708 t.Errorf("Machine.Results() = %v, want %v", results, tt.results)
1709 }
1710 }
1711 })
1712 }
1713 }
1714
1715 var positionTests = []struct {
1716 name string
1717 input []byte
1718 lineno int
1719 column int
1720 }{
1721 {
1722 name: "empty string",
1723 input: []byte(""),
1724 lineno: 1,
1725 column: 1,
1726 },
1727 {
1728 name: "minimal",
1729 input: []byte("cpu value=42"),
1730 lineno: 1,
1731 column: 13,
1732 },
1733 {
1734 name: "one newline",
1735 input: []byte("cpu value=42\ncpu value=42"),
1736 lineno: 2,
1737 column: 13,
1738 },
1739 {
1740 name: "several newlines",
1741 input: []byte("cpu value=42\n\n\n"),
1742 lineno: 4,
1743 column: 1,
1744 },
1745 {
1746 name: "error on second line",
1747 input: []byte("cpu value=42\ncpu value=invalid"),
1748 lineno: 2,
1749 column: 11,
1750 },
1751 {
1752 name: "error after comment line",
1753 input: []byte("cpu value=42\n# comment\ncpu value=invalid"),
1754 lineno: 3,
1755 column: 11,
1756 },
1757 {
1758 name: "dos line endings",
1759 input: []byte("cpu value=42\r\ncpu value=invalid"),
1760 lineno: 2,
1761 column: 11,
1762 },
1763 {
1764 name: "mac line endings not supported",
1765 input: []byte("cpu value=42\rcpu value=invalid"),
1766 lineno: 1,
1767 column: 14,
1768 },
1769 }
1770
1771 func TestMachinePosition(t *testing.T) {
1772 for _, tt := range positionTests {
1773 t.Run(tt.name, func(t *testing.T) {
1774 handler := &TestingHandler{}
1775 fsm := protocol.NewMachine(handler)
1776 fsm.SetData(tt.input)
1777
1778 // Parse until an error or eof
1779 for i := 0; i < 20; i++ {
1780 err := fsm.Next()
1781 if err != nil {
1782 break
1783 }
1784 }
1785
1786 if tt.lineno != fsm.LineNumber() {
1787 t.Errorf("unexpected difference in line number: %d, want = %d", tt.lineno, fsm.LineNumber())
1788 }
1789
1790 if tt.column != fsm.Column() {
1791 t.Errorf("unexpected difference in column number: %d, want = %d", tt.column, fsm.Column())
1792 }
1793 })
1794 }
1795 }
1796
1797 func BenchmarkMachine(b *testing.B) {
1798 for _, tt := range tests {
1799 b.Run(tt.name, func(b *testing.B) {
1800 handler := &BenchmarkingHandler{}
1801 fsm := protocol.NewMachine(handler)
1802
1803 for n := 0; n < b.N; n++ {
1804 fsm.SetData(tt.input)
1805
1806 for {
1807 err := fsm.Next()
1808 if err != nil {
1809 break
1810 }
1811 }
1812 }
1813 })
1814 }
1815 }
1816
1817 func TestMachineProcstat(t *testing.T) {
1818 input := []byte("procstat,exe=bash,process_name=bash voluntary_context_switches=42i,memory_rss=5103616i,rlimit_memory_data_hard=2147483647i,cpu_time_user=0.02,rlimit_file_locks_soft=2147483647i,pid=29417i,cpu_time_nice=0,rlimit_memory_locked_soft=65536i,read_count=259i,rlimit_memory_vms_hard=2147483647i,memory_swap=0i,rlimit_num_fds_soft=1024i,rlimit_nice_priority_hard=0i,cpu_time_soft_irq=0,cpu_time=0i,rlimit_memory_locked_hard=65536i,realtime_priority=0i,signals_pending=0i,nice_priority=20i,cpu_time_idle=0,memory_stack=139264i,memory_locked=0i,rlimit_memory_stack_soft=8388608i,cpu_time_iowait=0,cpu_time_guest=0,cpu_time_guest_nice=0,rlimit_memory_data_soft=2147483647i,read_bytes=0i,rlimit_cpu_time_soft=2147483647i,involuntary_context_switches=2i,write_bytes=106496i,cpu_time_system=0,cpu_time_irq=0,cpu_usage=0,memory_vms=21659648i,memory_data=1576960i,rlimit_memory_stack_hard=2147483647i,num_threads=1i,rlimit_memory_rss_soft=2147483647i,rlimit_realtime_priority_soft=0i,num_fds=4i,write_count=35i,rlimit_signals_pending_soft=78994i,cpu_time_steal=0,rlimit_num_fds_hard=4096i,rlimit_file_locks_hard=2147483647i,rlimit_cpu_time_hard=2147483647i,rlimit_signals_pending_hard=78994i,rlimit_nice_priority_soft=0i,rlimit_memory_rss_hard=2147483647i,rlimit_memory_vms_soft=2147483647i,rlimit_realtime_priority_hard=0i 1517620624000000000")
1819 handler := &TestingHandler{}
1820 fsm := protocol.NewMachine(handler)
1821 fsm.SetData(input)
1822 for {
1823 err := fsm.Next()
1824 if err != nil {
1825 break
1826 }
1827 }
1828 }
1829
1830 func BenchmarkMachineProcstat(b *testing.B) {
1831 input := []byte("procstat,exe=bash,process_name=bash voluntary_context_switches=42i,memory_rss=5103616i,rlimit_memory_data_hard=2147483647i,cpu_time_user=0.02,rlimit_file_locks_soft=2147483647i,pid=29417i,cpu_time_nice=0,rlimit_memory_locked_soft=65536i,read_count=259i,rlimit_memory_vms_hard=2147483647i,memory_swap=0i,rlimit_num_fds_soft=1024i,rlimit_nice_priority_hard=0i,cpu_time_soft_irq=0,cpu_time=0i,rlimit_memory_locked_hard=65536i,realtime_priority=0i,signals_pending=0i,nice_priority=20i,cpu_time_idle=0,memory_stack=139264i,memory_locked=0i,rlimit_memory_stack_soft=8388608i,cpu_time_iowait=0,cpu_time_guest=0,cpu_time_guest_nice=0,rlimit_memory_data_soft=2147483647i,read_bytes=0i,rlimit_cpu_time_soft=2147483647i,involuntary_context_switches=2i,write_bytes=106496i,cpu_time_system=0,cpu_time_irq=0,cpu_usage=0,memory_vms=21659648i,memory_data=1576960i,rlimit_memory_stack_hard=2147483647i,num_threads=1i,rlimit_memory_rss_soft=2147483647i,rlimit_realtime_priority_soft=0i,num_fds=4i,write_count=35i,rlimit_signals_pending_soft=78994i,cpu_time_steal=0,rlimit_num_fds_hard=4096i,rlimit_file_locks_hard=2147483647i,rlimit_cpu_time_hard=2147483647i,rlimit_signals_pending_hard=78994i,rlimit_nice_priority_soft=0i,rlimit_memory_rss_hard=2147483647i,rlimit_memory_vms_soft=2147483647i,rlimit_realtime_priority_hard=0i 1517620624000000000")
1832 handler := &BenchmarkingHandler{}
1833 fsm := protocol.NewMachine(handler)
1834 for n := 0; n < b.N; n++ {
1835 fsm.SetData(input)
1836 for {
1837 err := fsm.Next()
1838 if err != nil {
1839 break
1840 }
1841 }
1842 }
1843 }
1844
1845 func TestSeriesMachine(t *testing.T) {
1846 var tests = []struct {
1847 name string
1848 input []byte
1849 results []Result
1850 err error
1851 }{
1852 {
1853 name: "empty string",
1854 input: []byte(""),
1855 results: nil,
1856 },
1857 {
1858 name: "no tags",
1859 input: []byte("cpu"),
1860 results: []Result{
1861 {
1862 Name: Measurement,
1863 Value: []byte("cpu"),
1864 },
1865 {
1866 Name: Success,
1867 },
1868 },
1869 },
1870 {
1871 name: "tags",
1872 input: []byte("cpu,a=x,b=y"),
1873 results: []Result{
1874 {
1875 Name: Measurement,
1876 Value: []byte("cpu"),
1877 },
1878 {
1879 Name: TagKey,
1880 Value: []byte("a"),
1881 },
1882 {
1883 Name: TagValue,
1884 Value: []byte("x"),
1885 },
1886 {
1887 Name: TagKey,
1888 Value: []byte("b"),
1889 },
1890 {
1891 Name: TagValue,
1892 Value: []byte("y"),
1893 },
1894 {
1895 Name: Success,
1896 },
1897 },
1898 },
1899 }
1900
1901 for _, tt := range tests {
1902 t.Run(tt.name, func(t *testing.T) {
1903 handler := &TestingHandler{}
1904 fsm := protocol.NewSeriesMachine(handler)
1905 fsm.SetData(tt.input)
1906
1907 for {
1908 err := fsm.Next()
1909 if err != nil {
1910 break
1911 }
1912 handler.Result(err)
1913 }
1914
1915 results := handler.Results()
1916 if len(tt.results) != len(results) {
1917 t.Errorf("unexpected difference in result lengths = %d, want %v", len(tt.results), len(results))
1918 return
1919 }
1920 for i := range tt.results {
1921 if tt.results[i].String() != results[i].String() {
1922 t.Errorf("Machine.Results() = %v, want %v", results, tt.results)
1923 }
1924 }
1925 })
1926 }
1927 }
1928
1929 type MockHandler struct {
1930 SetMeasurementF func(name []byte) error
1931 AddTagF func(key []byte, value []byte) error
1932 AddIntF func(key []byte, value []byte) error
1933 AddUintF func(key []byte, value []byte) error
1934 AddFloatF func(key []byte, value []byte) error
1935 AddStringF func(key []byte, value []byte) error
1936 AddBoolF func(key []byte, value []byte) error
1937 SetTimestampF func(tm []byte) error
1938
1939 TestingHandler
1940 }
1941
1942 func (h *MockHandler) SetMeasurement(name []byte) error {
1943 h.TestingHandler.SetMeasurement(name)
1944 return h.SetMeasurementF(name)
1945 }
1946
1947 func (h *MockHandler) AddTag(name, value []byte) error {
1948 return h.AddTagF(name, value)
1949 }
1950
1951 func (h *MockHandler) AddInt(name, value []byte) error {
1952 err := h.AddIntF(name, value)
1953 if err != nil {
1954 return err
1955 }
1956 h.TestingHandler.AddInt(name, value)
1957 return nil
1958 }
1959
1960 func (h *MockHandler) AddUint(name, value []byte) error {
1961 err := h.AddUintF(name, value)
1962 if err != nil {
1963 return err
1964 }
1965 h.TestingHandler.AddUint(name, value)
1966 return nil
1967 }
1968
1969 func (h *MockHandler) AddFloat(name, value []byte) error {
1970 return h.AddFloatF(name, value)
1971 }
1972
1973 func (h *MockHandler) AddString(name, value []byte) error {
1974 return h.AddStringF(name, value)
1975 }
1976
1977 func (h *MockHandler) AddBool(name, value []byte) error {
1978 return h.AddBoolF(name, value)
1979 }
1980
1981 func (h *MockHandler) SetTimestamp(tm []byte) error {
1982 return h.SetTimestampF(tm)
1983 }
1984
1985 var errorRecoveryTests = []struct {
1986 name string
1987 input []byte
1988 handler *MockHandler
1989 results []Result
1990 }{
1991 {
1992 name: "integer",
1993 input: []byte("cpu value=43i\ncpu value=42i"),
1994 handler: &MockHandler{
1995 SetMeasurementF: func(name []byte) error {
1996 return nil
1997 },
1998 AddIntF: func(name, value []byte) error {
1999 if string(value) != "42i" {
2000 return errors.New("handler error")
2001 }
2002 return nil
2003 },
2004 },
2005 results: []Result{
2006 {
2007 Name: Measurement,
2008 Value: []byte("cpu"),
2009 },
2010 {
2011 Name: Error,
2012 err: errors.New("handler error"),
2013 },
2014 {
2015 Name: Measurement,
2016 Value: []byte("cpu"),
2017 },
2018 {
2019 Name: FieldKey,
2020 Value: []byte("value"),
2021 },
2022 {
2023 Name: FieldInt,
2024 Value: []byte("42i"),
2025 },
2026 {
2027 Name: Success,
2028 },
2029 },
2030 },
2031 {
2032 name: "integer with timestamp",
2033 input: []byte("cpu value=43i 1516241192000000000\ncpu value=42i"),
2034 handler: &MockHandler{
2035 SetMeasurementF: func(name []byte) error {
2036 return nil
2037 },
2038 AddIntF: func(name, value []byte) error {
2039 if string(value) != "42i" {
2040 return errors.New("handler error")
2041 }
2042 return nil
2043 },
2044 },
2045 results: []Result{
2046 {
2047 Name: Measurement,
2048 Value: []byte("cpu"),
2049 },
2050 {
2051 Name: Error,
2052 err: errors.New("handler error"),
2053 },
2054 {
2055 Name: Measurement,
2056 Value: []byte("cpu"),
2057 },
2058 {
2059 Name: FieldKey,
2060 Value: []byte("value"),
2061 },
2062 {
2063 Name: FieldInt,
2064 Value: []byte("42i"),
2065 },
2066 {
2067 Name: Success,
2068 },
2069 },
2070 },
2071 {
2072 name: "unsigned",
2073 input: []byte("cpu value=43u\ncpu value=42u"),
2074 handler: &MockHandler{
2075 SetMeasurementF: func(name []byte) error {
2076 return nil
2077 },
2078 AddUintF: func(name, value []byte) error {
2079 if string(value) != "42u" {
2080 return errors.New("handler error")
2081 }
2082 return nil
2083 },
2084 },
2085 results: []Result{
2086 {
2087 Name: Measurement,
2088 Value: []byte("cpu"),
2089 },
2090 {
2091 Name: Error,
2092 err: errors.New("handler error"),
2093 },
2094 {
2095 Name: Measurement,
2096 Value: []byte("cpu"),
2097 },
2098 {
2099 Name: FieldKey,
2100 Value: []byte("value"),
2101 },
2102 {
2103 Name: FieldUint,
2104 Value: []byte("42u"),
2105 },
2106 {
2107 Name: Success,
2108 },
2109 },
2110 },
2111 }
2112
2113 func TestHandlerErrorRecovery(t *testing.T) {
2114 for _, tt := range errorRecoveryTests {
2115 t.Run(tt.name, func(t *testing.T) {
2116 fsm := protocol.NewMachine(tt.handler)
2117 fsm.SetData(tt.input)
2118
2119 for i := 0; i < 20; i++ {
2120 err := fsm.Next()
2121 if err != nil && err == protocol.EOF {
2122 break
2123 }
2124 tt.handler.Result(err)
2125 }
2126
2127 results := tt.handler.Results()
2128 if len(tt.results) != len(results) {
2129 t.Errorf("unexpected difference in result lengths = %d, want %v", len(tt.results), len(results))
2130 return
2131 }
2132 for i := range tt.results {
2133 if tt.results[i].String() != results[i].String() {
2134 t.Errorf("Machine.Results() = %v, want %v", results, tt.results)
2135 }
2136 }
2137 })
2138 }
2139 }
2140
2141 func TestStreamMachine(t *testing.T) {
2142 type testcase struct {
2143 name string
2144 input io.Reader
2145 results []Result
2146 err error
2147 }
2148
2149 var tc []testcase
2150 for _, tt := range tests {
2151 tc = append(tc, testcase{
2152 name: tt.name,
2153 input: bytes.NewBuffer([]byte(tt.input)),
2154 results: tt.results,
2155 err: tt.err,
2156 })
2157 }
2158
2159 for _, tt := range tc {
2160 t.Run(tt.name, func(t *testing.T) {
2161 handler := &TestingHandler{}
2162 fsm := protocol.NewStreamMachine(tt.input, handler)
2163
2164 // Parse only up to 20 metrics; to avoid any bugs where the parser
2165 // isn't terminated.
2166 for i := 0; i < 20; i++ {
2167 err := fsm.Next()
2168 if err != nil && err == protocol.EOF {
2169 break
2170 }
2171 handler.Result(err)
2172 }
2173
2174 results := handler.Results()
2175 if len(tt.results) != len(results) {
2176 t.Errorf("unexpected difference in result lengths = %d, want %v", len(tt.results), len(results))
2177 return
2178 }
2179 for i := range tt.results {
2180 if tt.results[i].String() != results[i].String() {
2181 t.Errorf("Machine.Results() = %v, want %v", results, tt.results)
2182 }
2183 }
2184 })
2185 }
2186 }
2187
2188 func TestStreamMachinePosition(t *testing.T) {
2189 type testcase struct {
2190 name string
2191 input io.Reader
2192 lineno int
2193 column int
2194 }
2195
2196 var tc []testcase
2197 for _, tt := range positionTests {
2198 tc = append(tc, testcase{
2199 name: tt.name,
2200 input: bytes.NewBuffer([]byte(tt.input)),
2201 lineno: tt.lineno,
2202 column: tt.column,
2203 })
2204 }
2205
2206 for _, tt := range tc {
2207 t.Run(tt.name, func(t *testing.T) {
2208 handler := &TestingHandler{}
2209 fsm := protocol.NewStreamMachine(tt.input, handler)
2210
2211 // Parse until an error or eof
2212 for i := 0; i < 20; i++ {
2213 err := fsm.Next()
2214 if err != nil {
2215 break
2216 }
2217 }
2218
2219 if tt.lineno != fsm.LineNumber() {
2220 t.Errorf("unexpected difference in line number: %d, want = %d", tt.lineno, fsm.LineNumber())
2221 }
2222
2223 if tt.column != fsm.Column() {
2224 t.Errorf("unexpected difference in column number: %d, want = %d", tt.column, fsm.Column())
2225 }
2226 })
2227 }
2228 }
00 package protocol
11
2 import "time"
3
4 // Tag holds the keys and values for a bunch of Tag k/v pairs
2 import (
3 "fmt"
4 "hash/fnv"
5 "sort"
6 "time"
7 )
8
9 // Tag holds the keys and values for a bunch of Tag k/v pairs.
510 type Tag struct {
611 Key string
712 Value string
813 }
914
10 // Field holds the keys and values for a bunch of Metric Field k/v pairs
15 // Field holds the keys and values for a bunch of Metric Field k/v pairs where Value can be a uint64, int64, int, float32, float64, string, or bool.
1116 type Field struct {
1217 Key string
1318 Value interface{}
2126 FieldList() []*Field
2227 }
2328
29 // MutableMetric represents a metric that can be be modified.
30 type MutableMetric interface {
31 Metric
32 SetTime(time.Time)
33 AddTag(key, value string)
34 AddField(key string, value interface{})
35 }
36
2437 // FieldSortOrder is a type for controlling if Fields are sorted
2538 type FieldSortOrder int
2639
2740 const (
28 // NoSortFields tells the Decoder to not sort the fields
41 // NoSortFields tells the Decoder to not sort the fields.
2942 NoSortFields FieldSortOrder = iota
3043
31 // SortFields tells the Decoder to sort the fields
44 // SortFields tells the Decoder to sort the fields.
3245 SortFields
3346 )
3447
35 // FieldTypeSupport is a type for the parser to understand its type support
48 // FieldTypeSupport is a type for the parser to understand its type support.
3649 type FieldTypeSupport int
3750
3851 const (
39 // UintSupport means the parser understands uint64s and can store them without having to convert to int64
52 // UintSupport means the parser understands uint64s and can store them without having to convert to int64.
4053 UintSupport FieldTypeSupport = 1 << iota
4154 )
4255
5972 }
6073
6174 var (
62 // ErrNeedMoreSpace tells us that the Decoder's io.Reader is full
75 // ErrNeedMoreSpace tells us that the Decoder's io.Reader is full.
6376 ErrNeedMoreSpace = &MetricError{"need more space"}
6477
65 // ErrInvalidName tells us that the chosen name is invalid
78 // ErrInvalidName tells us that the chosen name is invalid.
6679 ErrInvalidName = &MetricError{"invalid name"}
6780
68 // ErrNoFields tells us that there were no serializable fields in the line/metric
81 // ErrNoFields tells us that there were no serializable fields in the line/metric.
6982 ErrNoFields = &MetricError{"no serializable fields"}
7083 )
84
85 type metric struct {
86 name string
87 tags []*Tag
88 fields []*Field
89 tm time.Time
90 }
91
92 // New creates a new metric via maps.
93 func New(
94 name string,
95 tags map[string]string,
96 fields map[string]interface{},
97 tm time.Time,
98 ) (MutableMetric, error) {
99 m := &metric{
100 name: name,
101 tags: nil,
102 fields: nil,
103 tm: tm,
104 }
105
106 if len(tags) > 0 {
107 m.tags = make([]*Tag, 0, len(tags))
108 for k, v := range tags {
109 m.tags = append(m.tags,
110 &Tag{Key: k, Value: v})
111 }
112 sort.Slice(m.tags, func(i, j int) bool { return m.tags[i].Key < m.tags[j].Key })
113 }
114
115 if len(fields) > 0 {
116 m.fields = make([]*Field, 0, len(fields))
117 for k, v := range fields {
118 v := convertField(v)
119 if v == nil {
120 continue
121 }
122 m.AddField(k, v)
123 }
124 }
125
126 return m, nil
127 }
128
129 // FromMetric returns a deep copy of the metric with any tracking information
130 // removed.
131 func FromMetric(other Metric) Metric {
132 m := &metric{
133 name: other.Name(),
134 tags: make([]*Tag, len(other.TagList())),
135 fields: make([]*Field, len(other.FieldList())),
136 tm: other.Time(),
137 }
138
139 for i, tag := range other.TagList() {
140 m.tags[i] = &Tag{Key: tag.Key, Value: tag.Value}
141 }
142
143 for i, field := range other.FieldList() {
144 m.fields[i] = &Field{Key: field.Key, Value: field.Value}
145 }
146 return m
147 }
148
149 func (m *metric) String() string {
150 return fmt.Sprintf("%s %v %v %d", m.name, m.Tags(), m.Fields(), m.tm.UnixNano())
151 }
152
153 func (m *metric) Name() string {
154 return m.name
155 }
156
157 func (m *metric) Tags() map[string]string {
158 tags := make(map[string]string, len(m.tags))
159 for _, tag := range m.tags {
160 tags[tag.Key] = tag.Value
161 }
162 return tags
163 }
164
165 func (m *metric) TagList() []*Tag {
166 return m.tags
167 }
168
169 func (m *metric) Fields() map[string]interface{} {
170 fields := make(map[string]interface{}, len(m.fields))
171 for _, field := range m.fields {
172 fields[field.Key] = field.Value
173 }
174
175 return fields
176 }
177
178 func (m *metric) FieldList() []*Field {
179 return m.fields
180 }
181
182 func (m *metric) Time() time.Time {
183 return m.tm
184 }
185
186 func (m *metric) SetName(name string) {
187 m.name = name
188 }
189
190 func (m *metric) AddPrefix(prefix string) {
191 m.name = prefix + m.name
192 }
193
194 func (m *metric) AddSuffix(suffix string) {
195 m.name = m.name + suffix
196 }
197
198 func (m *metric) AddTag(key, value string) {
199 for i, tag := range m.tags {
200 if key > tag.Key {
201 continue
202 }
203
204 if key == tag.Key {
205 tag.Value = value
206 return
207 }
208
209 m.tags = append(m.tags, nil)
210 copy(m.tags[i+1:], m.tags[i:])
211 m.tags[i] = &Tag{Key: key, Value: value}
212 return
213 }
214
215 m.tags = append(m.tags, &Tag{Key: key, Value: value})
216 }
217
218 func (m *metric) HasTag(key string) bool {
219 for _, tag := range m.tags {
220 if tag.Key == key {
221 return true
222 }
223 }
224 return false
225 }
226
227 func (m *metric) GetTag(key string) (string, bool) {
228 for _, tag := range m.tags {
229 if tag.Key == key {
230 return tag.Value, true
231 }
232 }
233 return "", false
234 }
235
236 func (m *metric) RemoveTag(key string) {
237 for i, tag := range m.tags {
238 if tag.Key == key {
239 copy(m.tags[i:], m.tags[i+1:])
240 m.tags[len(m.tags)-1] = nil
241 m.tags = m.tags[:len(m.tags)-1]
242 return
243 }
244 }
245 }
246
247 func (m *metric) AddField(key string, value interface{}) {
248 for i, field := range m.fields {
249 if key == field.Key {
250 m.fields[i] = &Field{Key: key, Value: convertField(value)}
251 return
252 }
253 }
254 m.fields = append(m.fields, &Field{Key: key, Value: convertField(value)})
255 }
256
257 func (m *metric) HasField(key string) bool {
258 for _, field := range m.fields {
259 if field.Key == key {
260 return true
261 }
262 }
263 return false
264 }
265
266 func (m *metric) GetField(key string) (interface{}, bool) {
267 for _, field := range m.fields {
268 if field.Key == key {
269 return field.Value, true
270 }
271 }
272 return nil, false
273 }
274
275 func (m *metric) RemoveField(key string) {
276 for i, field := range m.fields {
277 if field.Key == key {
278 copy(m.fields[i:], m.fields[i+1:])
279 m.fields[len(m.fields)-1] = nil
280 m.fields = m.fields[:len(m.fields)-1]
281 return
282 }
283 }
284 }
285
286 func (m *metric) SetTime(t time.Time) {
287 m.tm = t
288 }
289
290 func (m *metric) Copy() Metric {
291 m2 := &metric{
292 name: m.name,
293 tags: make([]*Tag, len(m.tags)),
294 fields: make([]*Field, len(m.fields)),
295 tm: m.tm,
296 }
297
298 for i, tag := range m.tags {
299 m2.tags[i] = &Tag{Key: tag.Key, Value: tag.Value}
300 }
301
302 for i, field := range m.fields {
303 m2.fields[i] = &Field{Key: field.Key, Value: field.Value}
304 }
305 return m2
306 }
307
308 func (m *metric) HashID() uint64 {
309 h := fnv.New64a()
310 h.Write([]byte(m.name))
311 h.Write([]byte("\n"))
312 for _, tag := range m.tags {
313 h.Write([]byte(tag.Key))
314 h.Write([]byte("\n"))
315 h.Write([]byte(tag.Value))
316 h.Write([]byte("\n"))
317 }
318 return h.Sum64()
319 }
320
321 func (m *metric) Accept() {
322 }
323
324 func (m *metric) Reject() {
325 }
326
327 func (m *metric) Drop() {
328 }
329
330 // Convert field to a supported type or nil if unconvertible
331 func convertField(v interface{}) interface{} {
332 switch v := v.(type) {
333 case float64:
334 return v
335 case int64:
336 return v
337 case string:
338 return v
339 case bool:
340 return v
341 case int:
342 return int64(v)
343 case uint:
344 return uint64(v)
345 case uint64:
346 return uint64(v)
347 case []byte:
348 return string(v)
349 case int32:
350 return int64(v)
351 case int16:
352 return int64(v)
353 case int8:
354 return int64(v)
355 case uint32:
356 return uint64(v)
357 case uint16:
358 return uint64(v)
359 case uint8:
360 return uint64(v)
361 case float32:
362 return float64(v)
363 case *float64:
364 if v != nil {
365 return *v
366 }
367 case *int64:
368 if v != nil {
369 return *v
370 }
371 case *string:
372 if v != nil {
373 return *v
374 }
375 case *bool:
376 if v != nil {
377 return *v
378 }
379 case *int:
380 if v != nil {
381 return int64(*v)
382 }
383 case *uint:
384 if v != nil {
385 return uint64(*v)
386 }
387 case *uint64:
388 if v != nil {
389 return uint64(*v)
390 }
391 case *[]byte:
392 if v != nil {
393 return string(*v)
394 }
395 case *int32:
396 if v != nil {
397 return int64(*v)
398 }
399 case *int16:
400 if v != nil {
401 return int64(*v)
402 }
403 case *int8:
404 if v != nil {
405 return int64(*v)
406 }
407 case *uint32:
408 if v != nil {
409 return uint64(*v)
410 }
411 case *uint16:
412 if v != nil {
413 return uint64(*v)
414 }
415 case *uint8:
416 if v != nil {
417 return uint64(*v)
418 }
419 case *float32:
420 if v != nil {
421 return float64(*v)
422 }
423 default:
424 return nil
425 }
426 return nil
427 }
0 package protocol
1
2 import (
3 "fmt"
4 "io"
5 "strings"
6 "sync"
7 "time"
8 )
9
10 const (
11 maxErrorBufferSize = 1024
12 )
13
14 // TimeFunc is used to override the default time for a metric
15 // with no specified timestamp.
16 type TimeFunc func() time.Time
17
18 // ParseError indicates a error in the parsing of the text.
19 type ParseError struct {
20 Offset int
21 LineOffset int
22 LineNumber int
23 Column int
24 msg string
25 buf string
26 }
27
28 func (e *ParseError) Error() string {
29 buffer := e.buf[e.LineOffset:]
30 eol := strings.IndexAny(buffer, "\r\n")
31 if eol >= 0 {
32 buffer = buffer[:eol]
33 }
34 if len(buffer) > maxErrorBufferSize {
35 buffer = buffer[:maxErrorBufferSize] + "..."
36 }
37 return fmt.Sprintf("metric parse error: %s at %d:%d: %q", e.msg, e.LineNumber, e.Column, buffer)
38 }
39
40 // Parser is an InfluxDB Line Protocol parser that implements the
41 // parsers.Parser interface.
42 type Parser struct {
43 DefaultTags map[string]string
44
45 sync.Mutex
46 *machine
47 handler *MetricHandler
48 }
49
50 // NewParser returns a Parser than accepts line protocol
51 func NewParser(handler *MetricHandler) *Parser {
52 return &Parser{
53 machine: NewMachine(handler),
54 handler: handler,
55 }
56 }
57
58 // NewSeriesParser returns a Parser than accepts a measurement and tagset
59 func NewSeriesParser(handler *MetricHandler) *Parser {
60 return &Parser{
61 machine: NewSeriesMachine(handler),
62 handler: handler,
63 }
64 }
65
66 // SetTimeFunc allows default times to be set when no time is specified
67 // for a metric in line-protocol.
68 func (p *Parser) SetTimeFunc(f TimeFunc) {
69 p.handler.SetTimeFunc(f)
70 }
71
72 // Parse interprets line-protocol bytes as many metrics.
73 func (p *Parser) Parse(input []byte) ([]Metric, error) {
74 p.Lock()
75 defer p.Unlock()
76 metrics := make([]Metric, 0)
77 p.machine.SetData(input)
78
79 for {
80 err := p.machine.Next()
81 if err == EOF {
82 break
83 }
84
85 if err != nil {
86 return nil, &ParseError{
87 Offset: p.machine.Position(),
88 LineOffset: p.machine.LineOffset(),
89 LineNumber: p.machine.LineNumber(),
90 Column: p.machine.Column(),
91 msg: err.Error(),
92 buf: string(input),
93 }
94 }
95
96 metric, err := p.handler.Metric()
97 if err != nil {
98 return nil, err
99 }
100
101 if metric == nil {
102 continue
103 }
104
105 metrics = append(metrics, metric)
106 }
107
108 return metrics, nil
109 }
110
111 // StreamParser is an InfluxDB Line Protocol parser. It is not safe for
112 // concurrent use in multiple goroutines.
113 type StreamParser struct {
114 machine *streamMachine
115 handler *MetricHandler
116 }
117
118 // NewStreamParser parses from a reader and iterates the machine
119 // metric by metric. Not safe for concurrent use in multiple goroutines.
120 func NewStreamParser(r io.Reader) *StreamParser {
121 handler := NewMetricHandler()
122 return &StreamParser{
123 machine: NewStreamMachine(r, handler),
124 handler: handler,
125 }
126 }
127
128 // SetTimeFunc changes the function used to determine the time of metrics
129 // without a timestamp. The default TimeFunc is time.Now. Useful mostly for
130 // testing, or perhaps if you want all metrics to have the same timestamp.
131 func (p *StreamParser) SetTimeFunc(f TimeFunc) {
132 p.handler.SetTimeFunc(f)
133 }
134
135 // SetTimePrecision specifies units for the time stamp.
136 func (p *StreamParser) SetTimePrecision(u time.Duration) {
137 p.handler.SetTimePrecision(u)
138 }
139
140 // Next parses the next item from the stream. You can repeat calls to this
141 // function until it returns EOF.
142 func (p *StreamParser) Next() (Metric, error) {
143 err := p.machine.Next()
144 if err == EOF {
145 return nil, EOF
146 }
147
148 if err != nil {
149 return nil, &ParseError{
150 Offset: p.machine.Position(),
151 LineOffset: p.machine.LineOffset(),
152 LineNumber: p.machine.LineNumber(),
153 Column: p.machine.Column(),
154 msg: err.Error(),
155 buf: p.machine.LineText(),
156 }
157 }
158
159 metric, err := p.handler.Metric()
160 if err != nil {
161 return nil, err
162 }
163
164 return metric, nil
165 }
166
167 // Position returns the current byte offset into the data.
168 func (p *StreamParser) Position() int {
169 return p.machine.Position()
170 }
171
172 // LineOffset returns the byte offset of the current line.
173 func (p *StreamParser) LineOffset() int {
174 return p.machine.LineOffset()
175 }
176
177 // LineNumber returns the current line number. Lines are counted based on the
178 // regular expression `\r?\n`.
179 func (p *StreamParser) LineNumber() int {
180 return p.machine.LineNumber()
181 }
182
183 // Column returns the current column.
184 func (p *StreamParser) Column() int {
185 return p.machine.Column()
186 }
187
188 // LineText returns the text of the current line that has been parsed so far.
189 func (p *StreamParser) LineText() string {
190 return p.machine.LineText()
191 }
0 package protocol
1
2 import (
3 "bytes"
4 "reflect"
5 "sort"
6 "strconv"
7 "strings"
8 "testing"
9 "time"
10 )
11
12 func MustMetric(v Metric, err error) Metric {
13 if err != nil {
14 panic(err)
15 }
16 return v
17 }
18
19 var DefaultTime = func() time.Time {
20 return time.Unix(42, 0)
21 }
22
23 var ptests = []struct {
24 name string
25 input []byte
26 timeFunc func() time.Time
27 metrics []Metric
28 err error
29 }{
30 {
31 name: "minimal",
32 input: []byte("cpu value=42 0"),
33 metrics: []Metric{
34 MustMetric(
35 New(
36 "cpu",
37 map[string]string{},
38 map[string]interface{}{
39 "value": 42.0,
40 },
41 time.Unix(0, 0),
42 ),
43 ),
44 },
45 err: nil,
46 },
47 {
48 name: "minimal with newline",
49 input: []byte("cpu value=42 0\n"),
50 metrics: []Metric{
51 MustMetric(
52 New(
53 "cpu",
54 map[string]string{},
55 map[string]interface{}{
56 "value": 42.0,
57 },
58 time.Unix(0, 0),
59 ),
60 ),
61 },
62 err: nil,
63 },
64 {
65 name: "measurement escape space",
66 input: []byte(`c\ pu value=42`),
67 metrics: []Metric{
68 MustMetric(
69 New(
70 "c pu",
71 map[string]string{},
72 map[string]interface{}{
73 "value": 42.0,
74 },
75 time.Unix(42, 0),
76 ),
77 ),
78 },
79 err: nil,
80 },
81 {
82 name: "measurement escape comma",
83 input: []byte(`c\,pu value=42`),
84 metrics: []Metric{
85 MustMetric(
86 New(
87 "c,pu",
88 map[string]string{},
89 map[string]interface{}{
90 "value": 42.0,
91 },
92 time.Unix(42, 0),
93 ),
94 ),
95 },
96 err: nil,
97 },
98 {
99 name: "tags",
100 input: []byte(`cpu,cpu=cpu0,host=localhost value=42`),
101 metrics: []Metric{
102 MustMetric(
103 New(
104 "cpu",
105 map[string]string{
106 "cpu": "cpu0",
107 "host": "localhost",
108 },
109 map[string]interface{}{
110 "value": 42.0,
111 },
112 time.Unix(42, 0),
113 ),
114 ),
115 },
116 err: nil,
117 },
118 {
119 name: "tags escape unescapable",
120 input: []byte(`cpu,ho\st=localhost value=42`),
121 metrics: []Metric{
122 MustMetric(
123 New(
124 "cpu",
125 map[string]string{
126 `ho\st`: "localhost",
127 },
128 map[string]interface{}{
129 "value": 42.0,
130 },
131 time.Unix(42, 0),
132 ),
133 ),
134 },
135 err: nil,
136 },
137 {
138 name: "tags escape equals",
139 input: []byte(`cpu,ho\=st=localhost value=42`),
140 metrics: []Metric{
141 MustMetric(
142 New(
143 "cpu",
144 map[string]string{
145 "ho=st": "localhost",
146 },
147 map[string]interface{}{
148 "value": 42.0,
149 },
150 time.Unix(42, 0),
151 ),
152 ),
153 },
154 err: nil,
155 },
156 {
157 name: "tags escape comma",
158 input: []byte(`cpu,ho\,st=localhost value=42`),
159 metrics: []Metric{
160 MustMetric(
161 New(
162 "cpu",
163 map[string]string{
164 "ho,st": "localhost",
165 },
166 map[string]interface{}{
167 "value": 42.0,
168 },
169 time.Unix(42, 0),
170 ),
171 ),
172 },
173 err: nil,
174 },
175 {
176 name: "tag value escape space",
177 input: []byte(`cpu,host=two\ words value=42`),
178 metrics: []Metric{
179 MustMetric(
180 New(
181 "cpu",
182 map[string]string{
183 "host": "two words",
184 },
185 map[string]interface{}{
186 "value": 42.0,
187 },
188 time.Unix(42, 0),
189 ),
190 ),
191 },
192 err: nil,
193 },
194 {
195 name: "tag value double escape space",
196 input: []byte(`cpu,host=two\\ words value=42`),
197 metrics: []Metric{
198 MustMetric(
199 New(
200 "cpu",
201 map[string]string{
202 "host": `two\ words`,
203 },
204 map[string]interface{}{
205 "value": 42.0,
206 },
207 time.Unix(42, 0),
208 ),
209 ),
210 },
211 err: nil,
212 },
213 {
214 name: "tag value triple escape space",
215 input: []byte(`cpu,host=two\\\ words value=42`),
216 metrics: []Metric{
217 MustMetric(
218 New(
219 "cpu",
220 map[string]string{
221 "host": `two\\ words`,
222 },
223 map[string]interface{}{
224 "value": 42.0,
225 },
226 time.Unix(42, 0),
227 ),
228 ),
229 },
230 err: nil,
231 },
232 {
233 name: "field key escape not escapable",
234 input: []byte(`cpu va\lue=42`),
235 metrics: []Metric{
236 MustMetric(
237 New(
238 "cpu",
239 map[string]string{},
240 map[string]interface{}{
241 `va\lue`: 42.0,
242 },
243 time.Unix(42, 0),
244 ),
245 ),
246 },
247 err: nil,
248 },
249 {
250 name: "field key escape equals",
251 input: []byte(`cpu va\=lue=42`),
252 metrics: []Metric{
253 MustMetric(
254 New(
255 "cpu",
256 map[string]string{},
257 map[string]interface{}{
258 `va=lue`: 42.0,
259 },
260 time.Unix(42, 0),
261 ),
262 ),
263 },
264 err: nil,
265 },
266 {
267 name: "field key escape comma",
268 input: []byte(`cpu va\,lue=42`),
269 metrics: []Metric{
270 MustMetric(
271 New(
272 "cpu",
273 map[string]string{},
274 map[string]interface{}{
275 `va,lue`: 42.0,
276 },
277 time.Unix(42, 0),
278 ),
279 ),
280 },
281 err: nil,
282 },
283 {
284 name: "field key escape space",
285 input: []byte(`cpu va\ lue=42`),
286 metrics: []Metric{
287 MustMetric(
288 New(
289 "cpu",
290 map[string]string{},
291 map[string]interface{}{
292 `va lue`: 42.0,
293 },
294 time.Unix(42, 0),
295 ),
296 ),
297 },
298 err: nil,
299 },
300 {
301 name: "field int",
302 input: []byte("cpu value=42i"),
303 metrics: []Metric{
304 MustMetric(
305 New(
306 "cpu",
307 map[string]string{},
308 map[string]interface{}{
309 "value": 42,
310 },
311 time.Unix(42, 0),
312 ),
313 ),
314 },
315 err: nil,
316 },
317 {
318 name: "field int overflow",
319 input: []byte("cpu value=9223372036854775808i"),
320 metrics: nil,
321 err: &ParseError{
322 Offset: 30,
323 LineNumber: 1,
324 Column: 31,
325 msg: strconv.ErrRange.Error(),
326 buf: "cpu value=9223372036854775808i",
327 },
328 },
329 {
330 name: "field int max value",
331 input: []byte("cpu value=9223372036854775807i"),
332 metrics: []Metric{
333 MustMetric(
334 New(
335 "cpu",
336 map[string]string{},
337 map[string]interface{}{
338 "value": int64(9223372036854775807),
339 },
340 time.Unix(42, 0),
341 ),
342 ),
343 },
344 err: nil,
345 },
346 {
347 name: "field uint",
348 input: []byte("cpu value=42u"),
349 metrics: []Metric{
350 MustMetric(
351 New(
352 "cpu",
353 map[string]string{},
354 map[string]interface{}{
355 "value": uint64(42),
356 },
357 time.Unix(42, 0),
358 ),
359 ),
360 },
361 err: nil,
362 },
363 {
364 name: "field uint overflow",
365 input: []byte("cpu value=18446744073709551616u"),
366 metrics: nil,
367 err: &ParseError{
368 Offset: 31,
369 LineNumber: 1,
370 Column: 32,
371 msg: strconv.ErrRange.Error(),
372 buf: "cpu value=18446744073709551616u",
373 },
374 },
375 {
376 name: "field uint max value",
377 input: []byte("cpu value=18446744073709551615u"),
378 metrics: []Metric{
379 MustMetric(
380 New(
381 "cpu",
382 map[string]string{},
383 map[string]interface{}{
384 "value": uint64(18446744073709551615),
385 },
386 time.Unix(42, 0),
387 ),
388 ),
389 },
390 err: nil,
391 },
392 {
393 name: "field boolean",
394 input: []byte("cpu value=true"),
395 metrics: []Metric{
396 MustMetric(
397 New(
398 "cpu",
399 map[string]string{},
400 map[string]interface{}{
401 "value": true,
402 },
403 time.Unix(42, 0),
404 ),
405 ),
406 },
407 err: nil,
408 },
409 {
410 name: "field string",
411 input: []byte(`cpu value="42"`),
412 metrics: []Metric{
413 MustMetric(
414 New(
415 "cpu",
416 map[string]string{},
417 map[string]interface{}{
418 "value": "42",
419 },
420 time.Unix(42, 0),
421 ),
422 ),
423 },
424 err: nil,
425 },
426 {
427 name: "field string escape quote",
428 input: []byte(`cpu value="how\"dy"`),
429 metrics: []Metric{
430 MustMetric(
431 New(
432 "cpu",
433 map[string]string{},
434 map[string]interface{}{
435 `value`: `how"dy`,
436 },
437 time.Unix(42, 0),
438 ),
439 ),
440 },
441 err: nil,
442 },
443 {
444 name: "field string escape backslash",
445 input: []byte(`cpu value="how\\dy"`),
446 metrics: []Metric{
447 MustMetric(
448 New(
449 "cpu",
450 map[string]string{},
451 map[string]interface{}{
452 `value`: `how\dy`,
453 },
454 time.Unix(42, 0),
455 ),
456 ),
457 },
458 err: nil,
459 },
460 {
461 name: "field string newline",
462 input: []byte("cpu value=\"4\n2\""),
463 metrics: []Metric{
464 MustMetric(
465 New(
466 "cpu",
467 map[string]string{},
468 map[string]interface{}{
469 "value": "4\n2",
470 },
471 time.Unix(42, 0),
472 ),
473 ),
474 },
475 err: nil,
476 },
477 {
478 name: "no timestamp",
479 input: []byte("cpu value=42"),
480 metrics: []Metric{
481 MustMetric(
482 New(
483 "cpu",
484 map[string]string{},
485 map[string]interface{}{
486 "value": 42.0,
487 },
488 time.Unix(42, 0),
489 ),
490 ),
491 },
492 err: nil,
493 },
494 {
495 name: "no timestamp",
496 input: []byte("cpu value=42"),
497 timeFunc: func() time.Time {
498 return time.Unix(42, 123456789)
499 },
500 metrics: []Metric{
501 MustMetric(
502 New(
503 "cpu",
504 map[string]string{},
505 map[string]interface{}{
506 "value": 42.0,
507 },
508 time.Unix(42, 123456789),
509 ),
510 ),
511 },
512 err: nil,
513 },
514 {
515 name: "multiple lines",
516 input: []byte("cpu value=42\ncpu value=42"),
517 metrics: []Metric{
518 MustMetric(
519 New(
520 "cpu",
521 map[string]string{},
522 map[string]interface{}{
523 "value": 42.0,
524 },
525 time.Unix(42, 0),
526 ),
527 ),
528 MustMetric(
529 New(
530 "cpu",
531 map[string]string{},
532 map[string]interface{}{
533 "value": 42.0,
534 },
535 time.Unix(42, 0),
536 ),
537 ),
538 },
539 err: nil,
540 },
541 {
542 name: "invalid measurement only",
543 input: []byte("cpu"),
544 metrics: nil,
545 err: &ParseError{
546 Offset: 3,
547 LineNumber: 1,
548 Column: 4,
549 msg: ErrTagParse.Error(),
550 buf: "cpu",
551 },
552 },
553 {
554 name: "procstat",
555 input: []byte("procstat,exe=bash,process_name=bash voluntary_context_switches=42i,memory_rss=5103616i,rlimit_memory_data_hard=2147483647i,cpu_time_user=0.02,rlimit_file_locks_soft=2147483647i,pid=29417i,cpu_time_nice=0,rlimit_memory_locked_soft=65536i,read_count=259i,rlimit_memory_vms_hard=2147483647i,memory_swap=0i,rlimit_num_fds_soft=1024i,rlimit_nice_priority_hard=0i,cpu_time_soft_irq=0,cpu_time=0i,rlimit_memory_locked_hard=65536i,realtime_priority=0i,signals_pending=0i,nice_priority=20i,cpu_time_idle=0,memory_stack=139264i,memory_locked=0i,rlimit_memory_stack_soft=8388608i,cpu_time_iowait=0,cpu_time_guest=0,cpu_time_guest_nice=0,rlimit_memory_data_soft=2147483647i,read_bytes=0i,rlimit_cpu_time_soft=2147483647i,involuntary_context_switches=2i,write_bytes=106496i,cpu_time_system=0,cpu_time_irq=0,cpu_usage=0,memory_vms=21659648i,memory_data=1576960i,rlimit_memory_stack_hard=2147483647i,num_threads=1i,rlimit_memory_rss_soft=2147483647i,rlimit_realtime_priority_soft=0i,num_fds=4i,write_count=35i,rlimit_signals_pending_soft=78994i,cpu_time_steal=0,rlimit_num_fds_hard=4096i,rlimit_file_locks_hard=2147483647i,rlimit_cpu_time_hard=2147483647i,rlimit_signals_pending_hard=78994i,rlimit_nice_priority_soft=0i,rlimit_memory_rss_hard=2147483647i,rlimit_memory_vms_soft=2147483647i,rlimit_realtime_priority_hard=0i 1517620624000000000"),
556 metrics: []Metric{
557 MustMetric(
558 New(
559 "procstat",
560 map[string]string{
561 "exe": "bash",
562 "process_name": "bash",
563 },
564 map[string]interface{}{
565 "cpu_time": 0,
566 "cpu_time_guest": float64(0),
567 "cpu_time_guest_nice": float64(0),
568 "cpu_time_idle": float64(0),
569 "cpu_time_iowait": float64(0),
570 "cpu_time_irq": float64(0),
571 "cpu_time_nice": float64(0),
572 "cpu_time_soft_irq": float64(0),
573 "cpu_time_steal": float64(0),
574 "cpu_time_system": float64(0),
575 "cpu_time_user": float64(0.02),
576 "cpu_usage": float64(0),
577 "involuntary_context_switches": 2,
578 "memory_data": 1576960,
579 "memory_locked": 0,
580 "memory_rss": 5103616,
581 "memory_stack": 139264,
582 "memory_swap": 0,
583 "memory_vms": 21659648,
584 "nice_priority": 20,
585 "num_fds": 4,
586 "num_threads": 1,
587 "pid": 29417,
588 "read_bytes": 0,
589 "read_count": 259,
590 "realtime_priority": 0,
591 "rlimit_cpu_time_hard": 2147483647,
592 "rlimit_cpu_time_soft": 2147483647,
593 "rlimit_file_locks_hard": 2147483647,
594 "rlimit_file_locks_soft": 2147483647,
595 "rlimit_memory_data_hard": 2147483647,
596 "rlimit_memory_data_soft": 2147483647,
597 "rlimit_memory_locked_hard": 65536,
598 "rlimit_memory_locked_soft": 65536,
599 "rlimit_memory_rss_hard": 2147483647,
600 "rlimit_memory_rss_soft": 2147483647,
601 "rlimit_memory_stack_hard": 2147483647,
602 "rlimit_memory_stack_soft": 8388608,
603 "rlimit_memory_vms_hard": 2147483647,
604 "rlimit_memory_vms_soft": 2147483647,
605 "rlimit_nice_priority_hard": 0,
606 "rlimit_nice_priority_soft": 0,
607 "rlimit_num_fds_hard": 4096,
608 "rlimit_num_fds_soft": 1024,
609 "rlimit_realtime_priority_hard": 0,
610 "rlimit_realtime_priority_soft": 0,
611 "rlimit_signals_pending_hard": 78994,
612 "rlimit_signals_pending_soft": 78994,
613 "signals_pending": 0,
614 "voluntary_context_switches": 42,
615 "write_bytes": 106496,
616 "write_count": 35,
617 },
618 time.Unix(0, 1517620624000000000),
619 ),
620 ),
621 },
622 err: nil,
623 },
624 }
625
626 func TestParser(t *testing.T) {
627 for _, tt := range ptests {
628 t.Run(tt.name, func(t *testing.T) {
629 handler := NewMetricHandler()
630 parser := NewParser(handler)
631 parser.SetTimeFunc(DefaultTime)
632 if tt.timeFunc != nil {
633 parser.SetTimeFunc(tt.timeFunc)
634 }
635
636 metrics, err := parser.Parse(tt.input)
637 if (err != nil) != (tt.err != nil) {
638 t.Errorf("unexpected error difference: %v, want = %v", err, tt.err)
639 return
640 } else if tt.err != nil && err.Error() != tt.err.Error() {
641 t.Errorf("unexpected error difference: %v, want = %v", err, tt.err)
642 }
643
644 if got, want := len(metrics), len(tt.metrics); got != want {
645 t.Errorf("unexpected metric length difference: %d, want = %d", got, want)
646 }
647
648 for i, expected := range tt.metrics {
649 RequireMetricEqual(t, expected, metrics[i])
650 }
651 })
652 }
653 }
654
655 func BenchmarkParser(b *testing.B) {
656 for _, tt := range ptests {
657 b.Run(tt.name, func(b *testing.B) {
658 handler := NewMetricHandler()
659 parser := NewParser(handler)
660 for n := 0; n < b.N; n++ {
661 metrics, err := parser.Parse(tt.input)
662 _ = err
663 _ = metrics
664 }
665 })
666 }
667 }
668
669 func TestStreamParser(t *testing.T) {
670 for _, tt := range ptests {
671 t.Run(tt.name, func(t *testing.T) {
672 r := bytes.NewBuffer(tt.input)
673 parser := NewStreamParser(r)
674 parser.SetTimeFunc(DefaultTime)
675 if tt.timeFunc != nil {
676 parser.SetTimeFunc(tt.timeFunc)
677 }
678
679 var i int
680 for {
681 m, err := parser.Next()
682 if err != nil {
683 if err == EOF {
684 break
685 }
686 if (err != nil) == (tt.err != nil) && err.Error() != tt.err.Error() {
687 t.Errorf("unexpected error difference: %v, want = %v", err, tt.err)
688 }
689 break
690 }
691
692 RequireMetricEqual(t, tt.metrics[i], m)
693 i++
694 }
695 })
696 }
697 }
698
699 func TestSeriesParser(t *testing.T) {
700 var tests = []struct {
701 name string
702 input []byte
703 timeFunc func() time.Time
704 metrics []Metric
705 err error
706 }{
707 {
708 name: "empty",
709 input: []byte(""),
710 metrics: []Metric{},
711 },
712 {
713 name: "minimal",
714 input: []byte("cpu"),
715 metrics: []Metric{
716 MustMetric(
717 New(
718 "cpu",
719 map[string]string{},
720 map[string]interface{}{},
721 time.Unix(0, 0),
722 ),
723 ),
724 },
725 },
726 {
727 name: "tags",
728 input: []byte("cpu,a=x,b=y"),
729 metrics: []Metric{
730 MustMetric(
731 New(
732 "cpu",
733 map[string]string{
734 "a": "x",
735 "b": "y",
736 },
737 map[string]interface{}{},
738 time.Unix(0, 0),
739 ),
740 ),
741 },
742 },
743 {
744 name: "missing tag value",
745 input: []byte("cpu,a="),
746 metrics: []Metric{},
747 err: &ParseError{
748 Offset: 6,
749 LineNumber: 1,
750 Column: 7,
751 msg: ErrTagParse.Error(),
752 buf: "cpu,a=",
753 },
754 },
755 }
756 for _, tt := range tests {
757 t.Run(tt.name, func(t *testing.T) {
758 handler := NewMetricHandler()
759 parser := NewSeriesParser(handler)
760 if tt.timeFunc != nil {
761 parser.SetTimeFunc(tt.timeFunc)
762 }
763
764 metrics, err := parser.Parse(tt.input)
765
766 if (err != nil) != (tt.err != nil) {
767 t.Errorf("unexpected error difference: %v, want = %v", err, tt.err)
768 return
769 } else if tt.err != nil && err.Error() != tt.err.Error() {
770 t.Errorf("unexpected error difference: %v, want = %v", err, tt.err)
771 }
772
773 if got, want := len(metrics), len(tt.metrics); got != want {
774 t.Errorf("unexpected metric length difference: %d, want = %d", got, want)
775 }
776
777 for i, expected := range tt.metrics {
778 if got, want := metrics[i].Name(), expected.Name(); got != want {
779 t.Errorf("unexpected metric name difference: %v, want = %v", got, want)
780 }
781 if got, want := len(metrics[i].TagList()), len(expected.TagList()); got != want {
782 t.Errorf("unexpected tag length difference: %d, want = %d", got, want)
783 break
784 }
785
786 got := metrics[i].TagList()
787 want := expected.TagList()
788 for i := range got {
789 if got[i].Key != want[i].Key {
790 t.Errorf("unexpected tag key difference: %v, want = %v", got[i].Key, want[i].Key)
791 }
792 if got[i].Value != want[i].Value {
793 t.Errorf("unexpected tag key difference: %v, want = %v", got[i].Value, want[i].Value)
794 }
795 }
796 }
797 })
798 }
799 }
800
801 func TestParserErrorString(t *testing.T) {
802 var ptests = []struct {
803 name string
804 input []byte
805 errString string
806 }{
807 {
808 name: "multiple line error",
809 input: []byte("cpu value=42\ncpu value=invalid\ncpu value=42"),
810 errString: `metric parse error: expected field at 2:11: "cpu value=invalid"`,
811 },
812 {
813 name: "handler error",
814 input: []byte("cpu value=9223372036854775808i\ncpu value=42"),
815 errString: `metric parse error: value out of range at 1:31: "cpu value=9223372036854775808i"`,
816 },
817 {
818 name: "buffer too long",
819 input: []byte("cpu " + strings.Repeat("ab", maxErrorBufferSize) + "=invalid\ncpu value=42"),
820 errString: "metric parse error: expected field at 1:2054: \"cpu " + strings.Repeat("ab", maxErrorBufferSize)[:maxErrorBufferSize-4] + "...\"",
821 },
822 {
823 name: "multiple line error",
824 input: []byte("cpu value=42\ncpu value=invalid\ncpu value=42\ncpu value=invalid"),
825 errString: `metric parse error: expected field at 2:11: "cpu value=invalid"`,
826 },
827 }
828
829 for _, tt := range ptests {
830 t.Run(tt.name, func(t *testing.T) {
831 handler := NewMetricHandler()
832 parser := NewParser(handler)
833
834 _, err := parser.Parse(tt.input)
835 if err.Error() != tt.errString {
836 t.Errorf("unexpected error difference: %v, want = %v", err.Error(), tt.errString)
837 }
838 })
839 }
840 }
841
842 func TestStreamParserErrorString(t *testing.T) {
843 var ptests = []struct {
844 name string
845 input []byte
846 errs []string
847 }{
848 {
849 name: "multiple line error",
850 input: []byte("cpu value=42\ncpu value=invalid\ncpu value=42"),
851 errs: []string{
852 `metric parse error: expected field at 2:11: "cpu value="`,
853 },
854 },
855 {
856 name: "handler error",
857 input: []byte("cpu value=9223372036854775808i\ncpu value=42"),
858 errs: []string{
859 `metric parse error: value out of range at 1:31: "cpu value=9223372036854775808i"`,
860 },
861 },
862 {
863 name: "buffer too long",
864 input: []byte("cpu " + strings.Repeat("ab", maxErrorBufferSize) + "=invalid\ncpu value=42"),
865 errs: []string{
866 "metric parse error: expected field at 1:2054: \"cpu " + strings.Repeat("ab", maxErrorBufferSize)[:maxErrorBufferSize-4] + "...\"",
867 },
868 },
869 {
870 name: "multiple errors",
871 input: []byte("foo value=1asdf2.0\nfoo value=2.0\nfoo value=3asdf2.0\nfoo value=4.0"),
872 errs: []string{
873 `metric parse error: expected field at 1:12: "foo value=1"`,
874 `metric parse error: expected field at 3:12: "foo value=3"`,
875 },
876 },
877 }
878
879 for _, tt := range ptests {
880 t.Run(tt.name, func(t *testing.T) {
881 parser := NewStreamParser(bytes.NewBuffer(tt.input))
882
883 var errs []error
884 for i := 0; i < 20; i++ {
885 _, err := parser.Next()
886 if err == EOF {
887 break
888 }
889
890 if err != nil {
891 errs = append(errs, err)
892 }
893 }
894
895 if got, want := len(errs), len(tt.errs); got != want {
896 t.Errorf("unexpected error length difference: %d, want = %d", got, want)
897 }
898
899 for i, err := range errs {
900 if err.Error() != tt.errs[i] {
901 t.Errorf("unexpected error difference: %v, want = %v", err.Error(), tt.errs[i])
902 }
903 }
904 })
905 }
906 }
907
908 // RequireMetricEqual halts the test with an error if the metrics are not
909 // equal.
910 func RequireMetricEqual(t *testing.T, expected, actual Metric) {
911 t.Helper()
912
913 var lhs, rhs *metricDiff
914 if expected != nil {
915 lhs = newMetricDiff(expected)
916 }
917 if actual != nil {
918 rhs = newMetricDiff(actual)
919 }
920
921 if !reflect.DeepEqual(lhs, rhs) {
922 t.Fatalf("Metric %v, want=%v", rhs, lhs)
923 }
924 }
925
926 type metricDiff struct {
927 Measurement string
928 Tags []*Tag
929 Fields []*Field
930 Time time.Time
931 }
932
933 func newMetricDiff(metric Metric) *metricDiff {
934 if metric == nil {
935 return nil
936 }
937
938 m := &metricDiff{}
939 m.Measurement = metric.Name()
940 m.Tags = append(m.Tags, metric.TagList()...)
941 m.Fields = append(m.Fields, metric.FieldList()...)
942
943 sort.Slice(m.Tags, func(i, j int) bool {
944 return m.Tags[i].Key < m.Tags[j].Key
945 })
946
947 sort.Slice(m.Fields, func(i, j int) bool {
948 return m.Fields[i].Key < m.Fields[j].Key
949 })
950
951 m.Time = metric.Time()
952 return m
953 }
0 package protocol
1
2 import (
3 "fmt"
4 "time"
5 )
6
7 // Write writes out data to a line protocol encoder. Note: it does no sorting. It assumes you have done your own sorting for tagValues
8 func (e *Encoder) Write(name []byte, ts time.Time, tagKeys, tagVals, fieldKeys [][]byte, fieldVals []interface{}) (int, error) {
9 e.header = e.header[:0]
10 if len(name) == 0 || name[len(name)-1] == byte('\\') {
11 return 0, ErrInvalidName
12 }
13 nameEscapeBytes(&e.header, name)
14 for i := range tagKeys {
15 // Some keys and values are not encodeable as line protocol, such as
16 // those with a trailing '\' or empty strings.
17 if len(tagKeys[i]) == 0 || len(tagVals[i]) == 0 || tagKeys[i][len(tagKeys[i])-1] == byte('\\') {
18 if e.failOnFieldError {
19 return 0, fmt.Errorf("invalid field: key \"%s\", val \"%s\"", tagKeys[i], tagVals[i])
20 }
21 continue
22 }
23 e.header = append(e.header, byte(','))
24 escapeBytes(&e.header, tagKeys[i])
25 e.header = append(e.header, byte('='))
26 escapeBytes(&e.header, tagVals[i])
27 }
28 e.header = append(e.header, byte(' '))
29 e.buildFooter(ts)
30
31 i := 0
32 totalWritten := 0
33 pairsLen := 0
34 firstField := true
35 for i := range fieldKeys {
36 e.pair = e.pair[:0]
37 key := fieldKeys[i]
38 if len(key) == 0 || key[len(key)-1] == byte('\\') {
39 if e.failOnFieldError {
40 return 0, &FieldError{"invalid field key"}
41 }
42 continue
43 }
44 escapeBytes(&e.pair, key)
45 // Some keys are not encodeable as line protocol, such as those with a
46 // trailing '\' or empty strings.
47 e.pair = append(e.pair, byte('='))
48 err := e.buildFieldVal(fieldVals[i])
49 if err != nil {
50 if e.failOnFieldError {
51 return 0, err
52 }
53 continue
54 }
55
56 bytesNeeded := len(e.header) + pairsLen + len(e.pair) + len(e.footer)
57
58 // Additional length needed for field separator `,`
59 if !firstField {
60 bytesNeeded++
61 }
62
63 if e.maxLineBytes > 0 && bytesNeeded > e.maxLineBytes {
64 // Need at least one field per line
65 if firstField {
66 return 0, ErrNeedMoreSpace
67 }
68
69 i, err = e.w.Write(e.footer)
70 if err != nil {
71 return 0, err
72 }
73 totalWritten += i
74
75 bytesNeeded = len(e.header) + len(e.pair) + len(e.footer)
76
77 if e.maxLineBytes > 0 && bytesNeeded > e.maxLineBytes {
78 return 0, ErrNeedMoreSpace
79 }
80
81 i, err = e.w.Write(e.header)
82 if err != nil {
83 return 0, err
84 }
85 totalWritten += i
86
87 i, err = e.w.Write(e.pair)
88 if err != nil {
89 return 0, err
90 }
91 totalWritten += i
92
93 pairsLen += len(e.pair)
94 firstField = false
95 continue
96 }
97
98 if firstField {
99 i, err = e.w.Write(e.header)
100 if err != nil {
101 return 0, err
102 }
103 totalWritten += i
104
105 } else {
106 i, err = e.w.Write(comma)
107 if err != nil {
108 return 0, err
109 }
110 totalWritten += i
111
112 }
113
114 e.w.Write(e.pair)
115
116 pairsLen += len(e.pair)
117 firstField = false
118 }
119
120 if firstField {
121 return 0, ErrNoFields
122 }
123 i, err := e.w.Write(e.footer)
124 if err != nil {
125 return 0, err
126 }
127 totalWritten += i
128 return totalWritten, nil
129 }