fluent-plugin-bigquery 0.0.4 → 0.0.5
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 +4 -4
- data/README.md +1 -1
- data/lib/fluent/plugin/bigquery/version.rb +1 -1
- data/lib/fluent/plugin/out_bigquery.rb +42 -14
- data/test/plugin/test_out_bigquery.rb +78 -0
- data/test/plugin/testdata/sudo.schema +27 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 08a2d8a17b61a68a7b759d42d2c35c655660940e
|
4
|
+
data.tar.gz: 2e456086c9216056e9e4e7fe749521fa713ca2f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fac063ee55019a58253ec7a4a0de9ae973c3e9d6814ee74455a010d0ed84382200aa0e9f1bfe9cbc45856c6756cd34ea85d85071156020acf27441a4ee61a2a4
|
7
|
+
data.tar.gz: d2a3365ca5515b02a35f3cfaae8f7a867b4e71f241441c08d4b71f6b0c41954943aa4161be0f67b2aa77ac41c9ab785f329d6eef1c37b6ddbc26a1e7352945d2
|
data/README.md
CHANGED
@@ -236,7 +236,7 @@ With this configuration, flushing will be done in 0.25 seconds after record inpu
|
|
236
236
|
* support Load API
|
237
237
|
* with automatically configured flush/buffer options
|
238
238
|
* support optional data fields
|
239
|
-
* support NULLABLE/REQUIRED/REPEATED field options
|
239
|
+
* support NULLABLE/REQUIRED/REPEATED field options in field list style of configuration
|
240
240
|
* OAuth installed application credentials support
|
241
241
|
* Google API discovery expiration
|
242
242
|
* Error classes
|
@@ -145,7 +145,7 @@ module Fluent
|
|
145
145
|
|
146
146
|
@tablelist = @tables ? @tables.split(',') : [@table]
|
147
147
|
|
148
|
-
@fields = RecordSchema.new
|
148
|
+
@fields = RecordSchema.new('record')
|
149
149
|
if @schema_path
|
150
150
|
@fields.load_schema(JSON.parse(File.read(@schema_path)))
|
151
151
|
end
|
@@ -317,7 +317,30 @@ module Fluent
|
|
317
317
|
# end
|
318
318
|
|
319
319
|
class FieldSchema
|
320
|
+
def initialize(name, mode = :nullable)
|
321
|
+
unless [:nullable, :required, :repeated].include?(mode)
|
322
|
+
raise ConfigError, "Unrecognized mode for #{name}: #{mode}"
|
323
|
+
end
|
324
|
+
|
325
|
+
@name = name
|
326
|
+
@mode = mode
|
327
|
+
end
|
328
|
+
|
329
|
+
attr_reader :name, :mode
|
330
|
+
|
320
331
|
def format(value)
|
332
|
+
case @mode
|
333
|
+
when :nullable
|
334
|
+
format_one(value) unless value.nil?
|
335
|
+
when :required
|
336
|
+
raise "Required field #{name} cannot be null" if value.nil?
|
337
|
+
format_one(value)
|
338
|
+
when :repeated
|
339
|
+
value.nil? ? [] : value.map {|v| format_one(v) }
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def format_one(value)
|
321
344
|
raise NotImplementedError, "Must implement in a subclass"
|
322
345
|
end
|
323
346
|
end
|
@@ -327,7 +350,7 @@ module Fluent
|
|
327
350
|
:string
|
328
351
|
end
|
329
352
|
|
330
|
-
def
|
353
|
+
def format_one(value)
|
331
354
|
value.to_s
|
332
355
|
end
|
333
356
|
end
|
@@ -337,7 +360,7 @@ module Fluent
|
|
337
360
|
:integer
|
338
361
|
end
|
339
362
|
|
340
|
-
def
|
363
|
+
def format_one(value)
|
341
364
|
value.to_i
|
342
365
|
end
|
343
366
|
end
|
@@ -347,7 +370,7 @@ module Fluent
|
|
347
370
|
:float
|
348
371
|
end
|
349
372
|
|
350
|
-
def
|
373
|
+
def format_one(value)
|
351
374
|
value.to_f
|
352
375
|
end
|
353
376
|
end
|
@@ -357,7 +380,7 @@ module Fluent
|
|
357
380
|
:boolean
|
358
381
|
end
|
359
382
|
|
360
|
-
def
|
383
|
+
def format_one(value)
|
361
384
|
!!value
|
362
385
|
end
|
363
386
|
end
|
@@ -367,7 +390,7 @@ module Fluent
|
|
367
390
|
:timestamp
|
368
391
|
end
|
369
392
|
|
370
|
-
def
|
393
|
+
def format_one(value)
|
371
394
|
value
|
372
395
|
end
|
373
396
|
end
|
@@ -382,7 +405,8 @@ module Fluent
|
|
382
405
|
:record => RecordSchema
|
383
406
|
}.freeze
|
384
407
|
|
385
|
-
def initialize
|
408
|
+
def initialize(name, mode = :nullable)
|
409
|
+
super(name, mode)
|
386
410
|
@fields = {}
|
387
411
|
end
|
388
412
|
|
@@ -398,12 +422,15 @@ module Fluent
|
|
398
422
|
schema.each do |field|
|
399
423
|
raise ConfigError, 'field must have type' unless field.key?('type')
|
400
424
|
|
425
|
+
name = field['name']
|
426
|
+
mode = (field['mode'] || 'nullable').downcase.to_sym
|
427
|
+
|
401
428
|
type = field['type'].downcase.to_sym
|
402
429
|
field_schema_class = FIELD_TYPES[type]
|
403
430
|
raise ConfigError, "Invalid field type: #{field['type']}" unless field_schema_class
|
404
431
|
|
405
|
-
field_schema = field_schema_class.new
|
406
|
-
@fields[
|
432
|
+
field_schema = field_schema_class.new(name, mode)
|
433
|
+
@fields[name] = field_schema
|
407
434
|
if type == :record
|
408
435
|
raise ConfigError, "record field must have fields" unless field.key?('fields')
|
409
436
|
field_schema.load_schema(field['fields'])
|
@@ -423,16 +450,17 @@ module Fluent
|
|
423
450
|
else
|
424
451
|
schema = FIELD_TYPES[type]
|
425
452
|
raise ConfigError, "[Bug] Invalid field type #{type}" unless schema
|
426
|
-
@fields[name] = schema.new
|
453
|
+
@fields[name] = schema.new(name)
|
427
454
|
end
|
428
455
|
end
|
429
456
|
|
430
|
-
def
|
457
|
+
def format_one(record)
|
431
458
|
out = {}
|
432
459
|
@fields.each do |key, schema|
|
433
460
|
value = record[key]
|
434
|
-
|
435
|
-
|
461
|
+
formatted = schema.format(value)
|
462
|
+
next if formatted.nil? # field does not exists, or null value
|
463
|
+
out[key] = formatted
|
436
464
|
end
|
437
465
|
out
|
438
466
|
end
|
@@ -440,7 +468,7 @@ module Fluent
|
|
440
468
|
private
|
441
469
|
def register_record_field(name)
|
442
470
|
if !@fields.key?(name)
|
443
|
-
@fields[name] = RecordSchema.new
|
471
|
+
@fields[name] = RecordSchema.new(name)
|
444
472
|
else
|
445
473
|
unless @fields[name].kind_of?(RecordSchema)
|
446
474
|
raise ConfigError, "field #{name} is required to be a record but already registered as #{@field[name]}"
|
@@ -307,6 +307,84 @@ class BigQueryOutputTest < Test::Unit::TestCase
|
|
307
307
|
assert_equal expected, MessagePack.unpack(buf)
|
308
308
|
end
|
309
309
|
|
310
|
+
def test_format_repeated_field_with_schema
|
311
|
+
now = Time.now
|
312
|
+
input = [
|
313
|
+
now,
|
314
|
+
{
|
315
|
+
"tty" => nil,
|
316
|
+
"pwd" => "/home/yugui",
|
317
|
+
"user" => "fluentd",
|
318
|
+
"argv" => %w[ tail -f /var/log/fluentd/fluentd.log ]
|
319
|
+
}
|
320
|
+
]
|
321
|
+
expected = {
|
322
|
+
"json" => {
|
323
|
+
"time" => now.to_i,
|
324
|
+
"pwd" => "/home/yugui",
|
325
|
+
"user" => "fluentd",
|
326
|
+
"argv" => %w[ tail -f /var/log/fluentd/fluentd.log ]
|
327
|
+
}
|
328
|
+
}
|
329
|
+
|
330
|
+
driver = create_driver(<<-CONFIG)
|
331
|
+
table foo
|
332
|
+
email foo@bar.example
|
333
|
+
private_key_path /path/to/key
|
334
|
+
project yourproject_id
|
335
|
+
dataset yourdataset_id
|
336
|
+
|
337
|
+
time_format %s
|
338
|
+
time_field time
|
339
|
+
|
340
|
+
schema_path #{File.join(File.dirname(__FILE__), "testdata", "sudo.schema")}
|
341
|
+
field_integer time
|
342
|
+
CONFIG
|
343
|
+
mock_client(driver) do |expect|
|
344
|
+
expect.discovered_api("bigquery", "v2") { stub! }
|
345
|
+
end
|
346
|
+
driver.instance.start
|
347
|
+
buf = driver.instance.format_stream("my.tag", [input])
|
348
|
+
driver.instance.shutdown
|
349
|
+
|
350
|
+
assert_equal expected, MessagePack.unpack(buf)
|
351
|
+
end
|
352
|
+
|
353
|
+
def test_empty_value_in_required
|
354
|
+
now = Time.now
|
355
|
+
input = [
|
356
|
+
now,
|
357
|
+
{
|
358
|
+
"tty" => "pts/1",
|
359
|
+
"pwd" => "/home/yugui",
|
360
|
+
"user" => nil,
|
361
|
+
"argv" => %w[ tail -f /var/log/fluentd/fluentd.log ]
|
362
|
+
}
|
363
|
+
]
|
364
|
+
|
365
|
+
driver = create_driver(<<-CONFIG)
|
366
|
+
table foo
|
367
|
+
email foo@bar.example
|
368
|
+
private_key_path /path/to/key
|
369
|
+
project yourproject_id
|
370
|
+
dataset yourdataset_id
|
371
|
+
|
372
|
+
time_format %s
|
373
|
+
time_field time
|
374
|
+
|
375
|
+
schema_path #{File.join(File.dirname(__FILE__), "testdata", "sudo.schema")}
|
376
|
+
field_integer time
|
377
|
+
CONFIG
|
378
|
+
mock_client(driver) do |expect|
|
379
|
+
expect.discovered_api("bigquery", "v2") { stub! }
|
380
|
+
end
|
381
|
+
driver.instance.start
|
382
|
+
assert_raises(RuntimeError, /cannot be null/) do
|
383
|
+
driver.instance.format_stream("my.tag", [input])
|
384
|
+
end
|
385
|
+
driver.instance.shutdown
|
386
|
+
end
|
387
|
+
|
310
388
|
def test_write
|
311
389
|
entry = {"json" => {"a" => "b"}}, {"json" => {"b" => "c"}}
|
312
390
|
driver = create_driver(CONFIG)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"name": "time",
|
4
|
+
"type": "TIMESTAMP",
|
5
|
+
"mode": "REQUIRED"
|
6
|
+
},
|
7
|
+
{
|
8
|
+
"name": "tty",
|
9
|
+
"type": "STRING",
|
10
|
+
"mode": "NULLABLE"
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"name": "pwd",
|
14
|
+
"type": "STRING",
|
15
|
+
"mode": "REQUIRED"
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"name": "user",
|
19
|
+
"type": "STRING",
|
20
|
+
"mode": "REQUIRED"
|
21
|
+
},
|
22
|
+
{
|
23
|
+
"name": "argv",
|
24
|
+
"type": "STRING",
|
25
|
+
"mode": "REPEATED"
|
26
|
+
}
|
27
|
+
]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fluent-plugin-bigquery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TAGOMORI Satoshi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -143,6 +143,7 @@ files:
|
|
143
143
|
- test/helper.rb
|
144
144
|
- test/plugin/test_out_bigquery.rb
|
145
145
|
- test/plugin/testdata/apache.schema
|
146
|
+
- test/plugin/testdata/sudo.schema
|
146
147
|
- test/test_load_request_body_wrapper.rb
|
147
148
|
homepage: https://github.com/tagomoris/fluent-plugin-bigquery
|
148
149
|
licenses:
|
@@ -172,5 +173,6 @@ test_files:
|
|
172
173
|
- test/helper.rb
|
173
174
|
- test/plugin/test_out_bigquery.rb
|
174
175
|
- test/plugin/testdata/apache.schema
|
176
|
+
- test/plugin/testdata/sudo.schema
|
175
177
|
- test/test_load_request_body_wrapper.rb
|
176
178
|
has_rdoc:
|