fluentd 1.1.2 → 1.1.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
  SHA1:
3
- metadata.gz: e20dab78cc15d81c32ba9cd70fd5a806c6234a73
4
- data.tar.gz: 2c133e7665781dcc0d97da8459489ce3edf46f8f
3
+ metadata.gz: 3a26c51f262d85284f6ec0144fcab0088682efa9
4
+ data.tar.gz: 74f6bf4722ca406b51e678b7c0037f8f0c2e0a16
5
5
  SHA512:
6
- metadata.gz: 3d3775f9459c4c5ee8747c39596d2750e51ae6e0bab04958c6162d1faad4a6afd7deb2bcce27ed14b2f1eb925666554d444506cc30408a5db898f29aab3c6258
7
- data.tar.gz: c67fcc90f8f3717b73f4d3d78d5899881c688d52d3a39d4b0e112412092973a65d86ca7e9930326f894f3e896013afa42971532db895d67ecbc6e48c5b12180b
6
+ metadata.gz: 5de45a297b116281323d7c1d6cba55e46300c77025e4fa5f59de6be27bb21606448c3c2c86142c69e7b5ba4da0cbadb2b3f0acc23af6d3046c55521080559767
7
+ data.tar.gz: e9b1ddc803810bfd8b98fd2b3d5378bc1f50802b72e7343772b5bef229d8982d6d5e5a2aabf075c1ebe6d8d7a24c7931a3e95833f5e731943cf4d98f2bc66abc
@@ -1,5 +1,25 @@
1
1
  # v1.1
2
2
 
3
+ ## Release v1.1.3 - 2018/04/03
4
+
5
+ ### Enhancements
6
+
7
+ * output: Support negative index for tag placeholders
8
+ https://github.com/fluent/fluentd/pull/1908
9
+ * buffer: Add queued_chunks_limit_size to control the number of queued chunks
10
+ https://github.com/fluent/fluentd/pull/1916
11
+ * time: Make Fluent::EventTime human readable for inspect
12
+ https://github.com/fluent/fluentd/pull/1915
13
+
14
+ ### Bug fixes
15
+
16
+ * output: Delete empty queued_num field after purging chunks
17
+ https://github.com/fluent/fluentd/pull/1919
18
+ * fluent-debug: Fix usage message of fluent-debug command
19
+ https://github.com/fluent/fluentd/pull/1920
20
+ * out_forward: The node should be disabled when TLS socket for ack returns an error
21
+ https://github.com/fluent/fluentd/pull/1925
22
+
3
23
  ## Release v1.1.2 - 2018/03/18
4
24
 
5
25
  ### Enhancements
@@ -36,6 +36,7 @@ Here are some things that would increase a chance that your patch is accepted:
36
36
  * Write tests.
37
37
  * Run tests before send Pull Request by `bundle exec rake test`
38
38
  * Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
39
+ * Fluentd repositories needs [DCO](https://github.com/apps/dco) on PR. Please add `Signed-off-by` to the commit(See DCO link for more detail).
39
40
 
40
41
  There are some patches which are hard to write tests, e.g. process handling, concurrency issue or etc.
41
42
  In such case, please don't hesitate to submit a Pull Request.
@@ -91,9 +91,9 @@ include Fluent
91
91
 
92
92
  puts "Connected to #{uri}."
93
93
  puts "Usage:"
94
- puts " Fluent::Engine.match('some.tag').output : get an output plugin instance"
95
- puts " Fluent::Engine.sources[i] : get input plugin instances"
96
- puts " Fluent::Plugin.load_plugin(type,name) : load plugin class (use this if you get DRb::DRbUnknown)"
94
+ puts " Fluent::Engine.root_agent.event_router.match('some.tag') : get an output plugin instance"
95
+ puts " Fluent::Engine.root_agent.inputs[i] : get input plugin instances"
96
+ puts " Fluent::Plugin::OUTPUT_REGISTRY.lookup(name) : load output plugin class (use this if you get DRb::DRbUnknown)"
97
97
  puts ""
98
98
 
99
99
  Encoding.default_internal = nil if Encoding.respond_to?(:default_internal)
@@ -55,6 +55,9 @@ module Fluent
55
55
  # if chunk size (or records) is 95% or more after #write, then that chunk will be enqueued
56
56
  config_param :chunk_full_threshold, :float, default: DEFAULT_CHUNK_FULL_THRESHOLD
57
57
 
58
+ desc 'The max number of queued chunks.'
59
+ config_param :queued_chunks_limit_size, :integer, default: nil
60
+
58
61
  desc 'Compress buffered data.'
59
62
  config_param :compress, :enum, list: [:text, :gzip], default: :text
60
63
 
@@ -367,6 +370,10 @@ module Fluent
367
370
  end
368
371
  end
369
372
 
373
+ def queue_full?
374
+ @queued_chunks_limit_size && (synchronize { @queue.size } >= @queued_chunks_limit_size)
375
+ end
376
+
370
377
  def queued_records
371
378
  synchronize { @queue.reduce(0){|r, chunk| r + chunk.size } }
372
379
  end
@@ -421,11 +428,13 @@ module Fluent
421
428
  end
422
429
  end
423
430
 
424
- def enqueue_all
431
+ # At flush_at_shutdown, all staged chunks should be enqueued for buffer flush. Set true to force_enqueue for it.
432
+ def enqueue_all(force_enqueue = false)
425
433
  log.on_trace { log.trace "enqueueing all chunks in buffer", instance: self.object_id }
426
434
 
427
435
  if block_given?
428
436
  synchronize{ @stage.keys }.each do |metadata|
437
+ return if !force_enqueue && queue_full?
429
438
  # NOTE: The following line might cause data race depending on Ruby implementations except CRuby
430
439
  # cf. https://github.com/fluent/fluentd/pull/1721#discussion_r146170251
431
440
  chunk = @stage[metadata]
@@ -435,6 +444,7 @@ module Fluent
435
444
  end
436
445
  else
437
446
  synchronize{ @stage.keys }.each do |metadata|
447
+ return if !force_enqueue && queue_full?
438
448
  enqueue_chunk(metadata)
439
449
  end
440
450
  end
@@ -489,6 +499,7 @@ module Fluent
489
499
 
490
500
  if metadata && !@stage[metadata] && (!@queued_num[metadata] || @queued_num[metadata] < 1)
491
501
  @metadata_list.delete(metadata)
502
+ @queued_num.delete(metadata)
492
503
  end
493
504
  log.trace "chunk purged", instance: self.object_id, chunk_id: dump_unique_id_hex(chunk_id), metadata: metadata
494
505
  end
@@ -425,7 +425,7 @@ module Fluent::Plugin
425
425
  def read_ack_from_sock(sock, unpacker)
426
426
  begin
427
427
  raw_data = sock.instance_of?(Fluent::PluginHelper::Socket::WrappedSocket::TLS) ? sock.readpartial(@read_length) : sock.recv(@read_length)
428
- rescue Errno::ECONNRESET
428
+ rescue Errno::ECONNRESET, EOFError # ECONNRESET for #recv, #EOFError for #readpartial
429
429
  raw_data = ""
430
430
  end
431
431
  info = @sock_ack_waiting_mutex.synchronize{ @sock_ack_waiting.find{|i| i.sock == sock } }
@@ -38,7 +38,7 @@ module Fluent
38
38
 
39
39
  CHUNK_KEY_PATTERN = /^[-_.@a-zA-Z0-9]+$/
40
40
  CHUNK_KEY_PLACEHOLDER_PATTERN = /\$\{[-_.@$a-zA-Z0-9]+\}/
41
- CHUNK_TAG_PLACEHOLDER_PATTERN = /\$\{(tag(?:\[\d+\])?)\}/
41
+ CHUNK_TAG_PLACEHOLDER_PATTERN = /\$\{(tag(?:\[-?\d+\])?)\}/
42
42
  CHUNK_ID_PLACEHOLDER_PATTERN = /\$\{chunk_id\}/
43
43
 
44
44
  CHUNKING_FIELD_WARN_NUM = 4
@@ -672,7 +672,7 @@ module Fluent
672
672
  str.scan(CHUNK_TAG_PLACEHOLDER_PATTERN).map(&:first).each do |ph|
673
673
  if ph == "tag"
674
674
  parts << -1
675
- elsif ph =~ /^tag\[(\d+)\]$/
675
+ elsif ph =~ /^tag\[(-?\d+)\]$/
676
676
  parts << $1.to_i
677
677
  end
678
678
  end
@@ -708,15 +708,17 @@ module Fluent
708
708
  @output_time_formatter_cache[str] ||= Fluent::Timezone.formatter(@timekey_zone, str)
709
709
  rvalue = @output_time_formatter_cache[str].call(metadata.timekey)
710
710
  end
711
- # ${tag}, ${tag[0]}, ${tag[1]}, ...
711
+ # ${tag}, ${tag[0]}, ${tag[1]}, ... , ${tag[-2]}, ${tag[-1]}
712
712
  if @chunk_key_tag
713
713
  if str.include?('${tag}')
714
714
  rvalue = rvalue.gsub('${tag}', metadata.tag)
715
715
  end
716
716
  if str =~ CHUNK_TAG_PLACEHOLDER_PATTERN
717
717
  hash = {}
718
- metadata.tag.split('.').each_with_index do |part, i|
718
+ tag_parts = metadata.tag.split('.')
719
+ tag_parts.each_with_index do |part, i|
719
720
  hash["${tag[#{i}]}"] = part
721
+ hash["${tag[#{i-tag_parts.size}]}"] = part
720
722
  end
721
723
  rvalue = rvalue.gsub(CHUNK_TAG_PLACEHOLDER_PATTERN, hash)
722
724
  end
@@ -1197,7 +1199,7 @@ module Fluent
1197
1199
 
1198
1200
  def force_flush
1199
1201
  if @buffering
1200
- @buffer.enqueue_all
1202
+ @buffer.enqueue_all(true)
1201
1203
  submit_flush_all
1202
1204
  end
1203
1205
  end
@@ -24,6 +24,7 @@ require 'fluent/config/error'
24
24
  module Fluent
25
25
  class EventTime
26
26
  TYPE = 0
27
+ FORMATTER = Strftime.new('%Y-%m-%d %H:%M:%S.%N %z')
27
28
 
28
29
  def initialize(sec, nsec = 0)
29
30
  @sec = sec
@@ -108,6 +109,10 @@ module Fluent
108
109
  def method_missing(name, *args, &block)
109
110
  @sec.send(name, *args, &block)
110
111
  end
112
+
113
+ def inspect
114
+ FORMATTER.exec(Time.at(self))
115
+ end
111
116
  end
112
117
 
113
118
  module TimeMixin
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '1.1.2'
19
+ VERSION = '1.1.3'
20
20
 
21
21
  end
@@ -331,6 +331,24 @@ class OutputTest < Test::Unit::TestCase
331
331
  assert_equal "/mypath/2016/04/11/20-30/fluentd.test.output/test/output/value1/value2/tail", @i.extract_placeholders(tmpl, c)
332
332
  end
333
333
 
334
+ data(:new_api => :chunk,
335
+ :old_api => :metadata)
336
+ test '#extract_placeholders can extract negative index with tag' do |api|
337
+ @i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'time,tag,key1,key2', {'timekey' => 60*30, 'timekey_zone' => "+0900"})]))
338
+ assert @i.chunk_key_time
339
+ assert @i.chunk_key_tag
340
+ assert_equal ['key1','key2'], @i.chunk_keys
341
+ tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[-1]}/${tag[-2]}/${key1}/${key2}/tail"
342
+ t = event_time('2016-04-11 20:30:00 +0900')
343
+ v = {key1: "value1", key2: "value2"}
344
+ c = if api == :chunk
345
+ create_chunk(timekey: t, tag: 'fluentd.test.output', variables: v)
346
+ else
347
+ create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
348
+ end
349
+ assert_equal "/mypath/2016/04/11/20-30/fluentd.test.output/output/test/value1/value2/tail", @i.extract_placeholders(tmpl, c)
350
+ end
351
+
334
352
  data(:new_api => :chunk,
335
353
  :old_api => :metadata)
336
354
  test '#extract_placeholders removes out-of-range tag part and unknown variable placeholders' do |api|
@@ -338,7 +356,7 @@ class OutputTest < Test::Unit::TestCase
338
356
  assert @i.chunk_key_time
339
357
  assert @i.chunk_key_tag
340
358
  assert_equal ['key1','key2'], @i.chunk_keys
341
- tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[3]}/${tag[4]}/${key3}/${key4}/tail"
359
+ tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[3]}/${tag[-4]}/${key3}/${key4}/tail"
342
360
  t = event_time('2016-04-11 20:30:00 +0900')
343
361
  v = {key1: "value1", key2: "value2"}
344
362
  c = if api == :chunk
@@ -483,6 +501,9 @@ class OutputTest < Test::Unit::TestCase
483
501
  assert_nothing_raised do
484
502
  @i.placeholder_validate!(:path, "/my/path/${tag}/file.${tag[2]}.log")
485
503
  end
504
+ assert_nothing_raised do
505
+ @i.placeholder_validate!(:path, "/my/path/${tag}/file.${tag[-1]}.log")
506
+ end
486
507
  end
487
508
 
488
509
  test 'raises configuration error for a template when variable key placeholders exist but chunk keys are missing' do
@@ -412,6 +412,68 @@ class BufferedOutputRetryTest < Test::Unit::TestCase
412
412
  assert{ @i.buffer.stage.size == 1 }
413
413
  assert{ chunks.all?{|c| c.empty? } }
414
414
  end
415
+
416
+ test 'output plugin limits queued chunks via queued_chunks_limit_size' do
417
+ chunk_key = 'tag'
418
+ hash = {
419
+ 'flush_interval' => 1,
420
+ 'flush_thread_burst_interval' => 0.1,
421
+ 'retry_randomize' => false,
422
+ 'retry_max_times' => 7,
423
+ 'queued_chunks_limit_size' => 2,
424
+ }
425
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
426
+ @i.register(:prefer_buffered_processing) { true }
427
+ @i.register(:format) { |tag,time,record| [tag,time.to_i,record].to_json + "\n" }
428
+ @i.register(:write) { |chunk| raise "yay, your #write must fail" }
429
+ @i.start
430
+ @i.after_start
431
+
432
+ @i.interrupt_flushes
433
+
434
+ now = Time.parse('2016-04-13 18:33:30 -0700')
435
+ Timecop.freeze(now)
436
+
437
+ @i.emit_events("test.tag.1", dummy_event_stream())
438
+
439
+ now = Time.parse('2016-04-13 18:33:31 -0700')
440
+ Timecop.freeze(now)
441
+
442
+ @i.emit_events("test.tag.2", dummy_event_stream())
443
+
444
+ @i.enqueue_thread_wait
445
+ @i.flush_thread_wakeup
446
+ waiting(4) { Thread.pass until @i.write_count > 0 && @i.num_errors > 0 }
447
+
448
+ assert { @i.buffer.queue.size > 0 }
449
+ assert { @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
450
+
451
+ assert { @i.write_count > 0 }
452
+ assert { @i.num_errors > 0 }
453
+
454
+ prev_write_count = @i.write_count
455
+ prev_num_errors = @i.num_errors
456
+
457
+ chunks = @i.buffer.queue.dup
458
+
459
+ 20.times do |i| # large times enough
460
+ now = @i.next_flush_time
461
+
462
+ Timecop.freeze(now)
463
+ @i.enqueue_thread_wait
464
+ @i.flush_thread_wakeup
465
+ waiting(4) { Thread.pass until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
466
+
467
+ @i.emit_events("test.tag.1", dummy_event_stream())
468
+ assert { @i.buffer.queue.size <= 2 }
469
+ assert { @i.buffer.stage.size == 1 } # all new data is stored into staged chunk
470
+
471
+ break if @i.buffer.queue.size == 0
472
+
473
+ prev_write_count = @i.write_count
474
+ prev_num_errors = @i.num_errors
475
+ end
476
+ end
415
477
  end
416
478
 
417
479
  sub_test_case 'bufferd output for retries with periodical retry' do
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.1.2
4
+ version: 1.1.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-03-19 00:00:00.000000000 Z
11
+ date: 2018-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack