fluentd 1.16.8 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.github/DISCUSSION_TEMPLATE/q-a-japanese.yml +50 -0
  3. data/.github/DISCUSSION_TEMPLATE/q-a.yml +47 -0
  4. data/.github/workflows/test-ruby-head.yml +31 -0
  5. data/.github/workflows/test.yml +2 -13
  6. data/CHANGELOG.md +33 -69
  7. data/README.md +3 -1
  8. data/Rakefile +1 -1
  9. data/fluentd.gemspec +9 -10
  10. data/lib/fluent/command/binlog_reader.rb +1 -1
  11. data/lib/fluent/command/fluentd.rb +1 -1
  12. data/lib/fluent/compat/formatter.rb +0 -6
  13. data/lib/fluent/config/configure_proxy.rb +2 -2
  14. data/lib/fluent/config/parser.rb +3 -15
  15. data/lib/fluent/config/types.rb +1 -1
  16. data/lib/fluent/config/v1_parser.rb +1 -1
  17. data/lib/fluent/config/yaml_parser/parser.rb +0 -4
  18. data/lib/fluent/configurable.rb +2 -2
  19. data/lib/fluent/counter/mutex_hash.rb +1 -1
  20. data/lib/fluent/fluent_log_event_router.rb +0 -2
  21. data/lib/fluent/plugin/buf_file.rb +1 -1
  22. data/lib/fluent/plugin/buffer/file_chunk.rb +1 -1
  23. data/lib/fluent/plugin/buffer/file_single_chunk.rb +2 -3
  24. data/lib/fluent/plugin/filter_parser.rb +26 -8
  25. data/lib/fluent/plugin/formatter_csv.rb +4 -18
  26. data/lib/fluent/plugin/in_http.rb +17 -52
  27. data/lib/fluent/plugin/in_tail.rb +35 -3
  28. data/lib/fluent/plugin/out_file.rb +0 -8
  29. data/lib/fluent/plugin/out_http.rb +125 -13
  30. data/lib/fluent/plugin/owned_by_mixin.rb +0 -1
  31. data/lib/fluent/plugin/parser_json.rb +34 -9
  32. data/lib/fluent/plugin/parser_msgpack.rb +24 -3
  33. data/lib/fluent/plugin_helper/metrics.rb +2 -2
  34. data/lib/fluent/registry.rb +6 -6
  35. data/lib/fluent/supervisor.rb +3 -3
  36. data/lib/fluent/test/output_test.rb +1 -1
  37. data/lib/fluent/unique_id.rb +1 -1
  38. data/lib/fluent/version.rb +1 -1
  39. data/lib/fluent/winsvc.rb +8 -38
  40. data/test/command/test_cat.rb +2 -2
  41. data/test/command/test_fluentd.rb +10 -57
  42. data/test/config/test_plugin_configuration.rb +6 -6
  43. data/test/helper.rb +7 -27
  44. data/test/log/test_console_adapter.rb +10 -3
  45. data/test/plugin/data/log_numeric/01.log +0 -0
  46. data/test/plugin/data/log_numeric/02.log +0 -0
  47. data/test/plugin/data/log_numeric/12.log +0 -0
  48. data/test/plugin/data/log_numeric/14.log +0 -0
  49. data/test/plugin/in_tail/test_io_handler.rb +14 -13
  50. data/test/plugin/in_tail/test_position_file.rb +7 -6
  51. data/test/plugin/out_forward/test_ack_handler.rb +3 -3
  52. data/test/plugin/out_forward/test_socket_cache.rb +3 -3
  53. data/test/plugin/test_buffer.rb +2 -2
  54. data/test/plugin/test_filter_grep.rb +1 -1
  55. data/test/plugin/test_in_forward.rb +1 -2
  56. data/test/plugin/test_in_http.rb +23 -1
  57. data/test/plugin/test_in_monitor_agent.rb +6 -6
  58. data/test/plugin/test_in_syslog.rb +18 -25
  59. data/test/plugin/test_in_tail.rb +153 -5
  60. data/test/plugin/test_in_tcp.rb +1 -1
  61. data/test/plugin/test_in_udp.rb +10 -16
  62. data/test/plugin/test_out_exec_filter.rb +7 -12
  63. data/test/plugin/test_out_file.rb +2 -22
  64. data/test/plugin/test_out_forward.rb +3 -2
  65. data/test/plugin/test_out_http.rb +128 -0
  66. data/test/plugin/test_out_stream.rb +1 -1
  67. data/test/plugin/test_output.rb +1 -1
  68. data/test/plugin/test_output_as_buffered.rb +2 -2
  69. data/test/plugin/test_output_as_buffered_retries.rb +2 -2
  70. data/test/plugin/test_owned_by.rb +0 -1
  71. data/test/plugin/test_parser_csv.rb +1 -1
  72. data/test/plugin/test_parser_json.rb +106 -31
  73. data/test/plugin/test_parser_msgpack.rb +127 -0
  74. data/test/plugin/test_storage.rb +0 -1
  75. data/test/plugin_helper/test_child_process.rb +4 -4
  76. data/test/plugin_helper/test_http_server_helper.rb +1 -1
  77. data/test/plugin_helper/test_server.rb +41 -64
  78. data/test/plugin_helper/test_socket.rb +1 -1
  79. data/test/test_config.rb +0 -6
  80. data/test/test_event_router.rb +2 -2
  81. data/test/test_supervisor.rb +21 -30
  82. data/test/test_tls.rb +1 -1
  83. metadata +85 -16
@@ -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(protocol: :udp)
8
+ @port = unused_port
9
9
  end
10
10
 
11
11
  def teardown
12
12
  @port = nil
13
13
  end
14
14
 
15
- def ipv4_config(port = @port)
15
+ def ipv4_config
16
16
  %[
17
- port #{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(port = @port)
23
+ def ipv6_config
24
24
  %[
25
- port #{port}
25
+ port #{@port}
26
26
  bind ::1
27
27
  tag syslog
28
28
  ]
@@ -69,8 +69,7 @@ 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
- port = unused_port(protocol: proto_type ? proto_type : transport_proto_type)
73
- d = create_driver([ipv4_config(port), conf].join("\n"))
72
+ d = create_driver([ipv4_config, conf].join("\n"))
74
73
 
75
74
  assert_equal(d.instance.protocol_type, proto_type)
76
75
  assert_equal(d.instance.transport_config.protocol, transport_proto_type)
@@ -159,13 +158,12 @@ EOS
159
158
  end
160
159
 
161
160
  def test_msg_size_with_tcp
162
- port = unused_port(protocol: :tcp)
163
- d = create_driver([ipv4_config(port), "<transport tcp> \n</transport>"].join("\n"))
161
+ d = create_driver([ipv4_config, "<transport tcp> \n</transport>"].join("\n"))
164
162
  tests = create_test_case
165
163
 
166
164
  d.run(expect_emits: 2) do
167
165
  tests.each {|test|
168
- TCPSocket.open('127.0.0.1', port) do |s|
166
+ TCPSocket.open('127.0.0.1', @port) do |s|
169
167
  s.send(test['msg'], 0)
170
168
  end
171
169
  }
@@ -191,12 +189,11 @@ EOS
191
189
  end
192
190
 
193
191
  def test_msg_size_with_same_tcp_connection
194
- port = unused_port(protocol: :tcp)
195
- d = create_driver([ipv4_config(port), "<transport tcp> \n</transport>"].join("\n"))
192
+ d = create_driver([ipv4_config, "<transport tcp> \n</transport>"].join("\n"))
196
193
  tests = create_test_case
197
194
 
198
195
  d.run(expect_emits: 2) do
199
- TCPSocket.open('127.0.0.1', port) do |s|
196
+ TCPSocket.open('127.0.0.1', @port) do |s|
200
197
  tests.each {|test|
201
198
  s.send(test['msg'], 0)
202
199
  }
@@ -350,13 +347,12 @@ EOS
350
347
 
351
348
  sub_test_case 'octet counting frame' do
352
349
  def test_msg_size_with_tcp
353
- port = unused_port(protocol: :tcp)
354
- d = create_driver([ipv4_config(port), "<transport tcp> \n</transport>", 'frame_type octet_count'].join("\n"))
350
+ d = create_driver([ipv4_config, "<transport tcp> \n</transport>", 'frame_type octet_count'].join("\n"))
355
351
  tests = create_test_case
356
352
 
357
353
  d.run(expect_emits: 2) do
358
354
  tests.each {|test|
359
- TCPSocket.open('127.0.0.1', port) do |s|
355
+ TCPSocket.open('127.0.0.1', @port) do |s|
360
356
  s.send(test['msg'], 0)
361
357
  end
362
358
  }
@@ -367,12 +363,11 @@ EOS
367
363
  end
368
364
 
369
365
  def test_msg_size_with_same_tcp_connection
370
- port = unused_port(protocol: :tcp)
371
- d = create_driver([ipv4_config(port), "<transport tcp> \n</transport>", 'frame_type octet_count'].join("\n"))
366
+ d = create_driver([ipv4_config, "<transport tcp> \n</transport>", 'frame_type octet_count'].join("\n"))
372
367
  tests = create_test_case
373
368
 
374
369
  d.run(expect_emits: 2) do
375
- TCPSocket.open('127.0.0.1', port) do |s|
370
+ TCPSocket.open('127.0.0.1', @port) do |s|
376
371
  tests.each {|test|
377
372
  s.send(test['msg'], 0)
378
373
  }
@@ -474,8 +469,7 @@ EOS
474
469
  end
475
470
 
476
471
  def test_send_keepalive_packet_is_disabled_by_default
477
- port = unused_port(protocol: :tcp)
478
- d = create_driver(ipv4_config(port) + %[
472
+ d = create_driver(ipv4_config + %[
479
473
  <transport tcp>
480
474
  </transport>
481
475
  protocol tcp
@@ -485,20 +479,19 @@ EOS
485
479
 
486
480
  def test_send_keepalive_packet_can_be_enabled
487
481
  addr = "127.0.0.1"
488
- port = unused_port(protocol: :tcp)
489
- d = create_driver(ipv4_config(port) + %[
482
+ d = create_driver(ipv4_config + %[
490
483
  <transport tcp>
491
484
  </transport>
492
485
  send_keepalive_packet true
493
486
  ])
494
487
  assert_true d.instance.send_keepalive_packet
495
488
  mock.proxy(d.instance).server_create_connection(
496
- :in_syslog_tcp_server, port,
489
+ :in_syslog_tcp_server, @port,
497
490
  bind: addr,
498
491
  resolve_name: nil,
499
492
  send_keepalive_packet: true)
500
493
  d.run do
501
- TCPSocket.open(addr, port)
494
+ TCPSocket.open(addr, @port)
502
495
  end
503
496
  end
504
497
 
@@ -1538,6 +1538,147 @@ class TailInputTest < Test::Unit::TestCase
1538
1538
  assert_equal(ex_paths - [ex_paths.last], plugin.expand_paths.values.sort_by { |path_ino| path_ino.path })
1539
1539
  end
1540
1540
 
1541
+ sub_test_case "expand_paths with glob" do |data|
1542
+ sub_test_case "extended_glob" do
1543
+ data("curly braces" => [true, "always", "test/plugin/data/log_numeric/{0,1}*.log"],
1544
+ "square brackets" => [true, "always", "test/plugin/data/log_numeric/[0-1][2-4].log"],
1545
+ "asterisk" => [true, "always", "test/plugin/data/log/*.log"],
1546
+ "one character matcher" => [true, "always", "test/plugin/data/log/tes?.log"],
1547
+ )
1548
+ def test_expand_paths_with_use_glob_p_and_almost_set_of_patterns
1549
+ result, option, path = data
1550
+ config = config_element("", "", {
1551
+ "tag" => "tail",
1552
+ "path" => path,
1553
+ "format" => "none",
1554
+ "pos_file" => "#{@tmp_dir}/tail.pos",
1555
+ "read_from_head" => true,
1556
+ "refresh_interval" => 30,
1557
+ "glob_policy" => option,
1558
+ "path_delimiter" => "|",
1559
+ "rotate_wait" => "#{EX_ROTATE_WAIT}s",
1560
+ "follow_inodes" => "#{EX_FOLLOW_INODES}",
1561
+ })
1562
+ plugin = create_driver(config, false).instance
1563
+ assert_equal(result, !!plugin.use_glob?(path))
1564
+ end
1565
+
1566
+ data("curly braces" => [true, false, "extended", "test/plugin/data/log_numeric/{0,1}*.log"],
1567
+ "square brackets" => [false, true, "extended", "test/plugin/data/log_numeric/[0-1][2-4].log"],
1568
+ "asterisk" => [false, true, "extended", "test/plugin/data/log/*.log"],
1569
+ "one character matcher" => [false, true, "extended", "test/plugin/data/log/tes?.log"],
1570
+ )
1571
+ def test_expand_paths_with_use_glob_p
1572
+ emit_exception_p, result, option, path = data
1573
+ config = config_element("", "", {
1574
+ "tag" => "tail",
1575
+ "path" => path,
1576
+ "format" => "none",
1577
+ "pos_file" => "#{@tmp_dir}/tail.pos",
1578
+ "read_from_head" => true,
1579
+ "refresh_interval" => 30,
1580
+ "glob_policy" => option,
1581
+ "rotate_wait" => "#{EX_ROTATE_WAIT}s",
1582
+ "follow_inodes" => "#{EX_FOLLOW_INODES}",
1583
+ })
1584
+ if emit_exception_p
1585
+ assert_raise(Fluent::ConfigError) do
1586
+ plugin = create_driver(config, false).instance
1587
+ end
1588
+ else
1589
+ plugin = create_driver(config, false).instance
1590
+ assert_equal(result, !!plugin.use_glob?(path))
1591
+ end
1592
+ end
1593
+ end
1594
+
1595
+ sub_test_case "only_use_backward_compatible" do
1596
+ data("square brackets" => [false, "backward_compatible", "test/plugin/data/log_numeric/[0-1][2-4].log"],
1597
+ "asterisk" => [true, "backward_compatible", "test/plugin/data/log/*.log"],
1598
+ "one character matcher" => [false, "backward_compatible", "test/plugin/data/log/tes?.log"],
1599
+ )
1600
+ def test_expand_paths_with_use_glob_p
1601
+ result, option, path = data
1602
+ config = config_element("", "", {
1603
+ "tag" => "tail",
1604
+ "path" => path,
1605
+ "format" => "none",
1606
+ "pos_file" => "#{@tmp_dir}/tail.pos",
1607
+ "read_from_head" => true,
1608
+ "refresh_interval" => 30,
1609
+ "glob_policy" => option,
1610
+ "rotate_wait" => "#{EX_ROTATE_WAIT}s",
1611
+ "follow_inodes" => "#{EX_FOLLOW_INODES}",
1612
+ })
1613
+ plugin = create_driver(config, false).instance
1614
+ assert_equal(result, !!plugin.use_glob?(path))
1615
+ end
1616
+ end
1617
+ end
1618
+
1619
+ def ex_config_with_brackets
1620
+ config_element("", "", {
1621
+ "tag" => "tail",
1622
+ "path" => "test/plugin/data/log_numeric/[0-1][2-4].log",
1623
+ "format" => "none",
1624
+ "pos_file" => "#{@tmp_dir}/tail.pos",
1625
+ "read_from_head" => true,
1626
+ "refresh_interval" => 30,
1627
+ "glob_policy" => "extended",
1628
+ "rotate_wait" => "#{EX_ROTATE_WAIT}s",
1629
+ "follow_inodes" => "#{EX_FOLLOW_INODES}",
1630
+ })
1631
+ end
1632
+
1633
+ def test_config_with_always_with_default_delimiter
1634
+ assert_raise(Fluent::ConfigError) do
1635
+ config = config_element("", "", {
1636
+ "tag" => "tail",
1637
+ "path" => "test/plugin/data/log_numeric/[0-1][2-4].log",
1638
+ "format" => "none",
1639
+ "pos_file" => "#{@tmp_dir}/tail.pos",
1640
+ "read_from_head" => true,
1641
+ "refresh_interval" => 30,
1642
+ "glob_policy" => "always",
1643
+ "rotate_wait" => "#{EX_ROTATE_WAIT}s",
1644
+ "follow_inodes" => "#{EX_FOLLOW_INODES}",
1645
+ })
1646
+
1647
+ create_driver(config, false).instance
1648
+ end
1649
+ end
1650
+
1651
+ def test_config_with_always_with_custom_delimiter
1652
+ assert_nothing_raised do
1653
+ config = config_element("", "", {
1654
+ "tag" => "tail",
1655
+ "path" => "test/plugin/data/log_numeric/[0-1][2-4].log",
1656
+ "format" => "none",
1657
+ "pos_file" => "#{@tmp_dir}/tail.pos",
1658
+ "read_from_head" => true,
1659
+ "refresh_interval" => 30,
1660
+ "glob_policy" => "always",
1661
+ "path_delimiter" => "|",
1662
+ "rotate_wait" => "#{EX_ROTATE_WAIT}s",
1663
+ "follow_inodes" => "#{EX_FOLLOW_INODES}",
1664
+ })
1665
+
1666
+ create_driver(config, false).instance
1667
+ end
1668
+ end
1669
+
1670
+ def test_expand_paths_with_brackets
1671
+ expanded_paths = [
1672
+ create_target_info('test/plugin/data/log_numeric/01.log'),
1673
+ create_target_info('test/plugin/data/log_numeric/02.log'),
1674
+ create_target_info('test/plugin/data/log_numeric/12.log'),
1675
+ create_target_info('test/plugin/data/log_numeric/14.log'),
1676
+ ]
1677
+
1678
+ plugin = create_driver(ex_config_with_brackets, false).instance
1679
+ assert_equal(expanded_paths - [expanded_paths.first], plugin.expand_paths.values.sort_by { |path_ino| path_ino.path })
1680
+ end
1681
+
1541
1682
  def test_expand_paths_with_duplicate_configuration
1542
1683
  expanded_paths = [
1543
1684
  create_target_info('test/plugin/data/log/foo/bar.log'),
@@ -1611,7 +1752,6 @@ class TailInputTest < Test::Unit::TestCase
1611
1752
 
1612
1753
  cleanup_file("#{@tmp_dir}/tail.txt")
1613
1754
  waiting(20) { sleep 0.1 until Dir.glob("#{@tmp_dir}/*.txt").size == 0 } # Ensure file is deleted on Windows
1614
- waiting(5) { sleep 0.1 until d.logs.last.include?("detected rotation") }
1615
1755
  waiting(5) { sleep 0.1 until d.instance.instance_variable_get(:@tails).keys.size <= 0 }
1616
1756
 
1617
1757
  assert_equal(
@@ -3173,7 +3313,9 @@ class TailInputTest < Test::Unit::TestCase
3173
3313
  Fluent::FileWrapper.open("#{@tmp_dir}/tail.txt0", "ab") {|f| f.puts "file3 log2"}
3174
3314
  end
3175
3315
 
3176
- pos_file_inode = tail_watchers[2].pe.read_inode
3316
+ inode_0 = tail_watchers[0]&.ino
3317
+ inode_1 = tail_watchers[1]&.ino
3318
+ inode_2 = tail_watchers[2]&.ino
3177
3319
  record_values = d.events.collect { |event| event[2]["message"] }.sort
3178
3320
  position_entries = []
3179
3321
  Fluent::FileWrapper.open("#{@tmp_dir}/tail.pos", "r") do |f|
@@ -3187,15 +3329,17 @@ class TailInputTest < Test::Unit::TestCase
3187
3329
  {
3188
3330
  record_values: ["file1 log1", "file1 log2", "file2 log1", "file2 log2", "file3 log1", "file3 log2"],
3189
3331
  tail_watcher_paths: ["#{@tmp_dir}/tail.txt0", "#{@tmp_dir}/tail.txt0", "#{@tmp_dir}/tail.txt0"],
3332
+ tail_watcher_inodes: [inode_0, inode_1, inode_2],
3190
3333
  tail_watcher_io_handler_opened_statuses: [false, false, false],
3191
3334
  position_entries: [
3192
3335
  # The recorded path is old, but it is no problem. The path is not used when using follow_inodes.
3193
- ["#{@tmp_dir}/tail.txt0", "0000000000000016", pos_file_inode],
3336
+ ["#{@tmp_dir}/tail.txt0", "0000000000000016", inode_2],
3194
3337
  ],
3195
3338
  },
3196
3339
  {
3197
3340
  record_values: record_values,
3198
3341
  tail_watcher_paths: tail_watchers.collect { |tw| tw.path },
3342
+ tail_watcher_inodes: tail_watchers.collect { |tw| tw.ino },
3199
3343
  tail_watcher_io_handler_opened_statuses: tail_watchers.collect { |tw| tw.instance_variable_get(:@io_handler)&.opened? || false },
3200
3344
  position_entries: position_entries
3201
3345
  },
@@ -3250,7 +3394,9 @@ class TailInputTest < Test::Unit::TestCase
3250
3394
  sleep 4
3251
3395
  end
3252
3396
 
3253
- pos_file_inode = tail_watchers[2].pe.read_inode
3397
+ inode_0 = tail_watchers[0]&.ino
3398
+ inode_1 = tail_watchers[1]&.ino
3399
+ inode_2 = tail_watchers[2]&.ino
3254
3400
  record_values = d.events.collect { |event| event[2]["message"] }.sort
3255
3401
  position_entries = []
3256
3402
  Fluent::FileWrapper.open("#{@tmp_dir}/tail.pos", "r") do |f|
@@ -3264,14 +3410,16 @@ class TailInputTest < Test::Unit::TestCase
3264
3410
  {
3265
3411
  record_values: ["file1 log1", "file1 log2", "file2 log1", "file2 log2", "file3 log1", "file3 log2"],
3266
3412
  tail_watcher_paths: ["#{@tmp_dir}/tail.txt0", "#{@tmp_dir}/tail.txt0", "#{@tmp_dir}/tail.txt0"],
3413
+ tail_watcher_inodes: [inode_0, inode_1, inode_2],
3267
3414
  tail_watcher_io_handler_opened_statuses: [false, false, false],
3268
3415
  position_entries: [
3269
- ["#{@tmp_dir}/tail.txt0", "0000000000000016", pos_file_inode],
3416
+ ["#{@tmp_dir}/tail.txt0", "0000000000000016", inode_2],
3270
3417
  ],
3271
3418
  },
3272
3419
  {
3273
3420
  record_values: record_values,
3274
3421
  tail_watcher_paths: tail_watchers.collect { |tw| tw.path },
3422
+ tail_watcher_inodes: tail_watchers.collect { |tw| tw.ino },
3275
3423
  tail_watcher_io_handler_opened_statuses: tail_watchers.collect { |tw| tw.instance_variable_get(:@io_handler)&.opened? || false },
3276
3424
  position_entries: position_entries
3277
3425
  },
@@ -5,7 +5,7 @@ require 'fluent/plugin/in_tcp'
5
5
  class TcpInputTest < Test::Unit::TestCase
6
6
  def setup
7
7
  Fluent::Test.setup
8
- @port = unused_port(protocol: :tcp)
8
+ @port = unused_port
9
9
  end
10
10
 
11
11
  def teardown
@@ -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(protocol: :udp)
8
+ @port = unused_port
9
9
  end
10
10
 
11
11
  def teardown
@@ -268,31 +268,25 @@ 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
-
282
271
  d = create_driver(base_config + %!
283
272
  format none
284
273
  message_length_limit #{message_length_limit}
285
274
  !)
286
- d.run(expect_records: expected_records.size, timeout: 5) do
275
+ d.run(expect_records: 3) do
287
276
  create_udp_socket('127.0.0.1', @port) do |u|
288
- u.send("0" * 30 + "\n", 0)
289
- 1.upto(3) do |i|
277
+ 3.times do |i|
290
278
  u.send("#{i}" * 40 + "\n", 0)
291
279
  end
292
- u.send("4" * 30 + "\n", 0)
293
280
  end
294
281
  end
295
282
 
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
296
290
  actual_records = d.events.collect do |event|
297
291
  event[2]["message"]
298
292
  end
@@ -500,18 +500,10 @@ 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: 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
503
+ d.run(default_tag: 'test', expect_emits: 1, timeout: 10, start: true, shutdown: false){ d.feed(time, {"k1" => 0}) }
504
+ d.run(default_tag: 'test', expect_emits: 1, timeout: 10, start: false, shutdown: false){ d.feed(time, {"k1" => 1}) }
505
+ d.run(default_tag: 'test', expect_emits: 1, timeout: 10, start: false, shutdown: false){ d.feed(time, {"k1" => 2}) }
506
+ d.run(default_tag: 'test', expect_emits: 1, timeout: 10, start: false, shutdown: false){ d.feed(time, {"k1" => 3}) }
515
507
 
516
508
  assert_equal "2011-01-02 13:14:15\ttest\t0\n", d.formatted[0]
517
509
  assert_equal "2011-01-02 13:14:15\ttest\t1\n", d.formatted[1]
@@ -532,6 +524,9 @@ class ExecFilterOutputTest < Test::Unit::TestCase
532
524
  assert_equal pid_list[1], events[1][2]['child_pid']
533
525
  assert_equal pid_list[0], events[2][2]['child_pid']
534
526
  assert_equal pid_list[1], events[3][2]['child_pid']
527
+
528
+ ensure
529
+ d.run(start: false, shutdown: true)
535
530
  end
536
531
 
537
532
  # 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}/${tag}/conf_test.current.log",
133
+ 'symlink_path' => "#{TMP_DIR}/conf_test.current.log",
134
134
  'compress' => 'gzip',
135
135
  'recompress' => 'true',
136
136
  }, [
@@ -183,26 +183,6 @@ 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
206
186
  end
207
187
 
208
188
  sub_test_case 'fully configured output' do
@@ -334,7 +314,7 @@ class FileOutputTest < Test::Unit::TestCase
334
314
  assert_equal r5, d.formatted[4]
335
315
 
336
316
  read_gunzip = ->(path){
337
- File.open(path, 'rb'){ |fio|
317
+ File.open(path){ |fio|
338
318
  Zlib::GzipReader.new(StringIO.new(fio.read)).read
339
319
  }
340
320
  }
@@ -12,8 +12,7 @@ class ForwardOutputTest < Test::Unit::TestCase
12
12
  FileUtils.rm_rf(TMP_DIR)
13
13
  FileUtils.mkdir_p(TMP_DIR)
14
14
  @d = nil
15
- # forward plugin uses TCP and UDP sockets on the same port number
16
- @target_port = unused_port(protocol: :all)
15
+ @target_port = unused_port
17
16
  end
18
17
 
19
18
  def teardown
@@ -611,6 +610,7 @@ EOL
611
610
 
612
611
  @d = d = create_driver(config + %[
613
612
  require_ack_response true
613
+ ack_response_timeout 1s
614
614
  <buffer tag>
615
615
  flush_mode immediate
616
616
  retry_type periodic
@@ -658,6 +658,7 @@ EOL
658
658
 
659
659
  @d = d = create_driver(config + %[
660
660
  require_ack_response true
661
+ ack_response_timeout 10s
661
662
  <buffer tag>
662
663
  flush_mode immediate
663
664
  retry_type periodic
@@ -7,6 +7,7 @@ require 'webrick/https'
7
7
  require 'net/http'
8
8
  require 'uri'
9
9
  require 'json'
10
+ require 'aws-sdk-core'
10
11
 
11
12
  # WEBrick's ProcHandler doesn't handle PUT by default
12
13
  module WEBrick::HTTPServlet
@@ -390,6 +391,97 @@ class HTTPOutputTest < Test::Unit::TestCase
390
391
  end
391
392
  end
392
393
 
394
+
395
+ sub_test_case 'aws sigv4 auth' do
396
+ setup do
397
+ @@fake_aws_credentials = Aws::Credentials.new(
398
+ 'fakeaccess',
399
+ 'fakesecret',
400
+ 'fake session token'
401
+ )
402
+ end
403
+
404
+ def server_port
405
+ 19883
406
+ end
407
+
408
+ def test_aws_sigv4_sts_role_arn
409
+ stub(Aws::AssumeRoleCredentials).new do |credentials_provider|
410
+ stub(credentials_provider).credentials {
411
+ @@fake_aws_credentials
412
+ }
413
+ credentials_provider
414
+ end
415
+
416
+ d = create_driver(config + %[
417
+ <auth>
418
+ method aws_sigv4
419
+ aws_service someservice
420
+ aws_region my-region-1
421
+ aws_role_arn arn:aws:iam::123456789012:role/MyRole
422
+ </auth>
423
+ ])
424
+ d.run(default_tag: 'test.http') do
425
+ test_events.each { |event|
426
+ d.feed(event)
427
+ }
428
+ end
429
+
430
+ result = @@result
431
+ assert_equal 'POST', result.method
432
+ assert_equal 'application/x-ndjson', result.content_type
433
+ assert_equal test_events, result.data
434
+ assert_not_empty result.headers
435
+ assert_not_nil result.headers['authorization']
436
+ assert_match /AWS4-HMAC-SHA256 Credential=[a-zA-Z0-9]*\/\d+\/my-region-1\/someservice\/aws4_request/, result.headers['authorization']
437
+ assert_match /SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-security-token/, result.headers['authorization']
438
+ assert_equal @@fake_aws_credentials.session_token, result.headers['x-amz-security-token']
439
+ assert_not_nil result.headers['x-amz-content-sha256']
440
+ assert_not_empty result.headers['x-amz-content-sha256']
441
+ assert_not_nil result.headers['x-amz-security-token']
442
+ assert_not_empty result.headers['x-amz-security-token']
443
+ assert_not_nil result.headers['x-amz-date']
444
+ assert_not_empty result.headers['x-amz-date']
445
+ end
446
+
447
+ def test_aws_sigv4_no_role
448
+ stub(Aws::CredentialProviderChain).new do |provider_chain|
449
+ stub(provider_chain).resolve {
450
+ @@fake_aws_credentials
451
+ }
452
+ provider_chain
453
+ end
454
+ d = create_driver(config + %[
455
+ <auth>
456
+ method aws_sigv4
457
+ aws_service someservice
458
+ aws_region my-region-1
459
+ </auth>
460
+ ])
461
+ d.run(default_tag: 'test.http') do
462
+ test_events.each { |event|
463
+ d.feed(event)
464
+ }
465
+ end
466
+
467
+ result = @@result
468
+ assert_equal 'POST', result.method
469
+ assert_equal 'application/x-ndjson', result.content_type
470
+ assert_equal test_events, result.data
471
+ assert_not_empty result.headers
472
+ assert_not_nil result.headers['authorization']
473
+ assert_match /AWS4-HMAC-SHA256 Credential=[a-zA-Z0-9]*\/\d+\/my-region-1\/someservice\/aws4_request/, result.headers['authorization']
474
+ assert_match /SignedHeaders=content-type;host;x-amz-content-sha256;x-amz-date;x-amz-security-token/, result.headers['authorization']
475
+ assert_equal @@fake_aws_credentials.session_token, result.headers['x-amz-security-token']
476
+ assert_not_nil result.headers['x-amz-content-sha256']
477
+ assert_not_empty result.headers['x-amz-content-sha256']
478
+ assert_not_nil result.headers['x-amz-security-token']
479
+ assert_not_empty result.headers['x-amz-security-token']
480
+ assert_not_nil result.headers['x-amz-date']
481
+ assert_not_empty result.headers['x-amz-date']
482
+ end
483
+ end
484
+
393
485
  sub_test_case 'HTTPS' do
394
486
  def server_port
395
487
  19882
@@ -426,4 +518,40 @@ class HTTPOutputTest < Test::Unit::TestCase
426
518
  assert_not_empty result.headers
427
519
  end
428
520
  end
521
+
522
+ sub_test_case 'connection_reuse' do
523
+ def server_port
524
+ 19883
525
+ end
526
+
527
+ def test_connection_recreation
528
+ d = create_driver(%[
529
+ endpoint http://127.0.0.1:#{server_port}/test
530
+ reuse_connections true
531
+ ])
532
+
533
+ d.run(default_tag: 'test.http', shutdown: false) do
534
+ d.feed(test_events[0])
535
+ end
536
+
537
+ data = @@result.data
538
+
539
+ # Restart server to simulate connection loss
540
+ @@http_server_thread.kill
541
+ @@http_server_thread.join
542
+ @@http_server_thread = Thread.new do
543
+ run_http_server
544
+ end
545
+
546
+ d.run(default_tag: 'test.http') do
547
+ d.feed(test_events[1])
548
+ end
549
+
550
+ result = @@result
551
+ assert_equal 'POST', result.method
552
+ assert_equal 'application/x-ndjson', result.content_type
553
+ assert_equal test_events, data.concat(result.data)
554
+ assert_not_empty result.headers
555
+ end
556
+ end
429
557
  end
@@ -54,7 +54,7 @@ class TcpOutputTest < Test::Unit::TestCase
54
54
 
55
55
  def setup
56
56
  super
57
- @port = unused_port(protocol: :tcp)
57
+ @port = unused_port
58
58
  end
59
59
 
60
60
  def teardown