fluentd 1.10.0-x64-mingw32 → 1.11.0-x64-mingw32

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.

Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +117 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +4 -0
  5. data/docs/SECURITY_AUDIT.pdf +0 -0
  6. data/lib/fluent/command/debug.rb +1 -0
  7. data/lib/fluent/command/fluentd.rb +14 -1
  8. data/lib/fluent/config.rb +1 -0
  9. data/lib/fluent/daemonizer.rb +88 -0
  10. data/lib/fluent/log.rb +45 -6
  11. data/lib/fluent/match.rb +1 -1
  12. data/lib/fluent/plugin/in_dummy.rb +2 -2
  13. data/lib/fluent/plugin/in_forward.rb +2 -2
  14. data/lib/fluent/plugin/in_gc_stat.rb +16 -0
  15. data/lib/fluent/plugin/in_http.rb +2 -2
  16. data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
  17. data/lib/fluent/plugin/in_syslog.rb +4 -4
  18. data/lib/fluent/plugin/in_tail.rb +3 -3
  19. data/lib/fluent/plugin/in_tail/position_file.rb +23 -6
  20. data/lib/fluent/plugin/in_unix.rb +77 -77
  21. data/lib/fluent/plugin/out_copy.rb +1 -1
  22. data/lib/fluent/plugin/out_file.rb +1 -1
  23. data/lib/fluent/plugin/out_forward.rb +23 -18
  24. data/lib/fluent/plugin/out_forward/load_balancer.rb +1 -1
  25. data/lib/fluent/plugin/out_http.rb +15 -2
  26. data/lib/fluent/plugin/parser_multiline.rb +1 -1
  27. data/lib/fluent/plugin/parser_syslog.rb +216 -55
  28. data/lib/fluent/plugin_helper/record_accessor.rb +14 -0
  29. data/lib/fluent/plugin_helper/service_discovery.rb +7 -0
  30. data/lib/fluent/plugin_helper/service_discovery/manager.rb +8 -0
  31. data/lib/fluent/plugin_helper/socket.rb +20 -2
  32. data/lib/fluent/plugin_helper/socket_option.rb +2 -2
  33. data/lib/fluent/supervisor.rb +21 -9
  34. data/lib/fluent/system_config.rb +2 -1
  35. data/lib/fluent/test/filter_test.rb +2 -2
  36. data/lib/fluent/test/output_test.rb +3 -3
  37. data/lib/fluent/version.rb +1 -1
  38. data/test/command/test_fluentd.rb +57 -10
  39. data/test/config/test_system_config.rb +2 -0
  40. data/test/plugin/in_tail/test_position_file.rb +24 -0
  41. data/test/plugin/out_forward/test_load_balancer.rb +46 -0
  42. data/test/plugin/test_in_gc_stat.rb +24 -1
  43. data/test/plugin/test_in_syslog.rb +16 -1
  44. data/test/plugin/test_in_tail.rb +39 -16
  45. data/test/plugin/test_in_unix.rb +128 -73
  46. data/test/plugin/test_out_forward.rb +11 -2
  47. data/test/plugin/test_out_http.rb +38 -0
  48. data/test/plugin/test_out_null.rb +1 -1
  49. data/test/plugin/test_output_as_buffered_retries.rb +12 -4
  50. data/test/plugin/test_output_as_buffered_secondary.rb +9 -1
  51. data/test/plugin/test_parser_syslog.rb +77 -29
  52. data/test/plugin_helper/data/cert/cert_chains/ca-cert-key.pem +27 -0
  53. data/test/plugin_helper/data/cert/cert_chains/ca-cert.pem +20 -0
  54. data/test/plugin_helper/data/cert/cert_chains/cert-key.pem +27 -0
  55. data/test/plugin_helper/data/cert/cert_chains/cert.pem +40 -0
  56. data/test/plugin_helper/data/cert/generate_cert.rb +38 -0
  57. data/test/plugin_helper/http_server/test_app.rb +1 -1
  58. data/test/plugin_helper/http_server/test_route.rb +1 -1
  59. data/test/plugin_helper/test_http_server_helper.rb +2 -2
  60. data/test/plugin_helper/test_record_accessor.rb +41 -0
  61. data/test/plugin_helper/test_server.rb +1 -1
  62. data/test/plugin_helper/test_service_discovery.rb +37 -4
  63. data/test/plugin_helper/test_socket.rb +131 -0
  64. data/test/test_daemonizer.rb +91 -0
  65. data/test/test_log.rb +44 -0
  66. metadata +16 -2
@@ -49,6 +49,44 @@ class LoadBalancerTest < Test::Unit::TestCase
49
49
  end
50
50
  end
51
51
 
52
+ test 'call like round robin without weight=0 node' do
53
+ lb = Fluent::Plugin::ForwardOutput::LoadBalancer.new($log)
54
+ n1 = flexmock('node', :'standby?' => false, :'available?' => true, weight: 1)
55
+ n2 = flexmock('node', :'standby?' => false, :'available?' => true, weight: 1)
56
+ n3 = flexmock('node', :'standby?' => false, :'available?' => true, weight: 0)
57
+
58
+ lb.rebuild_weight_array([n1, n2, n3])
59
+
60
+ lb.select_healthy_node do |node|
61
+ # to handle random choice
62
+ if node == n1
63
+ lb.select_healthy_node do |node|
64
+ assert_equal(node, n2)
65
+ end
66
+
67
+ lb.select_healthy_node do |node|
68
+ assert_equal(node, n1)
69
+ end
70
+
71
+ lb.select_healthy_node do |node|
72
+ assert_equal(node, n2)
73
+ end
74
+ else
75
+ lb.select_healthy_node do |node|
76
+ assert_equal(node, n1)
77
+ end
78
+
79
+ lb.select_healthy_node do |node|
80
+ assert_equal(node, n2)
81
+ end
82
+
83
+ lb.select_healthy_node do |node|
84
+ assert_equal(node, n1)
85
+ end
86
+ end
87
+ end
88
+ end
89
+
52
90
  test 'raise an error if all node are unavialble' do
53
91
  lb = Fluent::Plugin::ForwardOutput::LoadBalancer.new($log)
54
92
  lb.rebuild_weight_array([flexmock('node', :'standby?' => false, :'available?' => false, weight: 1)])
@@ -56,5 +94,13 @@ class LoadBalancerTest < Test::Unit::TestCase
56
94
  lb.select_healthy_node
57
95
  end
58
96
  end
97
+
98
+ test 'it regards weight=0 node as unavialble' do
99
+ lb = Fluent::Plugin::ForwardOutput::LoadBalancer.new($log)
100
+ lb.rebuild_weight_array([flexmock('node', :'standby?' => false, :'available?' => true, weight: 0)])
101
+ assert_raise(Fluent::Plugin::ForwardOutput::NoNodesAvailable) do
102
+ lb.select_healthy_node
103
+ end
104
+ end
59
105
  end
60
106
  end
@@ -22,9 +22,14 @@ class GCStatInputTest < Test::Unit::TestCase
22
22
  assert_equal("t1", d.instance.tag)
23
23
  end
24
24
 
25
- def test_emit
25
+ def setup_gc_stat
26
26
  stat = GC.stat
27
27
  stub(GC).stat { stat }
28
+ stat
29
+ end
30
+
31
+ def test_emit
32
+ stat = setup_gc_stat
28
33
 
29
34
  d = create_driver
30
35
  d.run(expect_emits: 2)
@@ -36,4 +41,22 @@ class GCStatInputTest < Test::Unit::TestCase
36
41
  assert(events[i][1].is_a?(Fluent::EventTime))
37
42
  }
38
43
  end
44
+
45
+ def test_emit_with_use_symbol_keys_false
46
+ stat = setup_gc_stat
47
+ result = {}
48
+ stat.each_pair { |k, v|
49
+ result[k.to_s] = v
50
+ }
51
+
52
+ d = create_driver(CONFIG + "use_symbol_keys false")
53
+ d.run(expect_emits: 2)
54
+
55
+ events = d.events
56
+ assert(events.length > 0)
57
+ events.each_index {|i|
58
+ assert_equal(result, events[i][2])
59
+ assert(events[i][1].is_a?(Fluent::EventTime))
60
+ }
61
+ end
39
62
  end
@@ -163,6 +163,21 @@ EOS
163
163
  compare_test_result(d.events, tests)
164
164
  end
165
165
 
166
+ def test_emit_rfc5452
167
+ d = create_driver([CONFIG, "facility_key pri\n<parse>\n message_format rfc5424\nwith_priority true\n</parse>"].join("\n"))
168
+ msg = '<1>1 2017-02-06T13:14:15.003Z myhostname 02abaf0687f5 10339 02abaf0687f5 - method=POST db=0.00'
169
+
170
+ d.run(expect_emits: 1, timeout: 2) do
171
+ u = UDPSocket.new
172
+ u.connect('127.0.0.1', PORT)
173
+ u.send(msg, 0)
174
+ end
175
+
176
+ tag, _, event = d.events[0]
177
+ assert_equal('syslog.kern.alert', tag)
178
+ assert_equal('kern', event['pri'])
179
+ end
180
+
166
181
  def test_msg_size_with_same_tcp_connection
167
182
  d = create_driver([CONFIG, "<transport tcp> \n</transport>"].join("\n"))
168
183
  tests = create_test_case
@@ -360,7 +375,7 @@ EOS
360
375
  ]
361
376
  msgs.each { |msg|
362
377
  m = msg['msg']
363
- msg['msg'] = "#{m.size + 1} #{m}"
378
+ msg['msg'] = "#{m.size} #{m}"
364
379
  }
365
380
  msgs
366
381
  end
@@ -23,9 +23,6 @@ class TailInputTest < Test::Unit::TestCase
23
23
  def cleanup_directory(path)
24
24
  FileUtils.rm_rf(path, secure: true)
25
25
  if File.exist?(path)
26
- # ensure files are closed for Windows, on which deleted files
27
- # are still visible from filesystem
28
- GC.start(full_mark: true, immediate_mark: true, immediate_sweep: true)
29
26
  FileUtils.remove_entry_secure(path, true)
30
27
  end
31
28
  FileUtils.mkdir_p(path)
@@ -105,6 +102,12 @@ class TailInputTest < Test::Unit::TestCase
105
102
  assert_equal ["tail.txt", "test2", "tmp,dev"], d.instance.paths
106
103
  end
107
104
 
105
+ test "multi paths with same path configured twice" do
106
+ c = config_element("ROOT", "", { "path" => "test1.txt,test2.txt,test1.txt", "tag" => "t1", "path_delimiter" => "," })
107
+ d = create_driver(c + PARSE_SINGLE_LINE_CONFIG, false)
108
+ assert_equal ["test2.txt","test1.txt"].sort, d.instance.paths.sort
109
+ end
110
+
108
111
  test "multi paths with invaid path_delimiter" do
109
112
  c = config_element("ROOT", "", { "path" => "tail.txt|test2|tmp,dev", "tag" => "t1", "path_delimiter" => "*" })
110
113
  assert_raise(Fluent::ConfigError) do
@@ -1025,6 +1028,17 @@ class TailInputTest < Test::Unit::TestCase
1025
1028
  assert_equal EX_PATHS - [EX_PATHS.last], plugin.expand_paths.sort
1026
1029
  end
1027
1030
 
1031
+ def test_expand_paths_with_duplicate_configuration
1032
+ expanded_paths = [
1033
+ 'test/plugin/data/log/foo/bar.log',
1034
+ 'test/plugin/data/log/test.log'
1035
+ ]
1036
+ duplicate_config = EX_CONFIG.dup
1037
+ duplicate_config["path"]="test/plugin/data/log/**/*.log, test/plugin/data/log/**/*.log"
1038
+ plugin = create_driver(EX_CONFIG, false).instance
1039
+ assert_equal expanded_paths, plugin.expand_paths.sort
1040
+ end
1041
+
1028
1042
  def test_expand_paths_with_timezone
1029
1043
  ['Asia/Taipei', '+08'].each do |tz_type|
1030
1044
  taipei_config = EX_CONFIG + config_element("", "", {"path_timezone" => tz_type})
@@ -1065,9 +1079,6 @@ class TailInputTest < Test::Unit::TestCase
1065
1079
  assert_equal expected_files, plugin.expand_paths.sort
1066
1080
  end
1067
1081
 
1068
- # For https://github.com/fluent/fluentd/issues/1455
1069
- # This test is fragile because test content depends on internal implementation.
1070
- # So if you modify in_tail internal, this test may break.
1071
1082
  def test_unwatched_files_should_be_removed
1072
1083
  config = config_element("", "", {
1073
1084
  "tag" => "tail",
@@ -1079,22 +1090,15 @@ class TailInputTest < Test::Unit::TestCase
1079
1090
  })
1080
1091
  d = create_driver(config, false)
1081
1092
  d.end_if { d.instance.instance_variable_get(:@tails).keys.size >= 1 }
1082
- d.run(expect_emits: 1, shutdown: false, timeout: 1) do
1093
+ d.run(expect_emits: 1, shutdown: false) do
1083
1094
  File.open("#{TMP_DIR}/tail.txt", "ab") { |f| f.puts "test3\n" }
1084
1095
  end
1085
1096
 
1086
1097
  cleanup_directory(TMP_DIR)
1087
1098
  waiting(20) { sleep 0.1 until Dir.glob("#{TMP_DIR}/*.txt").size == 0 } # Ensure file is deleted on Windows
1088
- waiting(5) { sleep 0.1 until d.instance.instance_variable_get(:@tails).keys.size == 0 }
1099
+ waiting(5) { sleep 0.1 until d.instance.instance_variable_get(:@tails).keys.size <= 0 }
1089
1100
 
1090
- # Previous implementation has an infinite watcher creation bug.
1091
- # Following code checks such unexpected bug by counting actual object allocation.
1092
- base_num = count_timer_object
1093
- 2.times {
1094
- sleep 1
1095
- num = count_timer_object
1096
- assert_equal base_num, num
1097
- }
1101
+ assert_equal 0, d.instance.instance_variable_get(:@tails).keys.size
1098
1102
 
1099
1103
  d.instance_shutdown
1100
1104
  end
@@ -1183,6 +1187,25 @@ class TailInputTest < Test::Unit::TestCase
1183
1187
  end
1184
1188
  end
1185
1189
 
1190
+ sub_test_case "refresh of pos file" do
1191
+ test 'type of pos_file_compaction_interval is time' do
1192
+ tail = {
1193
+ "tag" => "tail",
1194
+ "path" => "#{TMP_DIR}/*.txt",
1195
+ "format" => "none",
1196
+ "pos_file" => "#{TMP_DIR}/pos/tail.pos",
1197
+ "refresh_interval" => 1,
1198
+ "read_from_head" => true,
1199
+ 'pos_file_compaction_interval' => '24h',
1200
+ }
1201
+ config = config_element("", "", tail)
1202
+ d = create_driver(config, false)
1203
+ mock(d.instance).timer_execute(:in_tail_refresh_watchers, 1.0).once
1204
+ mock(d.instance).timer_execute(:in_tail_refresh_compact_pos_file, 60 * 60 * 24).once
1205
+ d.run # call start
1206
+ end
1207
+ end
1208
+
1186
1209
  sub_test_case "receive_lines" do
1187
1210
  DummyWatcher = Struct.new("DummyWatcher", :tag)
1188
1211
 
@@ -1,126 +1,181 @@
1
1
  require_relative '../helper'
2
- require 'fluent/test'
2
+ require 'fluent/test/driver/input'
3
3
  require 'fluent/plugin/in_unix'
4
4
 
5
- module StreamInputTest
5
+ class UnixInputTest < Test::Unit::TestCase
6
6
  def setup
7
7
  Fluent::Test.setup
8
+ @d = nil
8
9
  end
9
10
 
10
- def test_time
11
- d = create_driver
11
+ def teardown
12
+ @d.instance_shutdown if @d
13
+ end
12
14
 
13
- time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
14
- Fluent::Engine.now = time
15
+ TMP_DIR = File.dirname(__FILE__) + "/../tmp/in_unix#{ENV['TEST_ENV_NUMBER']}"
16
+ CONFIG = %[
17
+ path #{TMP_DIR}/unix
18
+ backlog 1000
19
+ ]
20
+
21
+ def create_driver(conf = CONFIG)
22
+ Fluent::Test::Driver::Input.new(Fluent::Plugin::UnixInput).configure(conf)
23
+ end
15
24
 
16
- d.expect_emit "tag1", time, {"a"=>1}
17
- d.expect_emit "tag2", time, {"a"=>2}
25
+ def packer(*args)
26
+ Fluent::MessagePackFactory.msgpack_packer(*args)
27
+ end
18
28
 
19
- d.run do
20
- d.expected_emits.each {|tag,_time,record|
21
- send_data Fluent::MessagePackFactory.msgpack_packer.write([tag, 0, record]).to_s
29
+ def unpacker
30
+ Fluent::MessagePackFactory.msgpack_unpacker
31
+ end
32
+
33
+ def send_data(data)
34
+ io = UNIXSocket.new("#{TMP_DIR}/unix")
35
+ begin
36
+ io.write data
37
+ ensure
38
+ io.close
39
+ end
40
+ end
41
+
42
+ def test_configure
43
+ @d = create_driver
44
+ assert_equal "#{TMP_DIR}/unix", @d.instance.path
45
+ assert_equal 1000, @d.instance.backlog
46
+ end
47
+
48
+ def test_time
49
+ @d = create_driver
50
+
51
+ time = Fluent::EventTime.now
52
+ records = [
53
+ ["tag1", 0, {"a" => 1}],
54
+ ["tag2", nil, {"a" => 2}],
55
+ ]
56
+
57
+ @d.run(expect_records: records.length, timeout: 5) do
58
+ records.each {|tag, _time, record|
59
+ send_data packer.write([tag, _time, record]).to_s
22
60
  }
23
61
  end
62
+
63
+ @d.events.each_with_index { |e, i|
64
+ orig = records[i]
65
+ assert_equal(orig[0], e[0])
66
+ assert_true(time <= e[1])
67
+ assert_equal(orig[2], e[2])
68
+ }
24
69
  end
25
70
 
26
71
  def test_message
27
- d = create_driver
72
+ @d = create_driver
28
73
 
29
- time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
30
-
31
- d.expect_emit "tag1", time, {"a"=>1}
32
- d.expect_emit "tag2", time, {"a"=>2}
74
+ time = Fluent::EventTime.now
75
+ records = [
76
+ ["tag1", time, {"a" => 1}],
77
+ ["tag2", time, {"a" => 2}],
78
+ ]
33
79
 
34
- d.run do
35
- d.expected_emits.each {|tag,_time,record|
36
- send_data Fluent::MessagePackFactory.msgpack_packer.write([tag, _time, record]).to_s
80
+ @d.run(expect_records: records.length, timeout: 5) do
81
+ records.each {|tag, _time, record|
82
+ send_data packer.write([tag, _time, record]).to_s
37
83
  }
38
84
  end
85
+
86
+ assert_equal(records, @d.events)
39
87
  end
40
88
 
41
89
  def test_forward
42
- d = create_driver
90
+ @d = create_driver
43
91
 
44
92
  time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
93
+ records = [
94
+ ["tag1", time, {"a" => 1}],
95
+ ["tag1", time, {"a" => 2}]
96
+ ]
45
97
 
46
- d.expect_emit "tag1", time, {"a"=>1}
47
- d.expect_emit "tag1", time, {"a"=>2}
48
-
49
- d.run do
98
+ @d.run(expect_records: records.length, timeout: 20) do
50
99
  entries = []
51
- d.expected_emits.each {|tag,_time,record|
100
+ records.each {|tag, _time, record|
52
101
  entries << [_time, record]
53
102
  }
54
- send_data Fluent::MessagePackFactory.msgpack_packer.write(["tag1", entries]).to_s
103
+ send_data packer.write(["tag1", entries]).to_s
55
104
  end
105
+ assert_equal(records, @d.events)
56
106
  end
57
107
 
58
108
  def test_packed_forward
59
- d = create_driver
109
+ @d = create_driver
60
110
 
61
- time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
62
-
63
- d.expect_emit "tag1", time, {"a"=>1}
64
- d.expect_emit "tag1", time, {"a"=>2}
111
+ time = Fluent::EventTime.now
112
+ records = [
113
+ ["tag1", time, {"a" => 1}],
114
+ ["tag1", time, {"a" => 2}],
115
+ ]
65
116
 
66
- d.run do
117
+ @d.run(expect_records: records.length, timeout: 20) do
67
118
  entries = ''
68
- d.expected_emits.each {|tag,_time,record|
69
- Fluent::MessagePackFactory.msgpack_packer(entries).write([_time, record]).flush
119
+ records.each {|_tag, _time, record|
120
+ packer(entries).write([_time, record]).flush
70
121
  }
71
- send_data Fluent::MessagePackFactory.msgpack_packer.write(["tag1", entries]).to_s
122
+ send_data packer.write(["tag1", entries]).to_s
72
123
  end
124
+ assert_equal(records, @d.events)
73
125
  end
74
126
 
75
127
  def test_message_json
76
- d = create_driver
128
+ @d = create_driver
129
+
130
+ time = Fluent::EventTime.now
131
+ records = [
132
+ ["tag1", time, {"a" => 1}],
133
+ ["tag2", time, {"a" => 2}],
134
+ ]
135
+
136
+ @d.run(expect_records: records.length, timeout: 5) do
137
+ tag, _time, record = records[0]
138
+ send_data [tag, _time.to_i, record].to_json
139
+ tag, _time, record = records[1]
140
+ send_data [tag, _time.to_f, record].to_json
141
+ end
77
142
 
78
- time = Time.parse("2011-01-02 13:14:15 UTC").to_i
143
+ assert_equal(records, @d.events)
144
+ end
145
+
146
+ def test_message_with_tag
147
+ @d = create_driver(CONFIG + "tag new_tag")
79
148
 
80
- d.expect_emit "tag1", time, {"a"=>1}
81
- d.expect_emit "tag2", time, {"a"=>2}
149
+ time = Fluent::EventTime.now
150
+ records = [
151
+ ["tag1", time, {"a" => 1}],
152
+ ["tag2", time, {"a" => 2}],
153
+ ]
82
154
 
83
- d.run do
84
- d.expected_emits.each {|tag,_time,record|
85
- send_data [tag, time, record].to_json
155
+ @d.run(expect_records: records.length, timeout: 5) do
156
+ records.each {|tag, _time, record|
157
+ send_data packer.write([tag, _time, record]).to_s
86
158
  }
87
159
  end
88
- end
89
160
 
90
- def create_driver(klass, conf)
91
- Fluent::Test::InputTestDriver.new(klass).configure(conf)
161
+ @d.events.each { |event|
162
+ assert_equal("new_tag", event[0])
163
+ }
92
164
  end
93
165
 
94
- def send_data(data)
95
- io = connect
96
- begin
97
- io.write data
98
- ensure
99
- io.close
166
+ data('string chunk' => 'broken string',
167
+ 'integer chunk' => 10)
168
+ def test_broken_message(data)
169
+ @d = create_driver
170
+ @d.run(shutdown: false, timeout: 5) do
171
+ @d.instance.__send__(:on_message, data)
100
172
  end
101
- end
102
- end
103
-
104
- class UnixInputTest < Test::Unit::TestCase
105
- include StreamInputTest
106
-
107
- TMP_DIR = File.dirname(__FILE__) + "/../tmp/in_unix#{ENV['TEST_ENV_NUMBER']}"
108
- CONFIG = %[
109
- path #{TMP_DIR}/unix
110
- backlog 1000
111
- ]
112
173
 
113
- def create_driver(conf=CONFIG)
114
- super(Fluent::UnixInput, conf)
115
- end
116
-
117
- def test_configure
118
- d = create_driver
119
- assert_equal "#{TMP_DIR}/unix", d.instance.path
120
- assert_equal 1000, d.instance.backlog
121
- end
174
+ assert_equal 0, @d.events.size
122
175
 
123
- def connect
124
- UNIXSocket.new("#{TMP_DIR}/unix")
176
+ logs = @d.instance.log.logs
177
+ assert_equal 1, logs.select { |line|
178
+ line =~ / \[warn\]: incoming data is broken: msg=#{data.inspect}/
179
+ }.size, "should not accept broken chunk"
125
180
  end
126
181
  end unless Fluent.windows?