influxdb-lineprotocol-parser 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8e81800340bcf80271e56f5c19d03ea4cd8b9535e8d0fd5bd86e605f3dae124
4
- data.tar.gz: 1baa9ee265fc57e8b7bf987b8314c9305c8ab3f0240066ea9db2d901b425a35d
3
+ metadata.gz: a8e433f4f34e310f1886a551df2e5673f8f3ca4831f786cb22bb490b31740dc5
4
+ data.tar.gz: 5fd20ecf8b09f2fa682fff68dad78fdecd6c47c87f9cbe0d887ba57d4978565b
5
5
  SHA512:
6
- metadata.gz: 3655611e6edbfce8c960707bf72f1f3972a7d8ced12488280a088646145551e5668329766143df26f4258acc17ffa17233e7ea9f802240d4a579d01b99e4b55f
7
- data.tar.gz: ba6b7f5b37fcdc32f4e46a51d4fb7ed92b34921cb0c173ba80664a838dafef33008423745b21193592f483161edb66e916116dd353d7234f53d4db4932e05f2d
6
+ metadata.gz: e0273635beaf425e9d284219ac2e513bb3bc467fd10f65e6e9600e368743bfa26ac5e22edba50a50778e20313355dd3a1c79b9ecc6e89b8157626c3db3efe627
7
+ data.tar.gz: c8e24fde968761c85a6eecaa6d6a51bde1976a950b167bed45b53636e70644d5a18f9394bf857473d813df9bfa7915bd2f62a00d8e4f8257ec1173ce32b453cf
@@ -17,7 +17,7 @@ require 'logger'
17
17
  ##
18
18
  # Extension to InfluxDB module.
19
19
  #
20
- module InfluxDBExt
20
+ module InfluxDB
21
21
  ##
22
22
  # Line Protocol module.
23
23
  #
@@ -27,9 +27,15 @@ module InfluxDBExt
27
27
  # Line Protocol parser.
28
28
  #
29
29
  class Parser
30
- def initialize(logger: nil, log_level: :warn)
30
+ def initialize(logger: nil, log_level: :warn, escapes: nil)
31
31
  @log = logger || ::Logger.new(STDERR)
32
32
  @log.level = log_level
33
+ case escapes
34
+ when :compat
35
+ @unescapes = InfluxDB::LineProtocol::CompatUnescapes.new
36
+ else
37
+ @unescapes = InfluxDB::LineProtocol::Unescapes.new
38
+ end
33
39
  enter_initial
34
40
  end
35
41
 
@@ -40,9 +46,11 @@ module InfluxDBExt
40
46
  #
41
47
  # If block is not given, returns a list of points in data.
42
48
  #
49
+ # The data can be a String, or a single Integer or an Array of Integers.
50
+ # The Integers are assumed to be UTF-8 bytes.
51
+ #
43
52
  def each_point(data)
44
- # TODO: support byte arrays (client does not have to ensure that only complete UTF-8 characters are passed)
45
- buf = data.to_s.encode(UTF_8).bytes.freeze
53
+ buf = bytes(data)
46
54
  i = 0
47
55
  len = buf.size
48
56
 
@@ -82,14 +90,14 @@ module InfluxDBExt
82
90
  BACKSLASH = 92
83
91
  COMMA = 44
84
92
  EQUALS = 61
85
- HASH = 23
93
+ HASH = 35
86
94
  NEWLINE = 10
87
95
  NULL = 0
88
96
  SPACE = 32
89
97
  TAB = 9
90
98
 
91
99
  # Start (and end) marker of a string field value (not special anywhere else)
92
- QUOTATION_MARK = 22
100
+ QUOTATION_MARK = 34
93
101
 
94
102
  # Start markers of a numeric field value (not special anywhere else)
95
103
  PLUS_SIGN = 43
@@ -117,7 +125,7 @@ module InfluxDBExt
117
125
  when COMMA
118
126
  @log.error "initial: missing measurement"
119
127
  @state = :invalid
120
- invalid(buf, i, len)
128
+ i + 1
121
129
  when HASH # comment
122
130
  @state = :comment
123
131
  i + 1
@@ -139,21 +147,21 @@ module InfluxDBExt
139
147
  i += 1
140
148
  else
141
149
  c = buf[i]
150
+ raise "unsupported input type" unless c.is_a? Integer
142
151
  case c
143
152
  when BACKSLASH
144
153
  @escaped = true
145
154
  i += 1
146
155
  when COMMA # start of tag set.
147
- @point = {series: decode(buf[start..i-1]), tags: {}}
156
+ @point = {series: decode(buf, start, i-1), tags: {}, values: {}}
148
157
  @state = :tag_key
149
158
  return i+1
150
159
  when NEWLINE
151
160
  @log.error("measurement: missing fields")
152
- # no need to go via :invalid; already at newline
153
- enter_initial
154
- return i+1
161
+ @state = :invalid
162
+ return i
155
163
  when SPACE # start of field set
156
- @point = {series: decode(buf[start..i-1]), values: {}}
164
+ @point = {series: decode(buf, start, i-1), values: {}}
157
165
  @state = :field_key
158
166
  i, _ = whitespace(buf, i + 1, len)
159
167
  return i
@@ -176,23 +184,24 @@ module InfluxDBExt
176
184
  i += 1
177
185
  else
178
186
  c = buf[i]
187
+ raise "unsupported input type" unless c.is_a? Integer
179
188
  case c
180
189
  when BACKSLASH
181
190
  @escaped = true
182
191
  i += 1
183
192
  when EQUALS
184
- @key = decode(buf[start..i-1])
193
+ @key = decode(buf, start, i-1)
185
194
  if @key == ""
186
195
  @log.error("tag_key: empty key")
187
196
  @state = :invalid
188
- return invalid(buf, i, len)
197
+ return i
189
198
  end
190
199
  @state = :tag_value
191
200
  return i+1
192
201
  when NEWLINE
193
202
  @log.error("tag key: newline")
194
- enter_initial
195
- return i+1
203
+ @state = :invalid
204
+ return i
196
205
  else
197
206
  i += 1
198
207
  end
@@ -212,21 +221,22 @@ module InfluxDBExt
212
221
  i += 1
213
222
  else
214
223
  c = buf[i]
224
+ raise "unsupported input type" unless c.is_a? Integer
215
225
  case c
216
226
  when BACKSLASH
217
227
  @escaped = true
218
228
  i += 1
219
229
  when COMMA
220
- @point[:tags][@key] = decode(buf[start..i-1])
230
+ @point[:tags][@key] = decode(buf, start, i-1)
221
231
  @key = nil
222
232
  @state = :tag_key
223
233
  return i+1
224
234
  when NEWLINE
225
235
  @log.error("tag value: newline")
226
- enter_initial
227
- return i+1
236
+ @state = :invalid
237
+ return i
228
238
  when SPACE
229
- @point[:tags][@key] = decode(buf[start..i-1])
239
+ @point[:tags][@key] = decode(buf, start, i-1)
230
240
  @key = nil
231
241
  @state = :field_key
232
242
  i, _ = whitespace(buf, i + 1, len)
@@ -250,23 +260,24 @@ module InfluxDBExt
250
260
  i += 1
251
261
  else
252
262
  c = buf[i]
263
+ raise "unsupported input type" unless c.is_a? Integer
253
264
  case c
254
265
  when BACKSLASH
255
266
  @escaped = true
256
267
  i += 1
257
268
  when EQUALS
258
- @key = decode(buf[start..i-1])
269
+ @key = decode(buf, start, i-1)
259
270
  if @key == ""
260
271
  @log.error("field key: empty key")
261
272
  @state = :invalid
262
- return invalid(buf, i + 1, len)
273
+ return i
263
274
  end
264
275
  @state = :field_value
265
276
  return i+1
266
277
  when NEWLINE
267
278
  @log.error("field key: newline")
268
- enter_initial
269
- return i+1
279
+ @state = :invalid
280
+ return i
270
281
  else
271
282
  i += 1
272
283
  end
@@ -283,6 +294,7 @@ module InfluxDBExt
283
294
  return len
284
295
  end
285
296
  c = buf[i]
297
+ raise "unsupported input type" unless c.is_a? Integer
286
298
  case c
287
299
  when LATIN_CAPITAL_LETTER_F, LATIN_CAPITAL_LETTER_T, LATIN_SMALL_LETTER_F, LATIN_SMALL_LETTER_T
288
300
  @state = :field_value_boolean
@@ -296,7 +308,7 @@ module InfluxDBExt
296
308
  else
297
309
  @log.error("field value: invalid")
298
310
  @state = :invalid
299
- invalid(buf, i, len)
311
+ i
300
312
  end
301
313
  end
302
314
 
@@ -308,23 +320,24 @@ module InfluxDBExt
308
320
  i += 1
309
321
  else
310
322
  c = buf[i]
323
+ raise "unsupported input type" unless c.is_a? Integer
311
324
  case c
312
325
  when BACKSLASH
313
326
  @escaped = true
314
327
  i += 1
315
328
  when COMMA
316
- value = decode(buf[start..i-1])
329
+ value = decode(buf, start, i-1)
317
330
  if value.nil?
318
331
  @log.error("field value boolean: invalid boolean")
319
332
  @state = :invalid
320
- return invalid(buf, i, len)
333
+ return i
321
334
  end
322
335
  @point[:values][@key] = value
323
336
  @key = nil
324
337
  @state = :field_key
325
338
  return i+1
326
339
  when NEWLINE
327
- value = decode(buf[start..i-1])
340
+ value = decode(buf, start, i-1)
328
341
  if value.nil?
329
342
  @log.error("field value boolean: invalid boolean")
330
343
  enter_initial
@@ -335,11 +348,11 @@ module InfluxDBExt
335
348
  @state = :complete
336
349
  return i+1
337
350
  when SPACE
338
- value = decode(buf[start..i-1])
351
+ value = decode(buf, start, i-1)
339
352
  if value.nil?
340
353
  @log.error("field value boolean: invalid boolean")
341
354
  @state = :invalid
342
- return invalid(buf, i, len)
355
+ return i
343
356
  end
344
357
  @point[:values][@key] = value
345
358
  @key = nil
@@ -365,34 +378,35 @@ module InfluxDBExt
365
378
  i += 1
366
379
  else
367
380
  c = buf[i]
381
+ raise "unsupported input type" unless c.is_a? Integer
368
382
  case c
369
383
  when BACKSLASH
370
384
  @escaped = true
371
385
  i += 1
372
386
  when COMMA
373
- value = decode(buf[start..i-1])
387
+ value = decode(buf, start, i-1)
374
388
  if value.nil?
375
389
  @log.error("field value numeric: invalid number")
376
390
  @state = :invalid
377
- return invalid(buf, i, len)
391
+ return i
378
392
  end
379
393
  @point[:values][@key] = value
380
394
  @key = nil
381
395
  @state = :field_key
382
396
  return i+1
383
397
  when NEWLINE
384
- value = decode(buf[start..i-1])
398
+ value = decode(buf, start, i-1)
385
399
  if value.nil?
386
400
  @log.error("field value numeric: invalid number")
387
401
  @state = :invalid
388
- return invalid(buf, i, len)
402
+ return i
389
403
  end
390
404
  @point[:values][@key] = value
391
405
  @key = nil
392
406
  @state = :complete
393
407
  return i+1
394
408
  when SPACE
395
- value = decode(buf[start..i-1])
409
+ value = decode(buf, start, i-1)
396
410
  if value.nil?
397
411
  @log.error("field value numeric: invalid number")
398
412
  @state = :invalid
@@ -422,16 +436,17 @@ module InfluxDBExt
422
436
  i += 1
423
437
  else
424
438
  c = buf[i]
439
+ raise "unsupported input type" unless c.is_a? Integer
425
440
  case c
426
441
  when BACKSLASH
427
442
  @escaped = true
428
443
  i += 1
429
444
  when QUOTATION_MARK
430
- value = decode(buf[start..i-1])
445
+ value = decode(buf, start, i-1)
431
446
  if value.nil?
432
447
  @log.error("field value string: invalid string")
433
448
  @state = :invalid
434
- return invalid(buf, i, len)
449
+ return i
435
450
  end
436
451
  @point[:values][@key] = value
437
452
  @key = nil
@@ -450,7 +465,9 @@ module InfluxDBExt
450
465
 
451
466
  def field_value_string_end(buf, i, len)
452
467
  if i < len
453
- case buf[i]
468
+ c = buf[i]
469
+ raise "unsupported input type" unless c.is_a? Integer
470
+ case c
454
471
  when COMMA
455
472
  @state = :field_key
456
473
  i + 1
@@ -463,7 +480,7 @@ module InfluxDBExt
463
480
  i
464
481
  else
465
482
  @state = :invalid
466
- invalid(buf, i, len)
483
+ i
467
484
  end
468
485
  else
469
486
  len
@@ -478,16 +495,17 @@ module InfluxDBExt
478
495
  i += 1
479
496
  else
480
497
  c = buf[i]
498
+ raise "unsupported input type" unless c.is_a? Integer
481
499
  case c
482
500
  when BACKSLASH
483
501
  @escaped = true
484
502
  i += 1
485
503
  when NEWLINE
486
- value = decode(buf[start..i-1])
504
+ value = decode(buf, start, i-1)
487
505
  if value.nil?
488
506
  @log.error("timestamp: invalid timestamp")
489
507
  @state = :invalid
490
- return invalid(buf, i, len)
508
+ return i
491
509
  end
492
510
  @point[:timestamp] = value
493
511
  @key = nil
@@ -508,6 +526,7 @@ module InfluxDBExt
508
526
  i = line_end(buf, i, len)
509
527
  if i < len
510
528
  enter_initial
529
+ i += 1
511
530
  end
512
531
  i
513
532
  end
@@ -516,18 +535,19 @@ module InfluxDBExt
516
535
  i = line_end(buf, i, len)
517
536
  if i < len
518
537
  enter_initial
538
+ i += 1
519
539
  end
520
540
  i
521
541
  end
522
542
 
523
543
  # Starting from position i,
524
- # returns the index of the byte that follows next newline.
525
- # Returns len if no such byte is found or it is at the end of buf.
544
+ # returns the index of the newline.
545
+ # Returns len if no such byte is found.
526
546
  def line_end(buf, i, len)
527
547
  while i < len
528
548
  c = buf[i]
549
+ raise "unsupported input type" unless c.is_a? Integer
529
550
  if c == NEWLINE
530
- i += 1
531
551
  return i
532
552
  end
533
553
  i += 1
@@ -541,6 +561,7 @@ module InfluxDBExt
541
561
  def whitespace(buf, i, len)
542
562
  while i < len
543
563
  c = buf[i]
564
+ raise "unsupported input type" unless c.is_a? Integer
544
565
  if c != SPACE && c != TAB && c != NULL
545
566
  return [i, c]
546
567
  end
@@ -549,12 +570,16 @@ module InfluxDBExt
549
570
  [len, nil]
550
571
  end
551
572
 
552
- def decode(buf)
553
- str = @buf.nil? ? string(buf) : string(@buf + buf)
573
+ def decode(buf, start, i)
574
+ str = if @buf.nil?
575
+ (start <= i) ? string(buf[start..i]) : ""
576
+ else
577
+ (start <= i) ? string(@buf + buf[start..i]) : string(@buf)
578
+ end
554
579
  @buf = nil
555
580
  case @state
556
581
  when :measurement
557
- str
582
+ @unescapes.unescape(:measurement, str)
558
583
  when :tag_key
559
584
  str
560
585
  when :tag_value
@@ -595,9 +620,48 @@ module InfluxDBExt
595
620
  end
596
621
  end
597
622
 
623
+ def bytes(data)
624
+ case data
625
+ when nil
626
+ [].freeze
627
+ when Integer
628
+ [data].freeze
629
+ when String
630
+ data.encode(UTF_8).bytes.freeze
631
+ when Array
632
+ data
633
+ end
634
+ end
635
+
598
636
  def string(buf)
599
637
  buf.pack(UTF_8_PACK_FORMAT).force_encoding(UTF_8)
600
638
  end
639
+ end # Parser
640
+
641
+ class CompatUnescapes
642
+ def unescape(field, value)
643
+ case field
644
+ when :measurement
645
+ value.gsub(/\\([, ])/, '\\1')
646
+ # escaped comma anywhere
647
+ # escaped space anywhere
648
+ end
649
+ end
650
+ end
651
+
652
+ class Unescapes
653
+ def unescape(field, value)
654
+ case field
655
+ when :measurement
656
+ # 1. escaped hash, null, or tab at the beginning
657
+ # 2. escaped comma, space, or newline anywhere
658
+ # 3. escaped backslash at the end
659
+ value
660
+ .sub(/^\\([#\0\t])/, '\\1')
661
+ .gsub(/\\([, \n])/, '\\1')
662
+ .sub(/\\\\$/, '\\')
663
+ end
664
+ end
601
665
  end
602
666
  end
603
667
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: influxdb-lineprotocol-parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikko Värri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-15 00:00:00.000000000 Z
11
+ date: 2019-05-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Streaming parser for InfluxDB line protocol.
14
14