fluent-plugin-bigquery 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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: