fluent-plugin-td 0.10.20 → 0.10.21

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 45aa1dc756f40504543010be6622b6af518fa46c
4
+ data.tar.gz: 72c08e7060e8e6e1fb3af3144a746f92e78f4cf0
5
+ SHA512:
6
+ metadata.gz: 3d494ed57200fb989b24db7552a917f690ce5e96b83a8a108e56d03d2d41274c1a2b37ee610494790ea4f21be41cefcbcd783fad74cd1df03fa5fbd84caa079e
7
+ data.tar.gz: e62a326f85674fe4acdb78f7f9b7df0c27cc45e569b5af171b1754e99204222e8ff0cb286d0a4667ae6c64d83611b4aec742c98a5c95fdc77bf6f3fc5c45b884
data/.travis.yml CHANGED
@@ -6,6 +6,5 @@ rvm:
6
6
 
7
7
  gemfile:
8
8
  - Gemfile
9
- - Gemfile.fluentd.lt.0.10.43
10
9
 
11
10
  script: bundle exec rake test
data/ChangeLog CHANGED
@@ -1,3 +1,9 @@
1
+ Release 0.10.21 - 2014/07/04
2
+
3
+ * Use Yajl for summarizing json
4
+ * Change key_num_limit to 512
5
+
6
+
1
7
  Release 0.10.20 - 2014/06/05
2
8
 
3
9
  * Fix require order bug for td-client-ruby
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.20
1
+ 0.10.21
@@ -37,7 +37,7 @@ module Fluent
37
37
  @key_num_limit = 1024 # Item table default limitation
38
38
  @record_size_limit = 32 * 1024 * 1024 # TODO
39
39
  @empty_gz_data = TreasureData::API.create_empty_gz_data
40
- @user_agent = "fluent-plugin-td-item: 0.10.20".freeze # TODO: automatic increment version
40
+ @user_agent = "fluent-plugin-td-item: 0.10.21".freeze # TODO: automatic increment version
41
41
  end
42
42
 
43
43
  def configure(conf)
@@ -1,358 +1,347 @@
1
1
  require 'td-client'
2
2
 
3
3
  module Fluent
4
+ class TreasureDataLogOutput < BufferedOutput
5
+ Plugin.register_output('tdlog', self)
4
6
 
7
+ IMPORT_SIZE_LIMIT = 32 * 1024 * 1024
5
8
 
6
- class TreasureDataLogOutput < BufferedOutput
7
- Plugin.register_output('tdlog', self)
8
-
9
- IMPORT_SIZE_LIMIT = 32*1024*1024
10
-
11
- class Anonymizer
12
- include Configurable
13
- end
9
+ class Anonymizer
10
+ include Configurable
11
+ end
14
12
 
15
- class RawAnonymizer < Anonymizer
16
- def anonymize(obj)
17
- if obj == nil
18
- nil
19
- elsif obj.is_a?(String)
20
- anonymize_raw obj
21
- elsif obj.is_a?(Numeric)
22
- anonymize_raw obj.to_s
23
- else
24
- # boolean, array, map
25
- anonymize_raw MessagePack.pack(obj)
13
+ class RawAnonymizer < Anonymizer
14
+ def anonymize(obj)
15
+ if obj.nil?
16
+ nil
17
+ elsif obj.is_a?(String)
18
+ anonymize_raw obj
19
+ elsif obj.is_a?(Numeric)
20
+ anonymize_raw obj.to_s
21
+ else
22
+ # boolean, array, map
23
+ anonymize_raw MessagePack.pack(obj)
24
+ end
26
25
  end
27
26
  end
28
- end
29
27
 
30
- class MD5Anonymizer < RawAnonymizer
31
- def anonymize_raw(raw)
32
- Digest::MD5.hexdigest(raw)
28
+ class MD5Anonymizer < RawAnonymizer
29
+ def anonymize_raw(raw)
30
+ Digest::MD5.hexdigest(raw)
31
+ end
33
32
  end
34
- end
35
33
 
36
- class IPXORAnonymizer < RawAnonymizer
37
- config_param :xor_key, :string
34
+ class IPXORAnonymizer < RawAnonymizer
35
+ config_param :xor_key, :string
38
36
 
39
- def configure(conf)
40
- super
37
+ def configure(conf)
38
+ super
41
39
 
42
- a1, a2, a3, a4 = @xor_key.split('.')
43
- @xor_keys = [a1.to_i, a2.to_i, a3.to_i, a4.to_i]
40
+ a1, a2, a3, a4 = @xor_key.split('.')
41
+ @xor_keys = [a1.to_i, a2.to_i, a3.to_i, a4.to_i]
44
42
 
45
- if @xor_keys == [0, 0, 0, 0]
46
- raise ConfigError, "'xor_key' must be IPv4 address"
43
+ if @xor_keys == [0, 0, 0, 0]
44
+ raise ConfigError, "'xor_key' must be IPv4 address"
45
+ end
47
46
  end
48
- end
49
47
 
50
- def anonymize_raw(raw)
51
- m = /\A(\d+)\.(\d+)\.(\d+)\.(\d+)/.match(raw)
52
- return nil unless m
48
+ def anonymize_raw(raw)
49
+ m = /\A(\d+)\.(\d+)\.(\d+)\.(\d+)/.match(raw)
50
+ return nil unless m
53
51
 
54
- k1, k2, k3, k4 = @xor_keys
52
+ k1, k2, k3, k4 = @xor_keys
55
53
 
56
- o1 = m[1].to_i ^ k1
57
- o2 = m[2].to_i ^ k2
58
- o3 = m[3].to_i ^ k3
59
- o4 = m[4].to_i ^ k4
54
+ o1 = m[1].to_i ^ k1
55
+ o2 = m[2].to_i ^ k2
56
+ o3 = m[3].to_i ^ k3
57
+ o4 = m[4].to_i ^ k4
60
58
 
61
- "#{o1}.#{o2}.#{o3}.#{o4}"
59
+ "#{o1}.#{o2}.#{o3}.#{o4}"
60
+ end
62
61
  end
63
- end
64
62
 
65
- # To support log_level option since Fluentd v0.10.43
66
- unless method_defined?(:log)
67
- define_method(:log) { $log }
68
- end
63
+ # To support log_level option since Fluentd v0.10.43
64
+ unless method_defined?(:log)
65
+ define_method(:log) { $log }
66
+ end
69
67
 
70
- config_param :endpoint, :string, :default => TreasureData::API::NEW_DEFAULT_ENDPOINT
71
-
72
- config_param :connect_timeout, :integer, :default => nil
73
- config_param :read_timeout, :integer, :default => nil
74
- config_param :send_timeout, :integer, :default => nil
75
- config_set_default :buffer_type, 'file'
76
- config_set_default :flush_interval, 300
77
-
78
- def initialize
79
- require 'fileutils'
80
- require 'tempfile'
81
- require 'zlib'
82
- require 'net/http'
83
- require 'json'
84
- require 'cgi' # CGI.escape
85
- require 'time' # Time#rfc2822
86
- require 'digest/md5'
87
- require 'stringio'
88
- super
89
- @tmpdir = nil
90
- @apikey = nil
91
- @key = nil
92
- @key_num_limit = 5120 # TODO
93
- @record_size_limit = 32*1024*1024 # TODO
94
- @table_list = {}
95
- @auto_create_table = true
96
- @use_ssl = true
97
- @empty_gz_data = create_empty_gz_data
98
- end
68
+ config_param :endpoint, :string, :default => TreasureData::API::NEW_DEFAULT_ENDPOINT
69
+
70
+ config_param :connect_timeout, :integer, :default => nil
71
+ config_param :read_timeout, :integer, :default => nil
72
+ config_param :send_timeout, :integer, :default => nil
73
+ config_set_default :buffer_type, 'file'
74
+ config_set_default :flush_interval, 300
75
+
76
+ def initialize
77
+ require 'fileutils'
78
+ require 'tempfile'
79
+ require 'zlib'
80
+ require 'net/http'
81
+ require 'json'
82
+ require 'cgi' # CGI.escape
83
+ require 'time' # Time#rfc2822
84
+ require 'digest/md5'
85
+ require 'stringio'
86
+ super
87
+ @tmpdir = nil
88
+ @apikey = nil
89
+ @key = nil
90
+ @key_num_limit = 512 # TODO: Our one-time import has the restriction about the number of record keys.
91
+ @record_size_limit = 32 * 1024 * 1024 # TODO
92
+ @table_list = {}
93
+ @auto_create_table = true
94
+ @use_ssl = true
95
+ @empty_gz_data = TreasureData::API.create_empty_gz_data
96
+ end
99
97
 
100
- def configure(conf)
101
- super
98
+ def configure(conf)
99
+ super
102
100
 
103
- # overwrite default value of buffer_chunk_limit
104
- if @buffer.respond_to?(:buffer_chunk_limit=) && !conf['buffer_chunk_limit']
105
- @buffer.buffer_chunk_limit = IMPORT_SIZE_LIMIT
106
- end
101
+ # overwrite default value of buffer_chunk_limit
102
+ if @buffer.respond_to?(:buffer_chunk_limit=) && !conf['buffer_chunk_limit']
103
+ @buffer.buffer_chunk_limit = IMPORT_SIZE_LIMIT
104
+ end
107
105
 
108
- if conf.has_key?('tmpdir')
109
- @tmpdir = conf['tmpdir']
110
- FileUtils.mkdir_p(@tmpdir)
111
- end
106
+ if conf.has_key?('tmpdir')
107
+ @tmpdir = conf['tmpdir']
108
+ FileUtils.mkdir_p(@tmpdir)
109
+ end
112
110
 
113
- @apikey = conf['apikey']
114
- unless @apikey
115
- raise ConfigError, "'apikey' parameter is required on tdlog output"
116
- end
111
+ @apikey = conf['apikey']
112
+ unless @apikey
113
+ raise ConfigError, "'apikey' parameter is required on tdlog output"
114
+ end
117
115
 
118
- if auto_create_table = conf['auto_create_table']
119
- if auto_create_table.empty?
120
- @auto_create_table = true
121
- else
122
- @auto_create_table = Config.bool_value(auto_create_table)
123
- if @auto_create_table == nil
124
- raise ConfigError, "'true' or 'false' is required for auto_create_table option on tdlog output"
116
+ if auto_create_table = conf['auto_create_table']
117
+ if auto_create_table.empty?
118
+ @auto_create_table = true
119
+ else
120
+ @auto_create_table = Config.bool_value(auto_create_table)
121
+ if @auto_create_table == nil
122
+ raise ConfigError, "'true' or 'false' is required for auto_create_table option on tdlog output"
123
+ end
125
124
  end
126
125
  end
127
- end
128
126
 
129
- if use_ssl = conf['use_ssl']
130
- if use_ssl.empty?
131
- @use_ssl = true
132
- else
133
- @use_ssl = Config.bool_value(use_ssl)
134
- if @use_ssl == nil
135
- raise ConfigError, "'true' or 'false' is required for use_ssl option on tdlog output"
127
+ if use_ssl = conf['use_ssl']
128
+ if use_ssl.empty?
129
+ @use_ssl = true
130
+ else
131
+ @use_ssl = Config.bool_value(use_ssl)
132
+ if @use_ssl == nil
133
+ raise ConfigError, "'true' or 'false' is required for use_ssl option on tdlog output"
134
+ end
136
135
  end
137
136
  end
138
- end
139
137
 
140
- database = conf['database']
141
- table = conf['table']
142
- if database && table
143
- validate_database_and_table_name(database, table, conf)
144
- @key = "#{database}.#{table}"
145
- end
146
-
147
- @anonymizes = {}
148
- conf.elements.select {|e|
149
- e.name == 'anonymize'
150
- }.each {|e|
151
- key = e['key']
152
- method = e['method']
153
-
154
- case method
155
- when 'md5'
156
- scr = MD5Anonymizer.new
157
- when 'ip_xor'
158
- scr = IPXORAnonymizer.new
159
- else
160
- raise ConfigError, "Unknown anonymize method: #{method}"
138
+ database = conf['database']
139
+ table = conf['table']
140
+ if database && table
141
+ validate_database_and_table_name(database, table, conf)
142
+ @key = "#{database}.#{table}"
161
143
  end
162
144
 
163
- scr.configure(e)
145
+ @anonymizes = {}
146
+ conf.elements.select { |e|
147
+ e.name == 'anonymize'
148
+ }.each { |e|
149
+ key = e['key']
150
+ method = e['method']
151
+
152
+ case method
153
+ when 'md5'
154
+ scr = MD5Anonymizer.new
155
+ when 'ip_xor'
156
+ scr = IPXORAnonymizer.new
157
+ else
158
+ raise ConfigError, "Unknown anonymize method: #{method}"
159
+ end
164
160
 
165
- @anonymizes[key] = scr
166
- }
167
- @anonymizes = nil if @anonymizes.empty?
161
+ scr.configure(e)
168
162
 
169
- @http_proxy = conf['http_proxy']
170
- @user_agent = "fluent-plugin-td: 0.10.20" # TODO: automatic increment version
171
- end
163
+ @anonymizes[key] = scr
164
+ }
165
+ @anonymizes = nil if @anonymizes.empty?
172
166
 
173
- def start
174
- super
167
+ @http_proxy = conf['http_proxy']
168
+ @user_agent = "fluent-plugin-td: 0.10.21" # TODO: automatic increment version
169
+ end
175
170
 
176
- client_opts = {
177
- :ssl => @use_ssl, :http_proxy => @http_proxy, :user_agent => @user_agent, :endpoint => @endpoint,
178
- :connect_timeout => @connect_timeout, :read_timeout => @read_timeout, :send_timeout => @send_timeout
179
- }
180
- @client = TreasureData::Client.new(@apikey, client_opts)
171
+ def start
172
+ super
181
173
 
182
- if @key
183
- if @auto_create_table
184
- database, table = @key.split('.',2)
185
- ensure_database_and_table(database, table)
186
- else
187
- check_table_exists(@key)
174
+ client_opts = {
175
+ :ssl => @use_ssl, :http_proxy => @http_proxy, :user_agent => @user_agent, :endpoint => @endpoint,
176
+ :connect_timeout => @connect_timeout, :read_timeout => @read_timeout, :send_timeout => @send_timeout
177
+ }
178
+ @client = TreasureData::Client.new(@apikey, client_opts)
179
+
180
+ if @key
181
+ if @auto_create_table
182
+ database, table = @key.split('.',2)
183
+ ensure_database_and_table(database, table)
184
+ else
185
+ check_table_exists(@key)
186
+ end
188
187
  end
189
188
  end
190
- end
191
189
 
192
- def emit(tag, es, chain)
193
- if @key
194
- key = @key
195
- else
196
- database, table = tag.split('.')[-2,2]
197
- database = TreasureData::API.normalize_database_name(database)
198
- table = TreasureData::API.normalize_table_name(table)
199
- key = "#{database}.#{table}"
200
- end
190
+ def emit(tag, es, chain)
191
+ if @key
192
+ key = @key
193
+ else
194
+ database, table = tag.split('.')[-2,2]
195
+ database = TreasureData::API.normalize_database_name(database)
196
+ table = TreasureData::API.normalize_table_name(table)
197
+ key = "#{database}.#{table}"
198
+ end
201
199
 
202
- unless @auto_create_table
203
- check_table_exists(key)
204
- end
200
+ unless @auto_create_table
201
+ check_table_exists(key)
202
+ end
205
203
 
206
- super(tag, es, chain, key)
207
- end
204
+ super(tag, es, chain, key)
205
+ end
208
206
 
209
- def format_stream(tag, es)
210
- out = ''
211
- off = out.bytesize
212
- es.each {|time,record|
213
- begin
214
- if @anonymizes
215
- @anonymizes.each_pair {|key,scr|
216
- if value = record[key]
217
- record[key] = scr.anonymize(value)
218
- end
219
- }
207
+ def format_stream(tag, es)
208
+ out = ''
209
+ off = out.bytesize
210
+ es.each { |time, record|
211
+ begin
212
+ if @anonymizes
213
+ @anonymizes.each_pair { |key, scr|
214
+ if value = record[key]
215
+ record[key] = scr.anonymize(value)
216
+ end
217
+ }
218
+ end
219
+
220
+ record['time'] = time
221
+
222
+ if record.size > @key_num_limit
223
+ raise "Too many number of keys (#{record.size} keys)" # TODO include summary of the record
224
+ end
225
+ rescue => e
226
+ # TODO (a) Remove the transaction mechanism of fluentd
227
+ # or (b) keep transaction boundaries in in/out_forward.
228
+ # This code disables the transaction mechanism (a).
229
+ log.error "#{e}: #{summarize_record(record)}"
230
+ log.error_backtrace e.backtrace
231
+ next
220
232
  end
221
233
 
222
- record['time'] = time
223
-
224
- if record.size > @key_num_limit
225
- raise "Too many number of keys (#{record.size} keys)" # TODO include summary of the record
234
+ begin
235
+ record.to_msgpack(out)
236
+ rescue RangeError
237
+ TreasureData::API.normalized_msgpack(record, out)
226
238
  end
227
239
 
228
- rescue
229
- # TODO (a) Remove the transaction mechanism of fluentd
230
- # or (b) keep transaction boundaries in in/out_forward.
231
- # This code disables the transaction mechanism (a).
232
- log.error "#{$!}: #{summarize_record(record)}"
233
- log.error_backtrace $!.backtrace
234
- next
235
- end
236
-
237
- begin
238
- record.to_msgpack(out)
239
- rescue RangeError
240
- TreasureData::API.normalized_msgpack(record, out)
241
- end
240
+ noff = out.bytesize
241
+ sz = noff - off
242
+ if sz > @record_size_limit
243
+ # TODO don't raise error
244
+ #raise "Size of a record too large (#{sz} bytes)" # TODO include summary of the record
245
+ log.warn "Size of a record too large (#{sz} bytes): #{summarize_record(record)}"
246
+ end
247
+ off = noff
248
+ }
249
+ out
250
+ end
242
251
 
243
- noff = out.bytesize
244
- sz = noff - off
245
- if sz > @record_size_limit
246
- # TODO don't raise error
247
- #raise "Size of a record too large (#{sz} bytes)" # TODO include summary of the record
248
- log.warn "Size of a record too large (#{sz} bytes): #{summarize_record(record)}"
252
+ def summarize_record(record)
253
+ json = Yajl.dump(record)
254
+ if json.size > 100
255
+ json[0..97] + "..."
256
+ else
257
+ json
249
258
  end
250
- off = noff
251
- }
252
- out
253
- end
254
-
255
- def summarize_record(record)
256
- json = record.to_json
257
- if json.size > 100
258
- json[0..97]+"..."
259
- else
260
- json
261
259
  end
262
- end
263
260
 
264
- def write(chunk)
265
- unique_id = chunk.unique_id
266
- database, table = chunk.key.split('.',2)
261
+ def write(chunk)
262
+ unique_id = chunk.unique_id
263
+ database, table = chunk.key.split('.', 2)
267
264
 
268
- FileUtils.mkdir_p(@tmpdir) unless @tmpdir.nil?
269
- f = Tempfile.new("tdlog-", @tmpdir)
270
- w = Zlib::GzipWriter.new(f)
265
+ FileUtils.mkdir_p(@tmpdir) unless @tmpdir.nil?
266
+ f = Tempfile.new("tdlog-", @tmpdir)
267
+ w = Zlib::GzipWriter.new(f)
271
268
 
272
- chunk.write_to(w)
273
- w.finish
274
- w = nil
269
+ chunk.write_to(w)
270
+ w.finish
271
+ w = nil
275
272
 
276
- size = f.pos
277
- f.pos = 0
278
- upload(database, table, f, size, unique_id)
279
-
280
- ensure
281
- w.close if w
282
- f.close if f
283
- end
273
+ size = f.pos
274
+ f.pos = 0
275
+ upload(database, table, f, size, unique_id)
284
276
 
285
- def create_empty_gz_data
286
- io = StringIO.new
287
- Zlib::GzipWriter.new(io).close
288
- io.string
289
- end
277
+ ensure
278
+ w.close if w
279
+ f.close if f
280
+ end
290
281
 
291
- def upload(database, table, io, size, unique_id)
292
- unique_str = unique_id.unpack('C*').map {|x| "%02x" % x }.join
293
- log.trace { "uploading logs to Treasure Data database=#{database} table=#{table} (#{size}bytes)" }
282
+ def upload(database, table, io, size, unique_id)
283
+ unique_str = unique_id.unpack('C*').map { |x| "%02x" % x }.join
284
+ log.trace { "uploading logs to Treasure Data database=#{database} table=#{table} (#{size}bytes)" }
294
285
 
295
- begin
296
286
  begin
297
- start = Time.now
298
- @client.import(database, table, "msgpack.gz", io, size, unique_str)
299
- rescue TreasureData::NotFoundError
300
- unless @auto_create_table
301
- raise $!
287
+ begin
288
+ start = Time.now
289
+ @client.import(database, table, "msgpack.gz", io, size, unique_str)
290
+ rescue TreasureData::NotFoundError => e
291
+ unless @auto_create_table
292
+ raise e
293
+ end
294
+ ensure_database_and_table(database, table)
295
+ io.pos = 0
296
+ retry
302
297
  end
303
- ensure_database_and_table(database, table)
304
- io.pos = 0
305
- retry
298
+ rescue => e
299
+ elapsed = Time.now - start
300
+ ne = RuntimeError.new("Failed to upload to Treasure Data '#{database}.#{table}' table: #{$!} (#{size} bytes; #{elapsed} seconds)")
301
+ ne.set_backtrace(e.backtrace)
302
+ raise ne
306
303
  end
307
- rescue => e
308
- elapsed = Time.now - start
309
- ne = RuntimeError.new("Failed to upload to Treasure Data '#{database}.#{table}' table: #{$!} (#{size} bytes; #{elapsed} seconds)")
310
- ne.set_backtrace(e.backtrace)
311
- raise ne
312
304
  end
313
- end
314
305
 
315
- def check_table_exists(key)
316
- unless @table_list.has_key?(key)
317
- database, table = key.split('.',2)
318
- log.debug "checking whether table '#{database}.#{table}' exists on Treasure Data"
319
- io = StringIO.new(@empty_gz_data)
320
- begin
321
- @client.import(database, table, "msgpack.gz", io, io.size)
322
- @table_list[key] = true
323
- rescue TreasureData::NotFoundError
324
- raise "Table #{key.inspect} does not exist on Treasure Data. Use 'td table:create #{database} #{table}' to create it."
325
- rescue
326
- log.warn "failed to check existence of '#{database}.#{table}' table on Treasure Data", :error=>$!.to_s
327
- log.debug_backtrace $!
306
+ def check_table_exists(key)
307
+ unless @table_list.has_key?(key)
308
+ database, table = key.split('.', 2)
309
+ log.debug "checking whether table '#{database}.#{table}' exists on Treasure Data"
310
+ io = StringIO.new(@empty_gz_data)
311
+ begin
312
+ @client.import(database, table, "msgpack.gz", io, io.size)
313
+ @table_list[key] = true
314
+ rescue TreasureData::NotFoundError
315
+ raise "Table #{key.inspect} does not exist on Treasure Data. Use 'td table:create #{database} #{table}' to create it."
316
+ rescue => e
317
+ log.warn "failed to check existence of '#{database}.#{table}' table on Treasure Data", :error => e.to_s
318
+ log.debug_backtrace e.backtrace
319
+ end
328
320
  end
329
321
  end
330
- end
331
322
 
332
- def validate_database_and_table_name(database, table, conf)
333
- begin
334
- TreasureData::API.validate_database_name(database)
335
- rescue => e
336
- raise ConfigError, "Invalid database name #{database.inspect}: #{e}: #{conf}"
337
- end
338
- begin
339
- TreasureData::API.validate_table_name(table)
340
- rescue => e
341
- raise ConfigError, "Invalid table name #{table.inspect}: #{e}: #{conf}"
323
+ def validate_database_and_table_name(database, table, conf)
324
+ begin
325
+ TreasureData::API.validate_database_name(database)
326
+ rescue => e
327
+ raise ConfigError, "Invalid database name #{database.inspect}: #{e}: #{conf}"
328
+ end
329
+ begin
330
+ TreasureData::API.validate_table_name(table)
331
+ rescue => e
332
+ raise ConfigError, "Invalid table name #{table.inspect}: #{e}: #{conf}"
333
+ end
342
334
  end
343
- end
344
335
 
345
- def ensure_database_and_table(database, table)
346
- log.info "Creating table #{database}.#{table} on TreasureData"
347
- begin
348
- @client.create_log_table(database, table)
349
- rescue TreasureData::NotFoundError
350
- @client.create_database(database)
351
- @client.create_log_table(database, table)
352
- rescue TreasureData::AlreadyExistsError
336
+ def ensure_database_and_table(database, table)
337
+ log.info "Creating table #{database}.#{table} on TreasureData"
338
+ begin
339
+ @client.create_log_table(database, table)
340
+ rescue TreasureData::NotFoundError
341
+ @client.create_database(database)
342
+ @client.create_log_table(database, table)
343
+ rescue TreasureData::AlreadyExistsError
344
+ end
353
345
  end
354
346
  end
355
347
  end
356
-
357
-
358
- end
@@ -57,7 +57,6 @@ class TreasureDataItemOutputTest < Test::Unit::TestCase
57
57
 
58
58
  def test_emit
59
59
  d = create_driver
60
-
61
60
  time, records = stub_seed_values
62
61
  stub_td_import_request(stub_request_body(records), d.instance.database, d.instance.table)
63
62
 
@@ -69,10 +68,9 @@ class TreasureDataItemOutputTest < Test::Unit::TestCase
69
68
  assert_equal('TD1 testkey', @auth_header)
70
69
  end
71
70
 
72
- def test_emit
71
+ def test_emit_with_endpoint
73
72
  d = create_driver(DEFAULT_CONFIG + "endpoint foo.bar.baz")
74
73
  opts = {:endpoint => 'foo.bar.baz'}
75
-
76
74
  time, records = stub_seed_values
77
75
  stub_td_import_request(stub_request_body(records), d.instance.database, d.instance.table, opts)
78
76
 
@@ -83,4 +81,19 @@ class TreasureDataItemOutputTest < Test::Unit::TestCase
83
81
 
84
82
  assert_equal('TD1 testkey', @auth_header)
85
83
  end
84
+
85
+ def test_emit_with_too_many_keys
86
+ d = create_driver(DEFAULT_CONFIG + "endpoint foo.bar.baz")
87
+ opts = {:endpoint => 'foo.bar.baz'}
88
+ time, _ = stub_seed_values
89
+ stub_td_import_request(stub_request_body([]), d.instance.database, d.instance.table, opts)
90
+
91
+ d.emit(create_too_many_keys_record, time)
92
+ d.run
93
+
94
+ assert_equal 0, d.emits.size
95
+ assert d.instance.log.logs.select{ |line|
96
+ line =~ / \[error\]: Too many number of keys/
97
+ }.size == 1, "too many keys error is not logged"
98
+ end
86
99
  end
@@ -43,7 +43,6 @@ class TreasureDataLogOutputTest < Test::Unit::TestCase
43
43
 
44
44
  def test_emit
45
45
  d = create_driver
46
-
47
46
  time, records = stub_seed_values
48
47
  database, table = d.instance.instance_variable_get(:@key).split(".", 2)
49
48
  stub_td_table_create_request(database, table)
@@ -71,7 +70,24 @@ class TreasureDataLogOutputTest < Test::Unit::TestCase
71
70
  d.run
72
71
  end
73
72
 
74
- # TODO: add normalized_msgpack / key_num_limit / tag split test
73
+ def test_emit_with_too_many_keys
74
+ d = create_driver(DEFAULT_CONFIG + "endpoint foo.bar.baz")
75
+ opts = {:endpoint => 'foo.bar.baz'}
76
+ time, records = stub_seed_values
77
+ database, table = d.instance.instance_variable_get(:@key).split(".", 2)
78
+ stub_td_table_create_request(database, table, opts)
79
+ stub_td_import_request(stub_request_body([], time), database, table, opts)
80
+
81
+ d.emit(create_too_many_keys_record, time)
82
+ d.run
83
+
84
+ assert_equal 0, d.emits.size
85
+ assert d.instance.log.logs.select{ |line|
86
+ line =~ / \[error\]: Too many number of keys/
87
+ }.size == 1, "too many keys error is not logged"
88
+ end
89
+
90
+ # TODO: add normalized_msgpack / tag split test
75
91
 
76
92
  ## TODO invalid names are normalized
77
93
  # def test_invalid_name
data/test/test_helper.rb CHANGED
@@ -12,6 +12,12 @@ def e(s)
12
12
  end
13
13
 
14
14
  class Test::Unit::TestCase
15
+ def create_too_many_keys_record
16
+ record = {}
17
+ 5012.times { |i| record["k#{i}"] = i }
18
+ record
19
+ end
20
+
15
21
  def stub_seed_values
16
22
  time = Time.parse("2014-01-01 00:00:00 UTC").to_i
17
23
  records = [{"a" => 1}, {"a" => 2}]
metadata CHANGED
@@ -1,78 +1,69 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-td
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.20
5
- prerelease:
4
+ version: 0.10.21
6
5
  platform: ruby
7
6
  authors:
8
7
  - Treasure Data, Inc.
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-06-05 00:00:00.000000000 Z
11
+ date: 2014-07-03 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: fluentd
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: 0.10.27
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
26
  version: 0.10.27
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: td-client
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ~>
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
33
  version: 0.8.61
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ~>
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
40
  version: 0.8.61
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: rake
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: 0.9.2
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
60
53
  - !ruby/object:Gem::Version
61
54
  version: 0.9.2
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: webmock
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ~>
59
+ - - "~>"
68
60
  - !ruby/object:Gem::Version
69
61
  version: '1.16'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ~>
66
+ - - "~>"
76
67
  - !ruby/object:Gem::Version
77
68
  version: '1.16'
78
69
  description: Treasure Data Cloud Data Service plugin for Fluentd
@@ -81,12 +72,11 @@ executables: []
81
72
  extensions: []
82
73
  extra_rdoc_files: []
83
74
  files:
84
- - .gitignore
85
- - .travis.yml
75
+ - ".gitignore"
76
+ - ".travis.yml"
86
77
  - AUTHORS
87
78
  - ChangeLog
88
79
  - Gemfile
89
- - Gemfile.fluentd.lt.0.10.43
90
80
  - README.rdoc
91
81
  - Rakefile
92
82
  - VERSION
@@ -100,33 +90,26 @@ files:
100
90
  - test/test_helper.rb
101
91
  homepage: http://www.treasuredata.com/
102
92
  licenses: []
93
+ metadata: {}
103
94
  post_install_message:
104
95
  rdoc_options: []
105
96
  require_paths:
106
97
  - lib
107
98
  required_ruby_version: !ruby/object:Gem::Requirement
108
- none: false
109
99
  requirements:
110
- - - ! '>='
100
+ - - ">="
111
101
  - !ruby/object:Gem::Version
112
102
  version: '0'
113
- segments:
114
- - 0
115
- hash: 4219119697860923650
116
103
  required_rubygems_version: !ruby/object:Gem::Requirement
117
- none: false
118
104
  requirements:
119
- - - ! '>='
105
+ - - ">="
120
106
  - !ruby/object:Gem::Version
121
107
  version: '0'
122
- segments:
123
- - 0
124
- hash: 4219119697860923650
125
108
  requirements: []
126
109
  rubyforge_project:
127
- rubygems_version: 1.8.23
110
+ rubygems_version: 2.2.2
128
111
  signing_key:
129
- specification_version: 3
112
+ specification_version: 4
130
113
  summary: Treasure Data Cloud Data Service plugin for Fluentd
131
114
  test_files:
132
115
  - test/plugin/test_out_tditem.rb
@@ -1,4 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gem 'fluentd', '= 0.10.42'
4
- gemspec