fluentd 1.16.5 → 1.16.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +8 -1
- data/CHANGELOG.md +50 -0
- data/README.md +0 -2
- data/fluentd.gemspec +9 -1
- data/lib/fluent/command/fluentd.rb +1 -1
- data/lib/fluent/config/yaml_parser/parser.rb +4 -0
- data/lib/fluent/plugin/out_file.rb +8 -0
- data/lib/fluent/plugin/parser_json.rb +4 -12
- data/lib/fluent/supervisor.rb +1 -1
- data/lib/fluent/version.rb +1 -1
- data/lib/fluent/winsvc.rb +28 -3
- data/test/command/test_cat.rb +2 -2
- data/test/command/test_fluentd.rb +57 -10
- data/test/helper.rb +27 -7
- data/test/plugin/in_tail/test_io_handler.rb +13 -14
- data/test/plugin/in_tail/test_position_file.rb +6 -7
- data/test/plugin/out_forward/test_ack_handler.rb +3 -3
- data/test/plugin/out_forward/test_socket_cache.rb +3 -3
- data/test/plugin/test_in_forward.rb +2 -1
- data/test/plugin/test_in_http.rb +1 -1
- data/test/plugin/test_in_monitor_agent.rb +6 -6
- data/test/plugin/test_in_syslog.rb +25 -18
- data/test/plugin/test_in_tail.rb +4 -12
- data/test/plugin/test_in_tcp.rb +1 -1
- data/test/plugin/test_in_udp.rb +16 -10
- data/test/plugin/test_out_exec_filter.rb +12 -7
- data/test/plugin/test_out_file.rb +22 -2
- data/test/plugin/test_out_forward.rb +2 -3
- data/test/plugin/test_out_stream.rb +1 -1
- data/test/plugin/test_parser_json.rb +31 -0
- data/test/plugin_helper/test_http_server_helper.rb +1 -1
- data/test/plugin_helper/test_server.rb +64 -41
- data/test/plugin_helper/test_socket.rb +1 -1
- data/test/test_config.rb +6 -0
- data/test/test_event_router.rb +2 -2
- metadata +37 -9
@@ -5,24 +5,24 @@ require 'fluent/plugin/in_syslog'
|
|
5
5
|
class SyslogInputTest < Test::Unit::TestCase
|
6
6
|
def setup
|
7
7
|
Fluent::Test.setup
|
8
|
-
@port = unused_port
|
8
|
+
@port = unused_port(protocol: :udp)
|
9
9
|
end
|
10
10
|
|
11
11
|
def teardown
|
12
12
|
@port = nil
|
13
13
|
end
|
14
14
|
|
15
|
-
def ipv4_config
|
15
|
+
def ipv4_config(port = @port)
|
16
16
|
%[
|
17
|
-
port #{
|
17
|
+
port #{port}
|
18
18
|
bind 127.0.0.1
|
19
19
|
tag syslog
|
20
20
|
]
|
21
21
|
end
|
22
22
|
|
23
|
-
def ipv6_config
|
23
|
+
def ipv6_config(port = @port)
|
24
24
|
%[
|
25
|
-
port #{
|
25
|
+
port #{port}
|
26
26
|
bind ::1
|
27
27
|
tag syslog
|
28
28
|
]
|
@@ -69,7 +69,8 @@ EOS
|
|
69
69
|
'Use transport and protocol' => ["protocol_type udp\n<transport tcp>\n </transport>", :udp, :tcp])
|
70
70
|
def test_configure_protocol(param)
|
71
71
|
conf, proto_type, transport_proto_type = *param
|
72
|
-
|
72
|
+
port = unused_port(protocol: proto_type ? proto_type : transport_proto_type)
|
73
|
+
d = create_driver([ipv4_config(port), conf].join("\n"))
|
73
74
|
|
74
75
|
assert_equal(d.instance.protocol_type, proto_type)
|
75
76
|
assert_equal(d.instance.transport_config.protocol, transport_proto_type)
|
@@ -158,12 +159,13 @@ EOS
|
|
158
159
|
end
|
159
160
|
|
160
161
|
def test_msg_size_with_tcp
|
161
|
-
|
162
|
+
port = unused_port(protocol: :tcp)
|
163
|
+
d = create_driver([ipv4_config(port), "<transport tcp> \n</transport>"].join("\n"))
|
162
164
|
tests = create_test_case
|
163
165
|
|
164
166
|
d.run(expect_emits: 2) do
|
165
167
|
tests.each {|test|
|
166
|
-
TCPSocket.open('127.0.0.1',
|
168
|
+
TCPSocket.open('127.0.0.1', port) do |s|
|
167
169
|
s.send(test['msg'], 0)
|
168
170
|
end
|
169
171
|
}
|
@@ -189,11 +191,12 @@ EOS
|
|
189
191
|
end
|
190
192
|
|
191
193
|
def test_msg_size_with_same_tcp_connection
|
192
|
-
|
194
|
+
port = unused_port(protocol: :tcp)
|
195
|
+
d = create_driver([ipv4_config(port), "<transport tcp> \n</transport>"].join("\n"))
|
193
196
|
tests = create_test_case
|
194
197
|
|
195
198
|
d.run(expect_emits: 2) do
|
196
|
-
TCPSocket.open('127.0.0.1',
|
199
|
+
TCPSocket.open('127.0.0.1', port) do |s|
|
197
200
|
tests.each {|test|
|
198
201
|
s.send(test['msg'], 0)
|
199
202
|
}
|
@@ -347,12 +350,13 @@ EOS
|
|
347
350
|
|
348
351
|
sub_test_case 'octet counting frame' do
|
349
352
|
def test_msg_size_with_tcp
|
350
|
-
|
353
|
+
port = unused_port(protocol: :tcp)
|
354
|
+
d = create_driver([ipv4_config(port), "<transport tcp> \n</transport>", 'frame_type octet_count'].join("\n"))
|
351
355
|
tests = create_test_case
|
352
356
|
|
353
357
|
d.run(expect_emits: 2) do
|
354
358
|
tests.each {|test|
|
355
|
-
TCPSocket.open('127.0.0.1',
|
359
|
+
TCPSocket.open('127.0.0.1', port) do |s|
|
356
360
|
s.send(test['msg'], 0)
|
357
361
|
end
|
358
362
|
}
|
@@ -363,11 +367,12 @@ EOS
|
|
363
367
|
end
|
364
368
|
|
365
369
|
def test_msg_size_with_same_tcp_connection
|
366
|
-
|
370
|
+
port = unused_port(protocol: :tcp)
|
371
|
+
d = create_driver([ipv4_config(port), "<transport tcp> \n</transport>", 'frame_type octet_count'].join("\n"))
|
367
372
|
tests = create_test_case
|
368
373
|
|
369
374
|
d.run(expect_emits: 2) do
|
370
|
-
TCPSocket.open('127.0.0.1',
|
375
|
+
TCPSocket.open('127.0.0.1', port) do |s|
|
371
376
|
tests.each {|test|
|
372
377
|
s.send(test['msg'], 0)
|
373
378
|
}
|
@@ -469,7 +474,8 @@ EOS
|
|
469
474
|
end
|
470
475
|
|
471
476
|
def test_send_keepalive_packet_is_disabled_by_default
|
472
|
-
|
477
|
+
port = unused_port(protocol: :tcp)
|
478
|
+
d = create_driver(ipv4_config(port) + %[
|
473
479
|
<transport tcp>
|
474
480
|
</transport>
|
475
481
|
protocol tcp
|
@@ -479,19 +485,20 @@ EOS
|
|
479
485
|
|
480
486
|
def test_send_keepalive_packet_can_be_enabled
|
481
487
|
addr = "127.0.0.1"
|
482
|
-
|
488
|
+
port = unused_port(protocol: :tcp)
|
489
|
+
d = create_driver(ipv4_config(port) + %[
|
483
490
|
<transport tcp>
|
484
491
|
</transport>
|
485
492
|
send_keepalive_packet true
|
486
493
|
])
|
487
494
|
assert_true d.instance.send_keepalive_packet
|
488
495
|
mock.proxy(d.instance).server_create_connection(
|
489
|
-
:in_syslog_tcp_server,
|
496
|
+
:in_syslog_tcp_server, port,
|
490
497
|
bind: addr,
|
491
498
|
resolve_name: nil,
|
492
499
|
send_keepalive_packet: true)
|
493
500
|
d.run do
|
494
|
-
TCPSocket.open(addr,
|
501
|
+
TCPSocket.open(addr, port)
|
495
502
|
end
|
496
503
|
end
|
497
504
|
|
data/test/plugin/test_in_tail.rb
CHANGED
@@ -3172,9 +3172,7 @@ class TailInputTest < Test::Unit::TestCase
|
|
3172
3172
|
Fluent::FileWrapper.open("#{@tmp_dir}/tail.txt0", "ab") {|f| f.puts "file3 log2"}
|
3173
3173
|
end
|
3174
3174
|
|
3175
|
-
|
3176
|
-
inode_1 = tail_watchers[1]&.ino
|
3177
|
-
inode_2 = tail_watchers[2]&.ino
|
3175
|
+
pos_file_inode = tail_watchers[2].pe.read_inode
|
3178
3176
|
record_values = d.events.collect { |event| event[2]["message"] }.sort
|
3179
3177
|
position_entries = []
|
3180
3178
|
Fluent::FileWrapper.open("#{@tmp_dir}/tail.pos", "r") do |f|
|
@@ -3188,17 +3186,15 @@ class TailInputTest < Test::Unit::TestCase
|
|
3188
3186
|
{
|
3189
3187
|
record_values: ["file1 log1", "file1 log2", "file2 log1", "file2 log2", "file3 log1", "file3 log2"],
|
3190
3188
|
tail_watcher_paths: ["#{@tmp_dir}/tail.txt0", "#{@tmp_dir}/tail.txt0", "#{@tmp_dir}/tail.txt0"],
|
3191
|
-
tail_watcher_inodes: [inode_0, inode_1, inode_2],
|
3192
3189
|
tail_watcher_io_handler_opened_statuses: [false, false, false],
|
3193
3190
|
position_entries: [
|
3194
3191
|
# The recorded path is old, but it is no problem. The path is not used when using follow_inodes.
|
3195
|
-
["#{@tmp_dir}/tail.txt0", "0000000000000016",
|
3192
|
+
["#{@tmp_dir}/tail.txt0", "0000000000000016", pos_file_inode],
|
3196
3193
|
],
|
3197
3194
|
},
|
3198
3195
|
{
|
3199
3196
|
record_values: record_values,
|
3200
3197
|
tail_watcher_paths: tail_watchers.collect { |tw| tw.path },
|
3201
|
-
tail_watcher_inodes: tail_watchers.collect { |tw| tw.ino },
|
3202
3198
|
tail_watcher_io_handler_opened_statuses: tail_watchers.collect { |tw| tw.instance_variable_get(:@io_handler)&.opened? || false },
|
3203
3199
|
position_entries: position_entries
|
3204
3200
|
},
|
@@ -3253,9 +3249,7 @@ class TailInputTest < Test::Unit::TestCase
|
|
3253
3249
|
sleep 4
|
3254
3250
|
end
|
3255
3251
|
|
3256
|
-
|
3257
|
-
inode_1 = tail_watchers[1]&.ino
|
3258
|
-
inode_2 = tail_watchers[2]&.ino
|
3252
|
+
pos_file_inode = tail_watchers[2].pe.read_inode
|
3259
3253
|
record_values = d.events.collect { |event| event[2]["message"] }.sort
|
3260
3254
|
position_entries = []
|
3261
3255
|
Fluent::FileWrapper.open("#{@tmp_dir}/tail.pos", "r") do |f|
|
@@ -3269,16 +3263,14 @@ class TailInputTest < Test::Unit::TestCase
|
|
3269
3263
|
{
|
3270
3264
|
record_values: ["file1 log1", "file1 log2", "file2 log1", "file2 log2", "file3 log1", "file3 log2"],
|
3271
3265
|
tail_watcher_paths: ["#{@tmp_dir}/tail.txt0", "#{@tmp_dir}/tail.txt0", "#{@tmp_dir}/tail.txt0"],
|
3272
|
-
tail_watcher_inodes: [inode_0, inode_1, inode_2],
|
3273
3266
|
tail_watcher_io_handler_opened_statuses: [false, false, false],
|
3274
3267
|
position_entries: [
|
3275
|
-
["#{@tmp_dir}/tail.txt0", "0000000000000016",
|
3268
|
+
["#{@tmp_dir}/tail.txt0", "0000000000000016", pos_file_inode],
|
3276
3269
|
],
|
3277
3270
|
},
|
3278
3271
|
{
|
3279
3272
|
record_values: record_values,
|
3280
3273
|
tail_watcher_paths: tail_watchers.collect { |tw| tw.path },
|
3281
|
-
tail_watcher_inodes: tail_watchers.collect { |tw| tw.ino },
|
3282
3274
|
tail_watcher_io_handler_opened_statuses: tail_watchers.collect { |tw| tw.instance_variable_get(:@io_handler)&.opened? || false },
|
3283
3275
|
position_entries: position_entries
|
3284
3276
|
},
|
data/test/plugin/test_in_tcp.rb
CHANGED
data/test/plugin/test_in_udp.rb
CHANGED
@@ -5,7 +5,7 @@ require 'fluent/plugin/in_udp'
|
|
5
5
|
class UdpInputTest < Test::Unit::TestCase
|
6
6
|
def setup
|
7
7
|
Fluent::Test.setup
|
8
|
-
@port = unused_port
|
8
|
+
@port = unused_port(protocol: :udp)
|
9
9
|
end
|
10
10
|
|
11
11
|
def teardown
|
@@ -268,25 +268,31 @@ class UdpInputTest < Test::Unit::TestCase
|
|
268
268
|
|
269
269
|
test 'message_length_limit' do
|
270
270
|
message_length_limit = 32
|
271
|
+
|
272
|
+
if Fluent.windows?
|
273
|
+
expected_records = ["0" * 30, "4" * 30]
|
274
|
+
else
|
275
|
+
expected_records = 1.upto(3).collect do |i|
|
276
|
+
"#{i}" * message_length_limit
|
277
|
+
end
|
278
|
+
expected_records.prepend("0" * 30)
|
279
|
+
expected_records.append("4" * 30)
|
280
|
+
end
|
281
|
+
|
271
282
|
d = create_driver(base_config + %!
|
272
283
|
format none
|
273
284
|
message_length_limit #{message_length_limit}
|
274
285
|
!)
|
275
|
-
d.run(expect_records:
|
286
|
+
d.run(expect_records: expected_records.size, timeout: 5) do
|
276
287
|
create_udp_socket('127.0.0.1', @port) do |u|
|
277
|
-
|
288
|
+
u.send("0" * 30 + "\n", 0)
|
289
|
+
1.upto(3) do |i|
|
278
290
|
u.send("#{i}" * 40 + "\n", 0)
|
279
291
|
end
|
292
|
+
u.send("4" * 30 + "\n", 0)
|
280
293
|
end
|
281
294
|
end
|
282
295
|
|
283
|
-
if Fluent.windows?
|
284
|
-
expected_records = []
|
285
|
-
else
|
286
|
-
expected_records = 3.times.collect do |i|
|
287
|
-
"#{i}" * message_length_limit
|
288
|
-
end
|
289
|
-
end
|
290
296
|
actual_records = d.events.collect do |event|
|
291
297
|
event[2]["message"]
|
292
298
|
end
|
@@ -500,10 +500,18 @@ class ExecFilterOutputTest < Test::Unit::TestCase
|
|
500
500
|
d = create_driver(conf)
|
501
501
|
time = event_time('2011-01-02 13:14:15')
|
502
502
|
|
503
|
-
d.run(default_tag: 'test', expect_emits:
|
504
|
-
|
505
|
-
|
506
|
-
|
503
|
+
d.run(default_tag: 'test', expect_emits: 4) do
|
504
|
+
d.feed(time, {"k1" => 0})
|
505
|
+
d.flush
|
506
|
+
sleep 0.5
|
507
|
+
d.feed(time, {"k1" => 1})
|
508
|
+
d.flush
|
509
|
+
sleep 0.5
|
510
|
+
d.feed(time, {"k1" => 2})
|
511
|
+
d.flush
|
512
|
+
sleep 0.5
|
513
|
+
d.feed(time, {"k1" => 3})
|
514
|
+
end
|
507
515
|
|
508
516
|
assert_equal "2011-01-02 13:14:15\ttest\t0\n", d.formatted[0]
|
509
517
|
assert_equal "2011-01-02 13:14:15\ttest\t1\n", d.formatted[1]
|
@@ -524,9 +532,6 @@ class ExecFilterOutputTest < Test::Unit::TestCase
|
|
524
532
|
assert_equal pid_list[1], events[1][2]['child_pid']
|
525
533
|
assert_equal pid_list[0], events[2][2]['child_pid']
|
526
534
|
assert_equal pid_list[1], events[3][2]['child_pid']
|
527
|
-
|
528
|
-
ensure
|
529
|
-
d.run(start: false, shutdown: true)
|
530
535
|
end
|
531
536
|
|
532
537
|
# child process exits per 3 lines
|
@@ -130,7 +130,7 @@ class FileOutputTest < Test::Unit::TestCase
|
|
130
130
|
'path' => "#{TMP_DIR}/${tag}/${type}/conf_test.%Y%m%d.%H%M.log",
|
131
131
|
'add_path_suffix' => 'false',
|
132
132
|
'append' => "true",
|
133
|
-
'symlink_path' => "#{TMP_DIR}/conf_test.current.log",
|
133
|
+
'symlink_path' => "#{TMP_DIR}/${tag}/conf_test.current.log",
|
134
134
|
'compress' => 'gzip',
|
135
135
|
'recompress' => 'true',
|
136
136
|
}, [
|
@@ -183,6 +183,26 @@ class FileOutputTest < Test::Unit::TestCase
|
|
183
183
|
Fluent::Test::Driver::Output.new(Fluent::Plugin::NullOutput).configure(conf)
|
184
184
|
end
|
185
185
|
end
|
186
|
+
|
187
|
+
test 'warning for symlink_path not including correct placeholders corresponding to chunk keys' do
|
188
|
+
omit "Windows doesn't support symlink" if Fluent.windows?
|
189
|
+
conf = config_element('match', '**', {
|
190
|
+
'path' => "#{TMP_DIR}/${tag}/${key1}/${key2}/conf_test.%Y%m%d.%H%M.log",
|
191
|
+
'symlink_path' => "#{TMP_DIR}/conf_test.current.log",
|
192
|
+
}, [
|
193
|
+
config_element('buffer', 'time,tag,key1,key2', {
|
194
|
+
'@type' => 'file',
|
195
|
+
'timekey' => '1d',
|
196
|
+
'path' => "#{TMP_DIR}/buf_conf_test",
|
197
|
+
}),
|
198
|
+
])
|
199
|
+
assert_nothing_raised do
|
200
|
+
d = create_driver(conf)
|
201
|
+
assert do
|
202
|
+
d.logs.count { |log| log.include?("multiple chunks are competing for a single symlink_path") } == 2
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
186
206
|
end
|
187
207
|
|
188
208
|
sub_test_case 'fully configured output' do
|
@@ -314,7 +334,7 @@ class FileOutputTest < Test::Unit::TestCase
|
|
314
334
|
assert_equal r5, d.formatted[4]
|
315
335
|
|
316
336
|
read_gunzip = ->(path){
|
317
|
-
File.open(path){ |fio|
|
337
|
+
File.open(path, 'rb'){ |fio|
|
318
338
|
Zlib::GzipReader.new(StringIO.new(fio.read)).read
|
319
339
|
}
|
320
340
|
}
|
@@ -12,7 +12,8 @@ class ForwardOutputTest < Test::Unit::TestCase
|
|
12
12
|
FileUtils.rm_rf(TMP_DIR)
|
13
13
|
FileUtils.mkdir_p(TMP_DIR)
|
14
14
|
@d = nil
|
15
|
-
|
15
|
+
# forward plugin uses TCP and UDP sockets on the same port number
|
16
|
+
@target_port = unused_port(protocol: :all)
|
16
17
|
end
|
17
18
|
|
18
19
|
def teardown
|
@@ -610,7 +611,6 @@ EOL
|
|
610
611
|
|
611
612
|
@d = d = create_driver(config + %[
|
612
613
|
require_ack_response true
|
613
|
-
ack_response_timeout 1s
|
614
614
|
<buffer tag>
|
615
615
|
flush_mode immediate
|
616
616
|
retry_type periodic
|
@@ -658,7 +658,6 @@ EOL
|
|
658
658
|
|
659
659
|
@d = d = create_driver(config + %[
|
660
660
|
require_ack_response true
|
661
|
-
ack_response_timeout 10s
|
662
661
|
<buffer tag>
|
663
662
|
flush_mode immediate
|
664
663
|
retry_type periodic
|
@@ -8,6 +8,37 @@ class JsonParserTest < ::Test::Unit::TestCase
|
|
8
8
|
@parser = Fluent::Test::Driver::Parser.new(Fluent::Plugin::JSONParser)
|
9
9
|
end
|
10
10
|
|
11
|
+
sub_test_case "configure_json_parser" do
|
12
|
+
data("oj", [:oj, [Oj.method(:load), Oj::ParseError]])
|
13
|
+
data("json", [:json, [JSON.method(:load), JSON::ParserError]])
|
14
|
+
data("yajl", [:yajl, [Yajl.method(:load), Yajl::ParseError]])
|
15
|
+
def test_return_each_loader((input, expected_return))
|
16
|
+
result = @parser.instance.configure_json_parser(input)
|
17
|
+
assert_equal expected_return, result
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_raise_exception_for_unknown_input
|
21
|
+
assert_raise RuntimeError do
|
22
|
+
@parser.instance.configure_json_parser(:unknown)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_fall_back_oj_to_yajl_if_oj_not_available
|
27
|
+
stub(Fluent::OjOptions).available? { false }
|
28
|
+
|
29
|
+
result = @parser.instance.configure_json_parser(:oj)
|
30
|
+
|
31
|
+
assert_equal [Yajl.method(:load), Yajl::ParseError], result
|
32
|
+
logs = @parser.logs.collect do |log|
|
33
|
+
log.gsub(/\A\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-+]\d{4} /, "")
|
34
|
+
end
|
35
|
+
assert_equal(
|
36
|
+
["[info]: Oj is not installed, and failing back to Yajl for json parser\n"],
|
37
|
+
logs
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
11
42
|
data('oj' => 'oj', 'yajl' => 'yajl')
|
12
43
|
def test_parse(data)
|
13
44
|
@parser.configure('json_parser' => data)
|