fluentd 1.10.2-x86-mingw32 → 1.11.2-x86-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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/example/copy_roundrobin.conf +3 -3
  5. data/example/counter.conf +1 -1
  6. data/example/filter_stdout.conf +2 -2
  7. data/example/{in_dummy_blocks.conf → in_sample_blocks.conf} +4 -4
  8. data/example/{in_dummy_with_compression.conf → in_sample_with_compression.conf} +3 -3
  9. data/example/logevents.conf +5 -5
  10. data/example/multi_filters.conf +1 -1
  11. data/example/out_exec_filter.conf +2 -2
  12. data/example/out_forward.conf +1 -1
  13. data/example/out_forward_buf_file.conf +1 -1
  14. data/example/out_forward_client.conf +5 -5
  15. data/example/out_forward_heartbeat_none.conf +1 -1
  16. data/example/out_forward_sd.conf +1 -1
  17. data/example/out_forward_shared_key.conf +2 -2
  18. data/example/out_forward_tls.conf +1 -1
  19. data/example/out_forward_users.conf +3 -3
  20. data/example/out_null.conf +4 -4
  21. data/example/secondary_file.conf +1 -1
  22. data/lib/fluent/command/fluentd.rb +11 -0
  23. data/lib/fluent/config.rb +1 -0
  24. data/lib/fluent/match.rb +10 -1
  25. data/lib/fluent/plugin/buffer.rb +24 -4
  26. data/lib/fluent/plugin/in_dummy.rb +2 -123
  27. data/lib/fluent/plugin/in_forward.rb +2 -2
  28. data/lib/fluent/plugin/in_gc_stat.rb +16 -0
  29. data/lib/fluent/plugin/in_http.rb +148 -77
  30. data/lib/fluent/plugin/in_monitor_agent.rb +1 -1
  31. data/lib/fluent/plugin/in_sample.rb +141 -0
  32. data/lib/fluent/plugin/in_tail.rb +4 -4
  33. data/lib/fluent/plugin/in_unix.rb +77 -77
  34. data/lib/fluent/plugin/out_file.rb +1 -1
  35. data/lib/fluent/plugin/out_forward.rb +7 -2
  36. data/lib/fluent/plugin/out_forward/load_balancer.rb +1 -1
  37. data/lib/fluent/plugin/out_http.rb +15 -2
  38. data/lib/fluent/plugin/parser_multiline.rb +1 -1
  39. data/lib/fluent/plugin/parser_syslog.rb +215 -54
  40. data/lib/fluent/plugin_helper/cert_option.rb +5 -8
  41. data/lib/fluent/plugin_helper/child_process.rb +3 -2
  42. data/lib/fluent/plugin_helper/record_accessor.rb +14 -0
  43. data/lib/fluent/plugin_helper/service_discovery.rb +7 -0
  44. data/lib/fluent/plugin_helper/service_discovery/manager.rb +8 -0
  45. data/lib/fluent/plugin_helper/socket.rb +1 -1
  46. data/lib/fluent/plugin_helper/socket_option.rb +2 -2
  47. data/lib/fluent/supervisor.rb +6 -3
  48. data/lib/fluent/test/filter_test.rb +2 -2
  49. data/lib/fluent/test/output_test.rb +3 -3
  50. data/lib/fluent/version.rb +1 -1
  51. data/test/plugin/out_forward/test_load_balancer.rb +46 -0
  52. data/test/plugin/test_in_gc_stat.rb +24 -1
  53. data/test/plugin/test_in_http.rb +57 -0
  54. data/test/plugin/{test_in_dummy.rb → test_in_sample.rb} +25 -25
  55. data/test/plugin/test_in_tail.rb +17 -0
  56. data/test/plugin/test_in_unix.rb +128 -73
  57. data/test/plugin/test_out_http.rb +38 -0
  58. data/test/plugin/test_parser_syslog.rb +66 -29
  59. data/test/plugin_helper/data/cert/empty.pem +0 -0
  60. data/test/plugin_helper/test_cert_option.rb +7 -0
  61. data/test/plugin_helper/test_child_process.rb +15 -0
  62. data/test/plugin_helper/test_record_accessor.rb +41 -0
  63. data/test/plugin_helper/test_server.rb +34 -0
  64. data/test/plugin_helper/test_service_discovery.rb +37 -4
  65. data/test/plugin_helper/test_socket.rb +8 -0
  66. data/test/test_match.rb +11 -0
  67. data/test/test_static_config_analysis.rb +2 -2
  68. metadata +9 -6
@@ -259,6 +259,9 @@ module Fluent
259
259
 
260
260
  if !mode.include?(:stderr) && !mode.include?(:read_with_stderr)
261
261
  spawn_opts[:err] = IO::NULL if stderr == :discard
262
+ if !mode.include?(:read) && !mode.include?(:read_with_stderr)
263
+ spawn_opts[:out] = IO::NULL
264
+ end
262
265
  writeio, readio, wait_thread = *Open3.popen2(*spawn_args, spawn_opts)
263
266
  elsif mode.include?(:read_with_stderr)
264
267
  writeio, readio, wait_thread = *Open3.popen2e(*spawn_args, spawn_opts)
@@ -275,8 +278,6 @@ module Fluent
275
278
  if mode.include?(:read) || mode.include?(:read_with_stderr)
276
279
  readio.set_encoding(external_encoding, internal_encoding, **encoding_options)
277
280
  readio_in_use = true
278
- else
279
- readio.reopen(IO::NULL) if readio
280
281
  end
281
282
  if mode.include?(:stderr)
282
283
  stderrio.set_encoding(external_encoding, internal_encoding, **encoding_options)
@@ -41,9 +41,11 @@ module Fluent
41
41
  else
42
42
  mcall = method(:call_dig)
43
43
  mdelete = method(:delete_nest)
44
+ mset = method(:set_nest)
44
45
  singleton_class.module_eval do
45
46
  define_method(:call, mcall)
46
47
  define_method(:delete, mdelete)
48
+ define_method(:set, mset)
47
49
  end
48
50
  end
49
51
  end
@@ -75,6 +77,18 @@ module Fluent
75
77
  nil
76
78
  end
77
79
 
80
+ def set(r, v)
81
+ r[@keys] = v
82
+ end
83
+
84
+ # set_nest doesn't create intermediate object. If key doesn't exist, no effect.
85
+ # See also: https://bugs.ruby-lang.org/issues/11747
86
+ def set_nest(r, v)
87
+ r.dig(*@dig_keys)&.[]=(@last_key, v)
88
+ rescue
89
+ nil
90
+ end
91
+
78
92
  def self.parse_parameter(param)
79
93
  if param.start_with?('$.')
80
94
  parse_dot_notation(param)
@@ -43,6 +43,13 @@ module Fluent
43
43
  super
44
44
  end
45
45
 
46
+ %i[after_start stop before_shutdown shutdown after_shutdown close terminate].each do |mth|
47
+ define_method(mth) do
48
+ @discovery_manager&.__send__(mth)
49
+ super()
50
+ end
51
+ end
52
+
46
53
  private
47
54
 
48
55
  # @param title [Symbol] the thread name. this value should be unique.
@@ -60,6 +60,14 @@ module Fluent
60
60
  end
61
61
  end
62
62
 
63
+ %i[after_start stop before_shutdown shutdown after_shutdown close terminate].each do |mth|
64
+ define_method(mth) do
65
+ @discoveries.each do |d|
66
+ d.__send__(mth)
67
+ end
68
+ end
69
+ end
70
+
63
71
  def run_once
64
72
  # Don't care race in this loop intentionally
65
73
  s = @queue.size
@@ -199,7 +199,7 @@ module Fluent
199
199
  list = []
200
200
  data.scan(pattern) { |match| list << OpenSSL::X509::Certificate.new(match) }
201
201
  if list.length == 0
202
- log.warn "cert_path does not contain a valid certificate"
202
+ raise Fluent::ConfigError, "cert_path does not contain a valid certificate"
203
203
  end
204
204
  list
205
205
  end
@@ -67,8 +67,8 @@ module Fluent
67
67
  end
68
68
  else
69
69
  if linger_timeout
70
- optval = [1, linger_timeout.to_i].pack(FORMAT_STRUCT_LINGER)
71
- socket_option_set_one(sock, :SO_LINGER, optval)
70
+ optval = [1, linger_timeout.to_i].pack(FORMAT_STRUCT_LINGER)
71
+ socket_option_set_one(sock, :SO_LINGER, optval)
72
72
  end
73
73
  end
74
74
  if recv_timeout
@@ -556,7 +556,7 @@ module Fluent
556
556
  end
557
557
 
558
558
  if dry_run
559
- $log.info 'finsihed dry run mode'
559
+ $log.info 'finished dry run mode'
560
560
  exit 0
561
561
  else
562
562
  supervise
@@ -593,7 +593,10 @@ module Fluent
593
593
 
594
594
  main_process do
595
595
  create_socket_manager if @standalone_worker
596
- ServerEngine::Privilege.change(@chuser, @chgroup) if @standalone_worker
596
+ if @standalone_worker
597
+ ServerEngine::Privilege.change(@chuser, @chgroup)
598
+ File.umask(0)
599
+ end
597
600
  MessagePackFactory.init(enable_time_support: @system_config.enable_msgpack_time_support)
598
601
  Fluent::Engine.init(@system_config)
599
602
  Fluent::Engine.run_configure(@conf)
@@ -801,7 +804,7 @@ module Fluent
801
804
  Fluent::Engine.reload_config(conf)
802
805
  end
803
806
  rescue => e
804
- # it is guranteed that config file is valid by supervisor side. but it's not atomic becuase of using signals to commnicate between worker and super
807
+ # it is guaranteed that config file is valid by supervisor side. but it's not atomic because of using signals to commnicate between worker and super
805
808
  # So need this rescue code
806
809
  $log.error("failed to reload config: #{e}")
807
810
  next
@@ -30,12 +30,12 @@ module Fluent
30
30
  attr_reader :filtered
31
31
  attr_accessor :tag
32
32
 
33
- def emit(record, time = Engine.now)
33
+ def emit(record, time = EventTime.now)
34
34
  emit_with_tag(@tag, record, time)
35
35
  end
36
36
  alias_method :filter, :emit
37
37
 
38
- def emit_with_tag(tag, record, time = Engine.now)
38
+ def emit_with_tag(tag, record, time = EventTime.now)
39
39
  @events[tag] ||= MultiEventStream.new
40
40
  @events[tag].add(time, record)
41
41
  end
@@ -41,7 +41,7 @@ module Fluent
41
41
 
42
42
  attr_accessor :tag
43
43
 
44
- def emit(record, time=Engine.now)
44
+ def emit(record, time=EventTime.now)
45
45
  es = OneEventStream.new(time, record)
46
46
  @instance.emit_events(@tag, es)
47
47
  end
@@ -62,7 +62,7 @@ module Fluent
62
62
 
63
63
  attr_accessor :tag
64
64
 
65
- def emit(record, time=Engine.now)
65
+ def emit(record, time=EventTime.now)
66
66
  @entries << [time, record]
67
67
  self
68
68
  end
@@ -110,7 +110,7 @@ module Fluent
110
110
 
111
111
  attr_accessor :tag
112
112
 
113
- def emit(record, time=Engine.now)
113
+ def emit(record, time=EventTime.now)
114
114
  @entries << [time, record]
115
115
  self
116
116
  end
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '1.10.2'
19
+ VERSION = '1.11.2'
20
20
 
21
21
  end
@@ -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
@@ -116,6 +116,36 @@ class HttpInputTest < Test::Unit::TestCase
116
116
  assert_equal_event_time time, d.events[1][1]
117
117
  end
118
118
 
119
+ data('json' => ['json', :to_json],
120
+ 'msgpack' => ['msgpack', :to_msgpack])
121
+ def test_default_with_time_format(data)
122
+ param, method_name = data
123
+ d = create_driver(CONFIG + %[
124
+ <parse>
125
+ keep_time_key
126
+ time_format %iso8601
127
+ </parse>
128
+ ])
129
+
130
+ time = event_time("2020-06-10T01:14:27+00:00")
131
+ events = [
132
+ ["tag1", time, {"a" => 1, "time" => '2020-06-10T01:14:27+00:00'}],
133
+ ["tag2", time, {"a" => 2, "time" => '2020-06-10T01:14:27+00:00'}],
134
+ ]
135
+ res_codes = []
136
+
137
+ d.run(expect_records: 2) do
138
+ events.each do |tag, t, record|
139
+ res = post("/#{tag}", {param => record.__send__(method_name)})
140
+ res_codes << res.code
141
+ end
142
+ end
143
+ assert_equal ["200", "200"], res_codes
144
+ assert_equal events, d.events
145
+ assert_equal_event_time time, d.events[0][1]
146
+ assert_equal_event_time time, d.events[1][1]
147
+ end
148
+
119
149
  def test_multi_json
120
150
  d = create_driver
121
151
  time = event_time("2011-01-02 13:14:15 UTC")
@@ -163,6 +193,33 @@ class HttpInputTest < Test::Unit::TestCase
163
193
  assert_equal_event_time time, d.events[1][1]
164
194
  end
165
195
 
196
+ data('json' => ['json', :to_json],
197
+ 'msgpack' => ['msgpack', :to_msgpack])
198
+ def test_default_multi_with_time_format(data)
199
+ param, method_name = data
200
+ d = create_driver(CONFIG + %[
201
+ <parse>
202
+ keep_time_key
203
+ time_format %iso8601
204
+ </parse>
205
+ ])
206
+ time = event_time("2020-06-10T01:14:27+00:00")
207
+ events = [
208
+ ["tag1", time, {'a' => 1, 'time' => "2020-06-10T01:14:27+00:00"}],
209
+ ["tag1", time, {'a' => 2, 'time' => "2020-06-10T01:14:27+00:00"}],
210
+ ]
211
+ tag = "tag1"
212
+ res_codes = []
213
+ d.run(expect_records: 2, timeout: 5) do
214
+ res = post("/#{tag}", {param => events.map { |e| e[2] }.__send__(method_name)})
215
+ res_codes << res.code
216
+ end
217
+ assert_equal ["200"], res_codes
218
+ assert_equal events, d.events
219
+ assert_equal_event_time time, d.events[0][1]
220
+ assert_equal_event_time time, d.events[1][1]
221
+ end
222
+
166
223
  def test_multi_json_with_nonexistent_time_key
167
224
  d = create_driver(CONFIG + %[
168
225
  <parse>
@@ -1,33 +1,33 @@
1
1
  require_relative '../helper'
2
2
  require 'fluent/test/driver/input'
3
- require 'fluent/plugin/in_dummy'
3
+ require 'fluent/plugin/in_sample'
4
4
  require 'fileutils'
5
5
 
6
- class DummyTest < Test::Unit::TestCase
6
+ class SampleTest < Test::Unit::TestCase
7
7
  def setup
8
8
  Fluent::Test.setup
9
9
  end
10
10
 
11
11
  def create_driver(conf)
12
- Fluent::Test::Driver::Input.new(Fluent::Plugin::DummyInput).configure(conf)
12
+ Fluent::Test::Driver::Input.new(Fluent::Plugin::SampleInput).configure(conf)
13
13
  end
14
14
 
15
15
  sub_test_case 'configure' do
16
16
  test 'required parameters' do
17
17
  assert_raise_message("'tag' parameter is required") do
18
- Fluent::Plugin::DummyInput.new.configure(config_element('ROOT',''))
18
+ Fluent::Plugin::SampleInput.new.configure(config_element('ROOT',''))
19
19
  end
20
20
  end
21
21
 
22
22
  test 'tag' do
23
23
  d = create_driver(%[
24
- tag dummy
24
+ tag sample
25
25
  ])
26
- assert_equal "dummy", d.instance.tag
26
+ assert_equal "sample", d.instance.tag
27
27
  end
28
28
 
29
29
  config = %[
30
- tag dummy
30
+ tag sample
31
31
  ]
32
32
 
33
33
  test 'auto_increment_key' do
@@ -44,30 +44,30 @@ class DummyTest < Test::Unit::TestCase
44
44
  assert_equal 10, d.instance.rate
45
45
  end
46
46
 
47
- test 'dummy' do
47
+ test 'sample' do
48
48
  # hash is okay
49
- d = create_driver(config + %[dummy {"foo":"bar"}])
50
- assert_equal [{"foo"=>"bar"}], d.instance.dummy
49
+ d = create_driver(config + %[sample {"foo":"bar"}])
50
+ assert_equal [{"foo"=>"bar"}], d.instance.sample
51
51
 
52
52
  # array of hash is okay
53
- d = create_driver(config + %[dummy [{"foo":"bar"}]])
54
- assert_equal [{"foo"=>"bar"}], d.instance.dummy
53
+ d = create_driver(config + %[sample [{"foo":"bar"}]])
54
+ assert_equal [{"foo"=>"bar"}], d.instance.sample
55
55
 
56
56
  assert_raise_message(/JSON::ParserError|got incomplete JSON/) do
57
- create_driver(config + %[dummy "foo"])
57
+ create_driver(config + %[sample "foo"])
58
58
  end
59
59
 
60
60
  assert_raise_message(/is not a hash/) do
61
- create_driver(config + %[dummy ["foo"]])
61
+ create_driver(config + %[sample ["foo"]])
62
62
  end
63
63
  end
64
64
  end
65
65
 
66
66
  sub_test_case "emit" do
67
67
  config = %[
68
- tag dummy
68
+ tag sample
69
69
  rate 10
70
- dummy {"foo":"bar"}
70
+ sample {"foo":"bar"}
71
71
  ]
72
72
 
73
73
  test 'simple' do
@@ -75,7 +75,7 @@ class DummyTest < Test::Unit::TestCase
75
75
  d.run(timeout: 0.5)
76
76
 
77
77
  d.events.each do |tag, time, record|
78
- assert_equal("dummy", tag)
78
+ assert_equal("sample", tag)
79
79
  assert_equal({"foo"=>"bar"}, record)
80
80
  assert(time.is_a?(Fluent::EventTime))
81
81
  end
@@ -86,20 +86,20 @@ class DummyTest < Test::Unit::TestCase
86
86
  d.run(timeout: 0.5)
87
87
 
88
88
  d.events.each_with_index do |(tag, _time, record), i|
89
- assert_equal("dummy", tag)
89
+ assert_equal("sample", tag)
90
90
  assert_equal({"foo"=>"bar", "id"=>i}, record)
91
91
  end
92
92
  end
93
93
  end
94
94
 
95
- TEST_PLUGIN_STORAGE_PATH = File.join( File.dirname(File.dirname(__FILE__)), 'tmp', 'in_dummy', 'store' )
95
+ TEST_PLUGIN_STORAGE_PATH = File.join( File.dirname(File.dirname(__FILE__)), 'tmp', 'in_sample', 'store' )
96
96
  FileUtils.mkdir_p TEST_PLUGIN_STORAGE_PATH
97
97
 
98
- sub_test_case 'when dummy plugin has storage which is not specified the path' do
98
+ sub_test_case 'when sample plugin has storage which is not specified the path' do
99
99
  config1 = {
100
- 'tag' => 'dummy',
100
+ 'tag' => 'sample',
101
101
  'rate' => '0',
102
- 'dummy' => '[{"x": 1, "y": "1"}, {"x": 2, "y": "2"}, {"x": 3, "y": "3"}]',
102
+ 'sample' => '[{"x": 1, "y": "1"}, {"x": 2, "y": "2"}, {"x": 3, "y": "3"}]',
103
103
  'auto_increment_key' => 'id',
104
104
  }
105
105
  conf1 = config_element('ROOT', '', config1, [])
@@ -135,7 +135,7 @@ class DummyTest < Test::Unit::TestCase
135
135
  end
136
136
  end
137
137
 
138
- sub_test_case 'when dummy plugin has storage which is specified the path' do
138
+ sub_test_case 'when sample plugin has storage which is specified the path' do
139
139
  setup do
140
140
  FileUtils.rm_rf(TEST_PLUGIN_STORAGE_PATH)
141
141
  FileUtils.mkdir_p(File.join(TEST_PLUGIN_STORAGE_PATH, 'json'))
@@ -144,9 +144,9 @@ class DummyTest < Test::Unit::TestCase
144
144
 
145
145
  config2 = {
146
146
  '@id' => 'test-02',
147
- 'tag' => 'dummy',
147
+ 'tag' => 'sample',
148
148
  'rate' => '0',
149
- 'dummy' => '[{"x": 1, "y": "1"}, {"x": 2, "y": "2"}, {"x": 3, "y": "3"}]',
149
+ 'sample' => '[{"x": 1, "y": "1"}, {"x": 2, "y": "2"}, {"x": 3, "y": "3"}]',
150
150
  'auto_increment_key' => 'id',
151
151
  }
152
152
  conf2 = config_element('ROOT', '', config2, [