fluentd 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db2e0fe87d5466ddca212327e3e0ad56bd7c6055daffd05bc351c5544153908d
4
- data.tar.gz: b6b92ecd3814b496dfa7522850876bffeb6f2b59278159462b3de2e91a613170
3
+ metadata.gz: 592df476adfeb30ef3a08865d03af3eeb7f60e1d27684f22dc3505b8dc7bcab4
4
+ data.tar.gz: acc575bbf086686addf560a7a65e084221a609ce5eff6385b88a9aea65c4aca4
5
5
  SHA512:
6
- metadata.gz: c359fac49d0273d40d2b8452eacc3c85d899264d44f9eb57e11bcdf73373b146f065dc0d2cee87b8542a4da3087a917d344809697e1e8065165066530eda26b5
7
- data.tar.gz: a080e5d6948fe33bbc02ebfba49fb851c1facd9cf6a30a38a5f3762cb8e629e93950b3cf9d24780215655c12a7ca69a7cdaf546bed31bdab8319e8dcbdd9e405
6
+ metadata.gz: c1f5ebc8c426c80c7b6501afba2ac9534aeceafe21945e58fd0530dbde099d8cdbd0a6c9533c7500d838db09f66dfbefd4fbed5cb6304ab71fe473ab0a63cd5c
7
+ data.tar.gz: 6eef15e5140fc4547c59215ae01cd9eb661429bb7eb36067e6834f877c916bf78507345091002116129435e548525654e289db36c3a786f7aebc5780835458ef
@@ -1,5 +1,31 @@
1
1
  # v1.2
2
2
 
3
+ ## Release v1.2.3 - 2018/07/10
4
+
5
+ ### Enhancements
6
+
7
+ * in_http: Consider `<parse>` parameters in batch mode
8
+ https://github.com/fluent/fluentd/pull/2055
9
+ * in_http: Support gzip payload
10
+ https://github.com/fluent/fluentd/pull/2060
11
+ * output: Improve compress performance
12
+ https://github.com/fluent/fluentd/pull/2031
13
+ * in_monitor_agent: Add missing descriptions for configurable options
14
+ https://github.com/fluent/fluentd/pull/2037
15
+ * parser_syslog: update regex of pid field for conformance to RFC5424 spec
16
+ https://github.com/fluent/fluentd/pull/2051
17
+
18
+ ### Bug fixes
19
+
20
+ * in_tail: Fix to rescue Errno::ENOENT for File.mtime()
21
+ https://github.com/fluent/fluentd/pull/2063
22
+ * fluent-plugin-generate: Fix Parser plugin template
23
+ https://github.com/fluent/fluentd/pull/2026
24
+ * fluent-plugin-config-format: Fix NoMethodError for some plugins
25
+ https://github.com/fluent/fluentd/pull/2023
26
+ * config: Don't warn message for reserved parameters in DSL
27
+ https://github.com/fluent/fluentd/pull/2034
28
+
3
29
  ## Release v1.2.2 - 2018/06/12
4
30
 
5
31
  ### Enhancements
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
8
8
  gem.email = ["frsyuki@gmail.com"]
9
9
  gem.description = %q{Fluentd is an open source data collector designed to scale and simplify log management. It can collect, process and ship many kinds of data in near real-time.}
10
10
  gem.summary = %q{Fluentd event collector}
11
- gem.homepage = "https://fluentd.org/"
11
+ gem.homepage = "https://www.fluentd.org/"
12
12
 
13
13
  gem.files = `git ls-files`.split($\)
14
14
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -384,7 +384,7 @@ module Fluent
384
384
  end
385
385
  # Overwrite by config_set_default
386
386
  @defaults.each do |name, value|
387
- if @params.key?(name) || @argument.first == name
387
+ if @params.key?(name) || (@argument && @argument.first == name)
388
388
  dumped_config[name][:default] = value
389
389
  else
390
390
  dumped_config[name] = { default: value }
@@ -22,6 +22,8 @@ require 'fluent/config/element'
22
22
  module Fluent
23
23
  module Config
24
24
  module DSL
25
+ RESERVED_PARAMETERS = [:type, :id, :log_level, :label] # Need '@' prefix for reserved parameters
26
+
25
27
  module Parser
26
28
  def self.read(path)
27
29
  path = File.expand_path(path)
@@ -95,11 +97,12 @@ module Fluent
95
97
  proxy.element.instance_exec(&block)
96
98
  @elements.push(proxy.to_config_element)
97
99
  else
98
- @attrs[name.to_s] = if value.is_a?(Array) || value.is_a?(Hash)
99
- JSON.dump(value)
100
- else
101
- value.to_s
102
- end
100
+ param_name = RESERVED_PARAMETERS.include?(name) ? "@#{name}" : name.to_s
101
+ @attrs[param_name] = if value.is_a?(Array) || value.is_a?(Hash)
102
+ JSON.dump(value)
103
+ else
104
+ value.to_s
105
+ end
103
106
  end
104
107
 
105
108
  self
@@ -60,7 +60,7 @@ module Fluent
60
60
  out = ''
61
61
  loop do
62
62
  gz = Zlib::GzipReader.new(io)
63
- out += gz.read
63
+ out << gz.read
64
64
  unused = gz.unused
65
65
  gz.finish
66
66
 
@@ -78,10 +78,16 @@ module Fluent::Plugin
78
78
  @parser_json = parser_create(usage: 'parser_in_http_json', type: 'json')
79
79
  @parser_json.estimate_current_event = false
80
80
  @format_name = 'default'
81
+ @parser_time_key = if parser_config = conf.elements('parse').first
82
+ parser_config['time_key'] || 'time'
83
+ else
84
+ 'time'
85
+ end
81
86
  method(:parse_params_default)
82
87
  else
83
88
  @parser = parser_create
84
89
  @format_name = @parser_configs.first['@type']
90
+ @parser_time_key = @parser.time_key
85
91
  method(:parse_params_with_parser)
86
92
  end
87
93
  self.singleton_class.module_eval do
@@ -202,11 +208,18 @@ module Fluent::Plugin
202
208
  if @add_remote_addr
203
209
  single_record['REMOTE_ADDR'] = params['REMOTE_ADDR']
204
210
  end
205
- single_time = if t = single_record.delete('time')
206
- Fluent::EventTime.from_time(Time.at(t))
207
- else
208
- time
209
- end
211
+
212
+ if defined? @parser
213
+ single_time = @parser.parse_time(single_record)
214
+ single_time, single_record = @parser.convert_values(single_time, single_record)
215
+ else
216
+ single_time = if t = single_record.delete(@parser_time_key)
217
+ Fluent::EventTime.from_time(Time.at(t))
218
+ else
219
+ time
220
+ end
221
+ end
222
+
210
223
  mes.add(single_time, single_record)
211
224
  end
212
225
  router.emit_stream(tag, mes)
@@ -305,6 +318,7 @@ module Fluent::Plugin
305
318
  end
306
319
  @env = {}
307
320
  @content_type = ""
321
+ @content_encoding = ""
308
322
  headers.each_pair {|k,v|
309
323
  @env["HTTP_#{k.gsub('-','_').upcase}"] = v
310
324
  case k
@@ -314,6 +328,8 @@ module Fluent::Plugin
314
328
  size = v.to_i
315
329
  when /Content-Type/i
316
330
  @content_type = v
331
+ when /Content-Encoding/i
332
+ @content_encoding = v
317
333
  when /Connection/i
318
334
  if v =~ /close/i
319
335
  @keep_alive = false
@@ -365,6 +381,22 @@ module Fluent::Plugin
365
381
  end
366
382
  end
367
383
 
384
+ # Content Encoding
385
+ # =================
386
+ # Decode payload according to the "Content-Encoding" header.
387
+ # For now, we only support 'gzip' and 'deflate'.
388
+ begin
389
+ if @content_encoding == 'gzip'
390
+ @body = Zlib::GzipReader.new(StringIO.new(@body)).read
391
+ elsif @content_encoding == 'deflate'
392
+ @body = Zlib::Inflate.inflate(@body)
393
+ end
394
+ rescue
395
+ @log.warn 'fails to decode payload', error: $!.to_s
396
+ send_response_and_close("400 Bad Request", {}, "")
397
+ return
398
+ end
399
+
368
400
  @env['REMOTE_ADDR'] = @remote_addr if @remote_addr
369
401
 
370
402
  uri = URI.parse(@parser.request_url)
@@ -30,11 +30,17 @@ module Fluent::Plugin
30
30
 
31
31
  helpers :timer, :thread
32
32
 
33
+ desc 'The address to bind to.'
33
34
  config_param :bind, :string, default: '0.0.0.0'
35
+ desc 'The port to listen to.'
34
36
  config_param :port, :integer, default: 24220
37
+ desc 'The tag with which internal metrics are emitted.'
35
38
  config_param :tag, :string, default: nil
39
+ desc 'Determine the rate to emit internal metrics as events.'
36
40
  config_param :emit_interval, :time, default: 60
41
+ desc 'Determine whether to include the config information.'
37
42
  config_param :include_config, :bool, default: true
43
+ desc 'Determine whether to include the retry information.'
38
44
  config_param :include_retry, :bool, default: true
39
45
 
40
46
  class MonitorServlet < WEBrick::HTTPServlet::AbstractServlet
@@ -216,20 +216,24 @@ module Fluent::Plugin
216
216
  path = date.strftime(path)
217
217
  if path.include?('*')
218
218
  paths += Dir.glob(path).select { |p|
219
- is_file = !File.directory?(p)
220
- if File.readable?(p) && is_file
221
- if @limit_recently_modified && File.mtime(p) < (date - @limit_recently_modified)
222
- false
219
+ begin
220
+ is_file = !File.directory?(p)
221
+ if File.readable?(p) && is_file
222
+ if @limit_recently_modified && File.mtime(p) < (date - @limit_recently_modified)
223
+ false
224
+ else
225
+ true
226
+ end
223
227
  else
224
- true
225
- end
226
- else
227
- if is_file
228
- unless @ignore_list.include?(path)
229
- log.warn "#{p} unreadable. It is excluded and would be examined next time."
230
- @ignore_list << path if @ignore_repeated_permission_error
228
+ if is_file
229
+ unless @ignore_list.include?(path)
230
+ log.warn "#{p} unreadable. It is excluded and would be examined next time."
231
+ @ignore_list << path if @ignore_repeated_permission_error
232
+ end
231
233
  end
234
+ false
232
235
  end
236
+ rescue Errno::ENOENT
233
237
  false
234
238
  end
235
239
  }
@@ -27,8 +27,8 @@ module Fluent
27
27
  REGEXP = /^(?<time>[^ ]*\s*[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[^ :\[]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
28
28
  # From in_syslog default pattern
29
29
  REGEXP_WITH_PRI = /^\<(?<pri>[0-9]+)\>(?<time>[^ ]* {1,2}[^ ]* [^ ]*) (?<host>[^ ]*) (?<ident>[^ :\[]*)(?:\[(?<pid>[0-9]+)\])?(?:[^\:]*\:)? *(?<message>.*)$/
30
- REGEXP_RFC5424 = /\A^(?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>[-0-9]+) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|[^ ])) (?<message>.+)$\z/
31
- REGEXP_RFC5424_WITH_PRI = /\A^\<(?<pri>[0-9]{1,3})\>[1-9]\d{0,2} (?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>[-0-9]+) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|[^ ])) (?<message>.+)$\z/
30
+ REGEXP_RFC5424 = /\A^(?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>.{1,128}) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|[^ ])) (?<message>.+)$\z/
31
+ REGEXP_RFC5424_WITH_PRI = /\A^\<(?<pri>[0-9]{1,3})\>[1-9]\d{0,2} (?<time>[^ ]+) (?<host>[^ ]+) (?<ident>[^ ]+) (?<pid>.{1,128}) (?<msgid>[^ ]+) (?<extradata>(\[(.*)\]|[^ ])) (?<message>.+)$\z/
32
32
  REGEXP_DETECT_RFC5424 = /^\<.*\>[1-9]\d{0,2}/
33
33
 
34
34
  config_set_default :time_format, "%b %d %H:%M:%S"
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '1.2.2'
19
+ VERSION = '1.2.3'
20
20
 
21
21
  end
@@ -6,10 +6,10 @@ module Fluent
6
6
  module Plugin
7
7
  class <%= class_name %> < Fluent::Plugin::Parser
8
8
  Fluent::Plugin.register_parser("<%= plugin_name %>", self)
9
- end
10
9
 
11
- def parse(text)
12
- yield time, record
10
+ def parse(text)
11
+ yield time, record
12
+ end
13
13
  end
14
14
  end
15
15
  end
@@ -176,7 +176,7 @@ module Fluent::Config
176
176
  assert_equal('source', ele4.name)
177
177
  assert_predicate(ele4.arg, :empty?)
178
178
  assert_equal(2, ele4.keys.size)
179
- assert_equal('tail', ele4['type'])
179
+ assert_equal('tail', ele4['@type'])
180
180
  assert_equal("/var/log/httpd/access.part4.log", ele4['path'])
181
181
  end
182
182
 
@@ -185,11 +185,11 @@ module Fluent::Config
185
185
 
186
186
  assert_equal('filter', filter0.name)
187
187
  assert_equal('bar.**', filter0.arg)
188
- assert_equal('hoge', filter0['type'])
188
+ assert_equal('hoge', filter0['@type'])
189
189
  assert_equal('moge', filter0['val1'])
190
190
  assert_equal(JSON.dump(['foo', 'bar', 'baz']), filter0['val2'])
191
191
  assert_equal('10', filter0['val3'])
192
- assert_equal('hoge', filter0['id'])
192
+ assert_equal('hoge', filter0['@id'])
193
193
 
194
194
  assert_equal(2, filter0.elements.size)
195
195
  assert_equal('subsection', filter0.elements[0].name)
@@ -203,7 +203,7 @@ module Fluent::Config
203
203
 
204
204
  assert_equal('match', match0.name)
205
205
  assert_equal('{foo,bar}.**', match0.arg)
206
- assert_equal('file', match0['type'])
206
+ assert_equal('file', match0['@type'])
207
207
  assert_equal('/var/log/httpd/access.myhostname.4.log', match0['path'])
208
208
  end
209
209
  end
@@ -302,7 +302,7 @@ module Fluent::Config
302
302
  assert_equal('source', ele4.name)
303
303
  assert_predicate(ele4.arg, :empty?)
304
304
  assert_equal(2, ele4.keys.size)
305
- assert_equal('tail', ele4['type'])
305
+ assert_equal('tail', ele4['@type'])
306
306
  assert_equal("/var/log/httpd/access.part4.log", ele4['path'])
307
307
  end
308
308
 
@@ -311,11 +311,11 @@ module Fluent::Config
311
311
 
312
312
  assert_equal('filter', filter0.name)
313
313
  assert_equal('bar.**', filter0.arg)
314
- assert_equal('hoge', filter0['type'])
314
+ assert_equal('hoge', filter0['@type'])
315
315
  assert_equal('moge', filter0['val1'])
316
316
  assert_equal(JSON.dump(['foo', 'bar', 'baz']), filter0['val2'])
317
317
  assert_equal('10', filter0['val3'])
318
- assert_equal('hoge', filter0['id'])
318
+ assert_equal('hoge', filter0['@id'])
319
319
 
320
320
  assert_equal(2, filter0.elements.size)
321
321
  assert_equal('subsection', filter0.elements[0].name)
@@ -329,7 +329,7 @@ module Fluent::Config
329
329
 
330
330
  assert_equal('match', match0.name)
331
331
  assert_equal('{foo,bar}.**', match0.arg)
332
- assert_equal('file', match0['type'])
332
+ assert_equal('file', match0['@type'])
333
333
  assert_equal('/var/log/httpd/access.myhostname.4.log', match0['path'])
334
334
  end
335
335
  end
@@ -64,6 +64,12 @@ class CounterClientTest < ::Test::Unit::TestCase
64
64
  store[key]
65
65
  end
66
66
 
67
+ def travel(sec)
68
+ # Since Timecop.travel() causes test failures on Windows/AppVeyor by inducing
69
+ # rounding errors to Time.now, we need to use Timecop.freeze() instead.
70
+ Timecop.freeze(Time.now + sec)
71
+ end
72
+
67
73
  sub_test_case 'establish' do
68
74
  test 'establish a scope' do
69
75
  @client.establish(@scope)
@@ -277,7 +283,7 @@ class CounterClientTest < ::Test::Unit::TestCase
277
283
  assert_equal 0, v['total']
278
284
  assert_equal 0, v['current']
279
285
 
280
- Timecop.travel(1)
286
+ travel(1)
281
287
  inc_obj = { name: @name, value: 10 }
282
288
  @client.inc(inc_obj).get
283
289
 
@@ -444,7 +450,7 @@ class CounterClientTest < ::Test::Unit::TestCase
444
450
  assert_equal @now, Fluent::EventTime.new(*v1['last_reset_at'])
445
451
 
446
452
  travel_sec = 6 # greater than reset_interval
447
- Timecop.travel(travel_sec)
453
+ travel(travel_sec)
448
454
 
449
455
  v2 = @client.reset(@name).get
450
456
  data = v2.data.first
@@ -472,7 +478,7 @@ class CounterClientTest < ::Test::Unit::TestCase
472
478
  assert_equal @now, Fluent::EventTime.new(*v1['last_reset_at'])
473
479
 
474
480
  travel_sec = 4 # less than reset_interval
475
- Timecop.travel(travel_sec)
481
+ travel(travel_sec)
476
482
 
477
483
  v2 = @client.reset(@name).get
478
484
  data = v2.data.first
@@ -520,7 +526,7 @@ class CounterClientTest < ::Test::Unit::TestCase
520
526
  unknown_name = 'key2'
521
527
 
522
528
  travel_sec = 6 # greater than reset_interval
523
- Timecop.travel(travel_sec)
529
+ travel(travel_sec)
524
530
 
525
531
  response = @client.reset(@name, unknown_name).get
526
532
  data = response.data.first
@@ -28,6 +28,12 @@ class CounterServerTest < ::Test::Unit::TestCase
28
28
  store[key]
29
29
  end
30
30
 
31
+ def travel(sec)
32
+ # Since Timecop.travel() causes test failures on Windows/AppVeyor by inducing
33
+ # rounding errors to Time.now, we need to use Timecop.freeze() instead.
34
+ Timecop.freeze(Time.now + sec)
35
+ end
36
+
31
37
  test 'raise an error when server name is invalid' do
32
38
  assert_raise do
33
39
  Fluent::Counter::Server.new("\tinvalid_name")
@@ -387,7 +393,7 @@ class CounterServerTest < ::Test::Unit::TestCase
387
393
  end
388
394
 
389
395
  test 'reset a value in the counter' do
390
- Timecop.travel(@travel_sec)
396
+ travel(@travel_sec)
391
397
 
392
398
  result = @server.send('reset', [@name], @scope, {})
393
399
  assert_nil result['errors']
@@ -412,7 +418,7 @@ class CounterServerTest < ::Test::Unit::TestCase
412
418
 
413
419
  test 'reset a value after `reset_interval` passed' do
414
420
  first_travel_sec = 5
415
- Timecop.travel(first_travel_sec) # jump time less than reset_interval
421
+ travel(first_travel_sec) # jump time less than reset_interval
416
422
  result = @server.send('reset', [@name], @scope, {})
417
423
  v = result['data'].first
418
424
 
@@ -424,7 +430,7 @@ class CounterServerTest < ::Test::Unit::TestCase
424
430
  assert_equal @now, Fluent::EventTime.new(*store['last_reset_at'])
425
431
 
426
432
  # time is passed greater than reset_interval
427
- Timecop.travel(@travel_sec)
433
+ travel(@travel_sec)
428
434
  result = @server.send('reset', [@name], @scope, {})
429
435
  v = result['data'].first
430
436
 
@@ -23,6 +23,12 @@ class CounterStoreTest < ::Test::Unit::TestCase
23
23
  store[key]
24
24
  end
25
25
 
26
+ def travel(sec)
27
+ # Since Timecop.travel() causes test failures on Windows/AppVeyor by inducing
28
+ # rounding errors to Time.now, we need to use Timecop.freeze() instead.
29
+ Timecop.freeze(Time.now + sec)
30
+ end
31
+
26
32
  sub_test_case 'init' do
27
33
  setup do
28
34
  @reset_interval = 10
@@ -142,7 +148,7 @@ class CounterStoreTest < ::Test::Unit::TestCase
142
148
  test 'increment or decrement a value in the counter' do |value|
143
149
  key = Fluent::Counter::Store.gen_key(@scope, @name)
144
150
  @store.init(key, @init_data)
145
- Timecop.travel(@travel_sec)
151
+ travel(@travel_sec)
146
152
  v = @store.inc(key, { 'value' => value })
147
153
 
148
154
  assert_equal value, v['total']
@@ -198,7 +204,7 @@ class CounterStoreTest < ::Test::Unit::TestCase
198
204
  end
199
205
 
200
206
  test 'reset a value in the counter' do
201
- Timecop.travel(@travel_sec)
207
+ travel(@travel_sec)
202
208
 
203
209
  v = @store.reset(@key)
204
210
  assert_equal @travel_sec, v['elapsed_time']
@@ -222,7 +228,7 @@ class CounterStoreTest < ::Test::Unit::TestCase
222
228
 
223
229
  test 'reset a value after `reset_interval` passed' do
224
230
  first_travel_sec = 5
225
- Timecop.travel(first_travel_sec) # jump time less than reset_interval
231
+ travel(first_travel_sec) # jump time less than reset_interval
226
232
  v = @store.reset(@key)
227
233
 
228
234
  assert_equal false, v['success']
@@ -232,7 +238,7 @@ class CounterStoreTest < ::Test::Unit::TestCase
232
238
  assert_equal @now, Fluent::EventTime.new(*store['last_reset_at'])
233
239
 
234
240
  # time is passed greater than reset_interval
235
- Timecop.travel(@travel_sec)
241
+ travel(@travel_sec)
236
242
  v = @store.reset(@key)
237
243
  assert_true v['success']
238
244
  assert_equal @travel_sec + first_travel_sec, v['elapsed_time']
@@ -162,6 +162,29 @@ class HttpInputTest < Test::Unit::TestCase
162
162
  assert_equal_event_time time, d.events[1][1]
163
163
  end
164
164
 
165
+ def test_multi_json_with_nonexistent_time_key
166
+ d = create_driver(CONFIG + %[
167
+ <parse>
168
+ time_key missing
169
+ </parse>
170
+ ])
171
+ time = event_time("2011-01-02 13:14:15 UTC")
172
+ time_i = time.to_i
173
+ time_f = time.to_f
174
+
175
+ records = [{"a" => 1, 'time' => time_i},{"a" => 2, 'time' => time_f}]
176
+ tag = "tag1"
177
+ res_codes = []
178
+ d.run(expect_records: 2, timeout: 5) do
179
+ res = post("/#{tag}", {"json" => records.to_json})
180
+ res_codes << res.code
181
+ end
182
+ assert_equal ["200"], res_codes
183
+ assert_equal 2, d.events.size
184
+ assert_not_equal time_i, d.events[0][1].sec # current time is used because "missing" field doesn't exist
185
+ assert_not_equal time_i, d.events[1][1].sec
186
+ end
187
+
165
188
  def test_json_with_add_remote_addr
166
189
  d = create_driver(CONFIG + "add_remote_addr true")
167
190
  time = event_time("2011-01-02 13:14:15 UTC")
@@ -347,6 +370,38 @@ class HttpInputTest < Test::Unit::TestCase
347
370
  assert include_http_header?(d.events[1][2])
348
371
  end
349
372
 
373
+ def test_multi_json_with_custom_parser
374
+ d = create_driver(CONFIG + %[
375
+ <parse>
376
+ @type json
377
+ keep_time_key true
378
+ time_key foo
379
+ time_format %iso8601
380
+ </parse>
381
+ ])
382
+
383
+ time = event_time("2011-01-02 13:14:15 UTC")
384
+ time_s = Time.at(time).iso8601
385
+
386
+ records = [{"foo"=>time_s,"bar"=>"test1"},{"foo"=>time_s,"bar"=>"test2"}]
387
+ tag = "tag1"
388
+ res_codes = []
389
+
390
+ d.run(expect_records: 2, timeout: 5) do
391
+ res = post("/#{tag}", records.to_json, {"Content-Type"=>"application/octet-stream"})
392
+ res_codes << res.code
393
+ end
394
+ assert_equal ["200"], res_codes
395
+
396
+ assert_equal "tag1", d.events[0][0]
397
+ assert_equal_event_time time, d.events[0][1]
398
+ assert_equal d.events[0][2], records[0]
399
+
400
+ assert_equal "tag1", d.events[1][0]
401
+ assert_equal_event_time time, d.events[1][1]
402
+ assert_equal d.events[1][2], records[1]
403
+ end
404
+
350
405
  def test_application_json
351
406
  d = create_driver
352
407
  time = event_time("2011-01-02 13:14:15 UTC")
@@ -549,6 +604,54 @@ class HttpInputTest < Test::Unit::TestCase
549
604
  assert_equal_event_time time, d.events[1][1]
550
605
  end
551
606
 
607
+ def test_content_encoding_gzip
608
+ d = create_driver
609
+
610
+ time = event_time("2011-01-02 13:14:15 UTC")
611
+ events = [
612
+ ["tag1", time, {"a"=>1}],
613
+ ["tag2", time, {"a"=>2}],
614
+ ]
615
+ res_codes = []
616
+ res_headers = []
617
+
618
+ d.run do
619
+ events.each do |tag, time, record|
620
+ header = {'Content-Type'=>'application/json', 'Content-Encoding'=>'gzip'}
621
+ res = post("/#{tag}?time=#{time}", compress_gzip(record.to_json), header)
622
+ res_codes << res.code
623
+ end
624
+ end
625
+ assert_equal ["200", "200"], res_codes
626
+ assert_equal events, d.events
627
+ assert_equal_event_time time, d.events[0][1]
628
+ assert_equal_event_time time, d.events[1][1]
629
+ end
630
+
631
+ def test_content_encoding_deflate
632
+ d = create_driver
633
+
634
+ time = event_time("2011-01-02 13:14:15 UTC")
635
+ events = [
636
+ ["tag1", time, {"a"=>1}],
637
+ ["tag2", time, {"a"=>2}],
638
+ ]
639
+ res_codes = []
640
+ res_headers = []
641
+
642
+ d.run do
643
+ events.each do |tag, time, record|
644
+ header = {'Content-Type'=>'application/msgpack', 'Content-Encoding'=>'deflate'}
645
+ res = post("/#{tag}?time=#{time}", Zlib.deflate(record.to_msgpack), header)
646
+ res_codes << res.code
647
+ end
648
+ end
649
+ assert_equal ["200", "200"], res_codes
650
+ assert_equal events, d.events
651
+ assert_equal_event_time time, d.events[0][1]
652
+ assert_equal_event_time time, d.events[1][1]
653
+ end
654
+
552
655
  def test_cors_disallowed
553
656
  d = create_driver(CONFIG + "cors_allow_origins [\"http://foo.com\"]")
554
657
  assert_equal ["http://foo.com"], d.instance.cors_allow_origins
@@ -639,6 +742,13 @@ class HttpInputTest < Test::Unit::TestCase
639
742
  http.request(req)
640
743
  end
641
744
 
745
+ def compress_gzip(data)
746
+ io = StringIO.new
747
+ io.binmode
748
+ Zlib::GzipWriter.wrap(io) { |gz| gz.write data }
749
+ return io.string
750
+ end
751
+
642
752
  def include_http_header?(record)
643
753
  record.keys.find { |header| header.start_with?('HTTP_') }
644
754
  end
@@ -304,7 +304,11 @@ class FileOutputTest < Test::Unit::TestCase
304
304
  assert_equal r4, d.formatted[3]
305
305
  assert_equal r5, d.formatted[4]
306
306
 
307
- read_gunzip = ->(path){ File.open(path){|fio| Zlib::GzipReader.open(fio){|io| io.read } } }
307
+ read_gunzip = ->(path){
308
+ File.open(path){ |fio|
309
+ Zlib::GzipReader.new(StringIO.new(fio.read)).read
310
+ }
311
+ }
308
312
  assert_equal r1 + r2, read_gunzip.call("#{TMP_DIR}/my.data/a/full.20161003.2345.log.gz")
309
313
  assert_equal r3, read_gunzip.call("#{TMP_DIR}/your.data/a/full.20161003.2345.log.gz")
310
314
  assert_equal r4, read_gunzip.call("#{TMP_DIR}/my.data/a/full.20161004.0000.log.gz")
@@ -370,7 +374,7 @@ class FileOutputTest < Test::Unit::TestCase
370
374
  result = ''
371
375
  File.open(path, "rb") { |io|
372
376
  loop do
373
- gzr = Zlib::GzipReader.new(io)
377
+ gzr = Zlib::GzipReader.new(StringIO.new(io.read))
374
378
  result << gzr.read
375
379
  unused = gzr.unused
376
380
  gzr.finish
@@ -422,7 +422,7 @@ class RetryStateHelperTest < Test::Unit::TestCase
422
422
 
423
423
  sub_test_case 'exponential backoff' do
424
424
  test 'too big steps(check inf handling)' do
425
- s = @d.retry_state_create(:t11, :exponential_backoff, 0.1, 300, randomize: false, forever: true, backoff_base: 2)
425
+ s = @d.retry_state_create(:t11, :exponential_backoff, 1, 300, randomize: false, forever: true, backoff_base: 2)
426
426
  dummy_current_time = s.start
427
427
  override_current_time(s, dummy_current_time)
428
428
 
@@ -431,7 +431,7 @@ class RetryStateHelperTest < Test::Unit::TestCase
431
431
  if i >= 1025
432
432
  # With this setting, 1025+ number causes inf in `calc_interval`, so 1024 value is used for next_time
433
433
  assert_nothing_raised(FloatDomainError) { s.step }
434
- assert_equal (dummy_current_time + 0.1 * (2 ** (1024 - 1))), s.next_time
434
+ assert_equal (dummy_current_time + (2 ** (1024 - 1))), s.next_time
435
435
  else
436
436
  s.step
437
437
  end
@@ -65,13 +65,13 @@ match('aa')
65
65
  e0 = root.elements[0]
66
66
  assert_equal 'source', e0.name
67
67
  assert_equal '', e0.arg
68
- assert_equal 'forward', e0['type']
68
+ assert_equal 'forward', e0['@type']
69
69
  assert_equal '24224', e0['port']
70
70
 
71
71
  e1 = root.elements[1]
72
72
  assert_equal 'match', e1.name
73
73
  assert_equal 'test.**', e1.arg
74
- assert_equal 'forward', e1['type']
74
+ assert_equal 'forward', e1['@type']
75
75
  assert_equal '1s', e1['flush_interval']
76
76
  assert_equal 2, e1.elements.size
77
77
  e1s0 = e1.elements[0]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluentd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-12 00:00:00.000000000 Z
11
+ date: 2018-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -749,7 +749,7 @@ files:
749
749
  - test/test_time_formatter.rb
750
750
  - test/test_time_parser.rb
751
751
  - test/test_unique_id.rb
752
- homepage: https://fluentd.org/
752
+ homepage: https://www.fluentd.org/
753
753
  licenses:
754
754
  - Apache-2.0
755
755
  metadata: {}