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 +4 -4
- data/CHANGELOG.md +20 -0
- data/CONTRIBUTING.md +1 -0
- data/lib/fluent/command/debug.rb +3 -3
- data/lib/fluent/plugin/buffer.rb +12 -1
- data/lib/fluent/plugin/out_forward.rb +1 -1
- data/lib/fluent/plugin/output.rb +7 -5
- data/lib/fluent/time.rb +5 -0
- data/lib/fluent/version.rb +1 -1
- data/test/plugin/test_output.rb +22 -1
- data/test/plugin/test_output_as_buffered_retries.rb +62 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a26c51f262d85284f6ec0144fcab0088682efa9
|
4
|
+
data.tar.gz: 74f6bf4722ca406b51e678b7c0037f8f0c2e0a16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5de45a297b116281323d7c1d6cba55e46300c77025e4fa5f59de6be27bb21606448c3c2c86142c69e7b5ba4da0cbadb2b3f0acc23af6d3046c55521080559767
|
7
|
+
data.tar.gz: e9b1ddc803810bfd8b98fd2b3d5378bc1f50802b72e7343772b5bef229d8982d6d5e5a2aabf075c1ebe6d8d7a24c7931a3e95833f5e731943cf4d98f2bc66abc
|
data/CHANGELOG.md
CHANGED
@@ -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
|
data/CONTRIBUTING.md
CHANGED
@@ -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.
|
data/lib/fluent/command/debug.rb
CHANGED
@@ -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')
|
95
|
-
puts " Fluent::Engine.
|
96
|
-
puts " Fluent::Plugin.
|
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)
|
data/lib/fluent/plugin/buffer.rb
CHANGED
@@ -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
|
-
|
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 } }
|
data/lib/fluent/plugin/output.rb
CHANGED
@@ -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(?:\[
|
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\[(
|
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('.')
|
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
|
data/lib/fluent/time.rb
CHANGED
@@ -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
|
data/lib/fluent/version.rb
CHANGED
data/test/plugin/test_output.rb
CHANGED
@@ -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.
|
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-
|
11
|
+
date: 2018-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|