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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 91a4bfe02680f2079998d36ab098c5498bdaea04
4
- data.tar.gz: 234135f11479a6d364d1c5d0f58d90cfe7d72717
3
+ metadata.gz: 08a2d8a17b61a68a7b759d42d2c35c655660940e
4
+ data.tar.gz: 2e456086c9216056e9e4e7fe749521fa713ca2f5
5
5
  SHA512:
6
- metadata.gz: a1e3df653dca491e163824f57e6d3d0932314ef59b2cc0cf36caa77f9007df624b183cd2b700caf5c02bd6a477322d136e44c14bed15f44c8c201eb9fb43838e
7
- data.tar.gz: d20de3a18a7507fb5532480cd51704e23e79740d12a58bde482824095740681b10ede39a9e0611e878bba6e609078dc406e5e983b5ea5160e83b0632a4c83542
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
@@ -1,6 +1,6 @@
1
1
  module Fluent
2
2
  module BigQueryPlugin
3
- VERSION = "0.0.4"
3
+ VERSION = "0.0.5"
4
4
  end
5
5
  end
6
6
 
@@ -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 format(value)
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 format(value)
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 format(value)
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 format(value)
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 format(value)
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[field['name']] = field_schema
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 format(record)
457
+ def format_one(record)
431
458
  out = {}
432
459
  @fields.each do |key, schema|
433
460
  value = record[key]
434
- next if value.nil? # field does not exists, or null value
435
- out[key] = schema.format(value)
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
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-12 00:00:00.000000000 Z
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: