fluentd 1.13.3 → 1.14.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/windows-test.yaml +3 -3
  3. data/CHANGELOG.md +44 -0
  4. data/lib/fluent/command/fluentd.rb +8 -0
  5. data/lib/fluent/compat/output.rb +9 -6
  6. data/lib/fluent/event_router.rb +28 -1
  7. data/lib/fluent/plugin/bare_output.rb +49 -8
  8. data/lib/fluent/plugin/buffer.rb +84 -22
  9. data/lib/fluent/plugin/filter.rb +35 -1
  10. data/lib/fluent/plugin/in_http.rb +21 -2
  11. data/lib/fluent/plugin/in_monitor_agent.rb +4 -2
  12. data/lib/fluent/plugin/in_syslog.rb +13 -1
  13. data/lib/fluent/plugin/in_tail/position_file.rb +1 -1
  14. data/lib/fluent/plugin/in_tail.rb +4 -1
  15. data/lib/fluent/plugin/input.rb +39 -1
  16. data/lib/fluent/plugin/metrics.rb +119 -0
  17. data/lib/fluent/plugin/metrics_local.rb +96 -0
  18. data/lib/fluent/plugin/multi_output.rb +43 -6
  19. data/lib/fluent/plugin/output.rb +74 -33
  20. data/lib/fluent/plugin.rb +10 -1
  21. data/lib/fluent/plugin_helper/event_emitter.rb +8 -1
  22. data/lib/fluent/plugin_helper/metrics.rb +129 -0
  23. data/lib/fluent/plugin_helper/server.rb +4 -2
  24. data/lib/fluent/plugin_helper.rb +1 -0
  25. data/lib/fluent/root_agent.rb +6 -0
  26. data/lib/fluent/supervisor.rb +2 -0
  27. data/lib/fluent/system_config.rb +9 -1
  28. data/lib/fluent/version.rb +1 -1
  29. data/test/config/test_system_config.rb +6 -0
  30. data/test/plugin/in_tail/test_position_file.rb +26 -4
  31. data/test/plugin/test_bare_output.rb +13 -0
  32. data/test/plugin/test_buffer.rb +8 -2
  33. data/test/plugin/test_filter.rb +11 -0
  34. data/test/plugin/test_in_http.rb +40 -0
  35. data/test/plugin/test_in_monitor_agent.rb +214 -8
  36. data/test/plugin/test_in_syslog.rb +35 -0
  37. data/test/plugin/test_in_tail.rb +9 -26
  38. data/test/plugin/test_input.rb +11 -0
  39. data/test/plugin/test_metrics.rb +294 -0
  40. data/test/plugin/test_metrics_local.rb +96 -0
  41. data/test/plugin/test_multi_output.rb +25 -1
  42. data/test/plugin/test_output.rb +16 -0
  43. data/test/plugin_helper/test_event_emitter.rb +29 -0
  44. data/test/plugin_helper/test_metrics.rb +137 -0
  45. data/test/test_plugin_classes.rb +102 -0
  46. data/test/test_root_agent.rb +30 -1
  47. metadata +11 -2
@@ -37,6 +37,194 @@ class MonitorAgentInputTest < Test::Unit::TestCase
37
37
  assert_true d.instance.include_config
38
38
  end
39
39
 
40
+ sub_test_case "collect in_monitor_agent plugin statistics" do
41
+ # Input Test Driver does not register metric callbacks.
42
+ # We should stub them here.
43
+ class TestEventMetricRouter < Fluent::Test::Driver::TestEventRouter
44
+ def initialize(driver)
45
+ super
46
+
47
+ raise ArgumentError, "plugin does not respond metric_callback method" unless @driver.instance.respond_to?(:metric_callback)
48
+ end
49
+
50
+ def emit(tag, time, record)
51
+ super
52
+ @driver.instance.metric_callback(OneEventStream.new(time, record))
53
+ end
54
+
55
+ def emit_array(tag, array)
56
+ super
57
+ @driver.instance.metric_callback(ArrayEventStream.new(array))
58
+ end
59
+
60
+ def emit_stream(tag, es)
61
+ super
62
+ @driver.instance.metric_callback(es)
63
+ end
64
+ end
65
+
66
+ class MetricInputDriver < Fluent::Test::Driver::Input
67
+ def configure(conf, syntax: :v1)
68
+ if conf.is_a?(Fluent::Config::Element)
69
+ @config = conf
70
+ else
71
+ @config = Fluent::Config.parse(conf, "(test)", "(test_dir)", syntax: syntax)
72
+ end
73
+
74
+ if @instance.respond_to?(:router=)
75
+ @event_streams = []
76
+ @error_events = []
77
+
78
+ driver = self
79
+ mojule = Module.new do
80
+ define_method(:event_emitter_router) do |label_name|
81
+ TestEventMetricRouter.new(driver)
82
+ end
83
+ end
84
+ @instance.singleton_class.prepend mojule
85
+ end
86
+
87
+ @instance.configure(@config)
88
+ self
89
+ end
90
+ end
91
+
92
+ setup do
93
+ # check @type and type in one configuration
94
+ conf = <<-EOC
95
+ <source>
96
+ @type test_in_gen
97
+ @id test_in_gen
98
+ num 10
99
+ </source>
100
+ <filter>
101
+ @type test_filter
102
+ @id test_filter
103
+ </filter>
104
+ <match **>
105
+ @type relabel
106
+ @id test_relabel
107
+ @label @test
108
+ </match>
109
+ <label @test>
110
+ <match **>
111
+ @type test_out
112
+ @id test_out
113
+ </match>
114
+ </label>
115
+ <label @copy>
116
+ <match **>
117
+ @type copy
118
+ <store>
119
+ @type test_out
120
+ @id copy_out_1
121
+ </store>
122
+ <store>
123
+ @type test_out
124
+ @id copy_out_2
125
+ </store>
126
+ </match>
127
+ </label>
128
+ <label @ERROR>
129
+ <match>
130
+ @type null
131
+ @id null
132
+ </match>
133
+ </label>
134
+ EOC
135
+ @ra = Fluent::RootAgent.new(log: $log)
136
+ stub(Fluent::Engine).root_agent { @ra }
137
+ @ra = configure_ra(@ra, conf)
138
+ end
139
+
140
+ data(:with_config_yes => true,
141
+ :with_config_no => false)
142
+ def test_enable_input_metrics(with_config)
143
+ monitor_agent_conf = <<-CONF
144
+ tag test.monitor
145
+ emit_interval 1
146
+ CONF
147
+ @ra.inputs.first.context_router.emit("test.event", Fluent::Engine.now, {"message":"ok"})
148
+ d = MetricInputDriver.new(Fluent::Plugin::MonitorAgentInput).configure(monitor_agent_conf)
149
+ d.run(expect_emits: 1, timeout: 3)
150
+
151
+ test_label = @ra.labels['@test']
152
+ error_label = @ra.labels['@ERROR']
153
+ input_info = {
154
+ "output_plugin" => false,
155
+ "plugin_category"=> "input",
156
+ "plugin_id" => "test_in_gen",
157
+ "retry_count" => nil,
158
+ "type" => "test_in_gen",
159
+ "emit_records" => 0, # This field is not updated due to not to be assigned metric callback.
160
+ "emit_size" => 0, # Ditto.
161
+ }
162
+ input_info.merge!("config" => {"@id" => "test_in_gen", "@type" => "test_in_gen", "num" => "10"}) if with_config
163
+ filter_info = {
164
+ "output_plugin" => false,
165
+ "plugin_category" => "filter",
166
+ "plugin_id" => "test_filter",
167
+ "retry_count" => nil,
168
+ "type" => "test_filter",
169
+ "emit_records" => Integer,
170
+ "emit_size" => Integer,
171
+ }
172
+ filter_info.merge!("config" => {"@id" => "test_filter", "@type" => "test_filter"}) if with_config
173
+ output_info = {
174
+ "output_plugin" => true,
175
+ "plugin_category" => "output",
176
+ "plugin_id" => "test_out",
177
+ "retry_count" => 0,
178
+ "type" => "test_out",
179
+ "emit_count" => Integer,
180
+ "emit_records" => Integer,
181
+ "emit_size" => Integer,
182
+ "write_count" => Integer,
183
+ "rollback_count" => Integer,
184
+ "slow_flush_count" => Integer,
185
+ "flush_time_count" => Integer,
186
+ }
187
+ output_info.merge!("config" => {"@id" => "test_out", "@type" => "test_out"}) if with_config
188
+ error_label_info = {
189
+ "buffer_queue_length" => 0,
190
+ "buffer_timekeys" => [],
191
+ "buffer_total_queued_size" => 0,
192
+ "output_plugin" => true,
193
+ "plugin_category" => "output",
194
+ "plugin_id" => "null",
195
+ "retry_count" => 0,
196
+ "type" => "null",
197
+ "buffer_available_buffer_space_ratios" => Float,
198
+ "buffer_queue_byte_size" => Integer,
199
+ "buffer_stage_byte_size" => Integer,
200
+ "buffer_stage_length" => Integer,
201
+ "emit_count" => Integer,
202
+ "emit_records" => Integer,
203
+ "emit_size" => Integer,
204
+ "write_count" => Integer,
205
+ "rollback_count" => Integer,
206
+ "slow_flush_count" => Integer,
207
+ "flush_time_count" => Integer,
208
+ }
209
+ error_label_info.merge!("config" => {"@id"=>"null", "@type" => "null"}) if with_config
210
+ opts = {with_config: with_config}
211
+ assert_equal(input_info, d.instance.get_monitor_info(@ra.inputs.first, opts))
212
+ assert_fuzzy_equal(filter_info, d.instance.get_monitor_info(@ra.filters.first, opts))
213
+ assert_fuzzy_equal(output_info, d.instance.get_monitor_info(test_label.outputs.first, opts))
214
+ assert_fuzzy_equal(error_label_info, d.instance.get_monitor_info(error_label.outputs.first, opts))
215
+ monitor_agent_emit_info = {
216
+ "emit_records" => Integer,
217
+ "emit_size" => Integer,
218
+ }
219
+ filter_statistics_info = {
220
+ "emit_records" => Integer,
221
+ "emit_size" => Integer,
222
+ }
223
+ assert_fuzzy_equal(monitor_agent_emit_info, d.instance.statistics["input"])
224
+ assert_fuzzy_equal(filter_statistics_info, @ra.filters.first.statistics["filter"])
225
+ end
226
+ end
227
+
40
228
  sub_test_case "collect plugin information" do
41
229
  setup do
42
230
  # check @type and type in one configuration
@@ -106,7 +294,9 @@ EOC
106
294
  "plugin_category"=> "input",
107
295
  "plugin_id" => "test_in",
108
296
  "retry_count" => nil,
109
- "type" => "test_in"
297
+ "type" => "test_in",
298
+ "emit_records" => 0,
299
+ "emit_size" => 0,
110
300
  }
111
301
  input_info.merge!("config" => {"@id" => "test_in", "@type" => "test_in"}) if with_config
112
302
  filter_info = {
@@ -114,7 +304,9 @@ EOC
114
304
  "plugin_category" => "filter",
115
305
  "plugin_id" => "test_filter",
116
306
  "retry_count" => nil,
117
- "type" => "test_filter"
307
+ "type" => "test_filter",
308
+ "emit_records" => 0,
309
+ "emit_size" => 0,
118
310
  }
119
311
  filter_info.merge!("config" => {"@id" => "test_filter", "@type" => "test_filter"}) if with_config
120
312
  output_info = {
@@ -125,6 +317,7 @@ EOC
125
317
  "type" => "test_out",
126
318
  "emit_count" => Integer,
127
319
  "emit_records" => Integer,
320
+ "emit_size" => Integer,
128
321
  "write_count" => Integer,
129
322
  "rollback_count" => Integer,
130
323
  "slow_flush_count" => Integer,
@@ -146,6 +339,7 @@ EOC
146
339
  "buffer_stage_length" => Integer,
147
340
  "emit_count" => Integer,
148
341
  "emit_records" => Integer,
342
+ "emit_size" => Integer,
149
343
  "write_count" => Integer,
150
344
  "rollback_count" => Integer,
151
345
  "slow_flush_count" => Integer,
@@ -220,6 +414,7 @@ EOC
220
414
  "retry_count" => 0,
221
415
  "emit_count" => Integer,
222
416
  "emit_records" => Integer,
417
+ "emit_size" => Integer,
223
418
  "write_count" => Integer,
224
419
  "rollback_count" => Integer,
225
420
  "slow_flush_count" => Integer,
@@ -233,6 +428,7 @@ EOC
233
428
  "retry_count" => 0,
234
429
  "emit_count" => Integer,
235
430
  "emit_records" => Integer,
431
+ "emit_size" => Integer,
236
432
  "write_count" => Integer,
237
433
  "rollback_count" => Integer,
238
434
  "slow_flush_count" => Integer,
@@ -322,9 +518,9 @@ EOC
322
518
  ")
323
519
  d.instance.start
324
520
  expected_test_in_response = "\
325
- plugin_id:test_in\tplugin_category:input\ttype:test_in\toutput_plugin:false\tretry_count:"
521
+ plugin_id:test_in\tplugin_category:input\ttype:test_in\toutput_plugin:false\tretry_count:\temit_records:0\temit_size:0"
326
522
  expected_test_filter_response = "\
327
- plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:false\tretry_count:"
523
+ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:false\tretry_count:\temit_records:0\temit_size:0"
328
524
 
329
525
  response = get("http://127.0.0.1:#{@port}/api/plugins").body
330
526
  test_in = response.split("\n")[0]
@@ -350,7 +546,9 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
350
546
  "plugin_category" => "input",
351
547
  "plugin_id" => "test_in",
352
548
  "retry_count" => nil,
353
- "type" => "test_in"
549
+ "type" => "test_in",
550
+ "emit_records" => 0,
551
+ "emit_size" => 0,
354
552
  }
355
553
  expected_test_in_response.merge!("config" => {"@id" => "test_in", "@type" => "test_in"}) if with_config
356
554
  expected_null_response = {
@@ -368,6 +566,7 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
368
566
  "buffer_stage_length" => Integer,
369
567
  "emit_count" => Integer,
370
568
  "emit_records" => Integer,
569
+ "emit_size" => Integer,
371
570
  "write_count" => Integer,
372
571
  "rollback_count" => Integer,
373
572
  "slow_flush_count" => Integer,
@@ -412,7 +611,9 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
412
611
  "plugin_category" => "input",
413
612
  "plugin_id" => "test_in",
414
613
  "retry_count" => nil,
415
- "type" => "test_in"
614
+ "type" => "test_in",
615
+ "emit_records" => 0,
616
+ "emit_size" => 0,
416
617
  }
417
618
  expected_test_in_response.merge!("config" => {"@id" => "test_in", "@type" => "test_in"}) if with_config
418
619
  expected_null_response = {
@@ -430,6 +631,7 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
430
631
  "buffer_stage_length" => Integer,
431
632
  "emit_count" => Integer,
432
633
  "emit_records" => Integer,
634
+ "emit_size" => Integer,
433
635
  "write_count" => Integer,
434
636
  "rollback_count" => Integer,
435
637
  "slow_flush_count" => Integer,
@@ -458,7 +660,9 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
458
660
  "plugin_id" => "test_in",
459
661
  "retry_count" => nil,
460
662
  "type" => "test_in",
461
- "instance_variables" => {"id" => "test_in"}
663
+ "instance_variables" => {"id" => "test_in"},
664
+ "emit_records" => 0,
665
+ "emit_size" => 0,
462
666
  }
463
667
  expected_null_response = {
464
668
  "buffer_queue_length" => 0,
@@ -469,13 +673,14 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
469
673
  "plugin_id" => "null",
470
674
  "retry_count" => 0,
471
675
  "type" => "null",
472
- "instance_variables" => {"id" => "null", "num_errors" => 0},
676
+ "instance_variables" => {"id" => "null"},
473
677
  "buffer_available_buffer_space_ratios" => Float,
474
678
  "buffer_queue_byte_size" => Integer,
475
679
  "buffer_stage_byte_size" => Integer,
476
680
  "buffer_stage_length" => Integer,
477
681
  "emit_count" => Integer,
478
682
  "emit_records" => Integer,
683
+ "emit_size" => Integer,
479
684
  "write_count" => Integer,
480
685
  "rollback_count" => Integer,
481
686
  "slow_flush_count" => Integer,
@@ -606,6 +811,7 @@ plugin_id:test_filter\tplugin_category:filter\ttype:test_filter\toutput_plugin:f
606
811
  "buffer_stage_length" => Integer,
607
812
  "emit_count" => Integer,
608
813
  "emit_records" => Integer,
814
+ "emit_size" => Integer,
609
815
  "write_count" => Integer,
610
816
  "rollback_count" => Integer,
611
817
  'slow_flush_count' => Integer,
@@ -467,4 +467,39 @@ EOS
467
467
  assert_equal tests.size, d.events.size
468
468
  compare_unmatched_lines_test_result(d.events, tests, {address: address})
469
469
  end
470
+
471
+ def test_send_keepalive_packet_is_disabled_by_default
472
+ d = create_driver(ipv4_config + %[
473
+ <transport tcp>
474
+ </transport>
475
+ protocol tcp
476
+ ])
477
+ assert_false d.instance.send_keepalive_packet
478
+ end
479
+
480
+ def test_send_keepalive_packet_can_be_enabled
481
+ addr = "127.0.0.1"
482
+ d = create_driver(ipv4_config + %[
483
+ <transport tcp>
484
+ </transport>
485
+ send_keepalive_packet true
486
+ ])
487
+ assert_true d.instance.send_keepalive_packet
488
+ mock.proxy(d.instance).server_create_connection(
489
+ :in_syslog_tcp_server, @port,
490
+ bind: addr,
491
+ resolve_name: nil,
492
+ send_keepalive_packet: true)
493
+ d.run do
494
+ TCPSocket.open(addr, @port)
495
+ end
496
+ end
497
+
498
+ def test_send_keepalive_packet_can_not_be_enabled_for_udp
499
+ assert_raise(Fluent::ConfigError) do
500
+ d = create_driver(ipv4_config + %[
501
+ send_keepalive_packet true
502
+ ])
503
+ end
504
+ end
470
505
  end
@@ -1739,7 +1739,7 @@ class TailInputTest < Test::Unit::TestCase
1739
1739
  d.instance_shutdown
1740
1740
  end
1741
1741
 
1742
- def test_should_keep_and_update_existing_file_pos_entry_for_deleted_file_when_new_file_with_same_name_created
1742
+ def test_should_remove_deleted_file
1743
1743
  config = config_element("", "", {"format" => "none"})
1744
1744
 
1745
1745
  path = "#{TMP_DIR}/tail.txt"
@@ -1750,30 +1750,11 @@ class TailInputTest < Test::Unit::TestCase
1750
1750
  }
1751
1751
 
1752
1752
  d = create_driver(config)
1753
- d.run(shutdown: false)
1754
-
1755
- pos_file = File.open("#{TMP_DIR}/tail.pos", "r")
1756
- pos_file.pos = 0
1757
-
1758
- path_pos_ino = /^([^\t]+)\t([0-9a-fA-F]+)\t([0-9a-fA-F]+)/.match(pos_file.readline)
1759
- assert_equal(path, path_pos_ino[1])
1760
- assert_equal(pos, path_pos_ino[2].to_i(16))
1761
- assert_equal(ino, path_pos_ino[3].to_i(16))
1762
-
1763
- File.open("#{TMP_DIR}/tail.txt", "wb") {|f|
1764
- f.puts "test1"
1765
- f.puts "test2"
1766
- }
1767
- Timecop.travel(Time.now + 10) do
1768
- sleep 5
1753
+ d.run do
1754
+ pos_file = File.open("#{TMP_DIR}/tail.pos", "r")
1769
1755
  pos_file.pos = 0
1770
- tuple = create_target_info("#{TMP_DIR}/tail.txt")
1771
- path_pos_ino = /^([^\t]+)\t([0-9a-fA-F]+)\t([0-9a-fA-F]+)/.match(pos_file.readline)
1772
- assert_equal(tuple.path, path_pos_ino[1])
1773
- assert_equal(12, path_pos_ino[2].to_i(16))
1774
- assert_equal(tuple.ino, path_pos_ino[3].to_i(16))
1756
+ assert_equal([], pos_file.readlines)
1775
1757
  end
1776
- d.instance_shutdown
1777
1758
  end
1778
1759
 
1779
1760
  def test_should_mark_file_unwatched_after_limit_recently_modified_and_rotate_wait
@@ -2198,8 +2179,9 @@ class TailInputTest < Test::Unit::TestCase
2198
2179
  assert_nothing_raised do
2199
2180
  d.run(shutdown: false) {}
2200
2181
  end
2201
- d.instance_shutdown
2202
2182
  assert($log.out.logs.any?{|log| log.include?("stat() for #{path} failed with Errno::ENOENT. Drop tail watcher for now.\n") })
2183
+ ensure
2184
+ d.instance_shutdown if d && d.instance
2203
2185
  end
2204
2186
 
2205
2187
  def test_EACCES_error_after_setup_watcher
@@ -2222,10 +2204,10 @@ class TailInputTest < Test::Unit::TestCase
2222
2204
  assert_nothing_raised do
2223
2205
  d.run(shutdown: false) {}
2224
2206
  end
2225
- d.instance_shutdown
2226
2207
  assert($log.out.logs.any?{|log| log.include?("stat() for #{path} failed with Errno::EACCES. Drop tail watcher for now.\n") })
2227
2208
  end
2228
2209
  ensure
2210
+ d.instance_shutdown if d && d.instance
2229
2211
  if File.exist?("#{TMP_DIR}/noaccess")
2230
2212
  FileUtils.chmod(0755, "#{TMP_DIR}/noaccess")
2231
2213
  FileUtils.rm_rf("#{TMP_DIR}/noaccess")
@@ -2245,8 +2227,9 @@ class TailInputTest < Test::Unit::TestCase
2245
2227
  assert_nothing_raised do
2246
2228
  d.run(shutdown: false) {}
2247
2229
  end
2248
- d.instance_shutdown
2249
2230
  assert($log.out.logs.any?{|log| log.include?("expand_paths: stat() for #{path} failed with Errno::EACCES. Skip file.\n") })
2231
+ ensure
2232
+ d.instance_shutdown if d && d.instance
2250
2233
  end
2251
2234
 
2252
2235
  def test_shutdown_timeout
@@ -85,6 +85,17 @@ class InputTest < Test::Unit::TestCase
85
85
  end
86
86
  end
87
87
 
88
+ test 'can use metrics plugins and fallback methods' do
89
+ @p.configure(config_element('ROOT', '', {'@log_level' => 'debug'}))
90
+
91
+ %w[emit_size_metrics emit_records_metrics].each do |metric_name|
92
+ assert_true @p.instance_variable_get(:"@#{metric_name}").is_a?(Fluent::Plugin::Metrics)
93
+ end
94
+
95
+ assert_equal 0, @p.emit_size
96
+ assert_equal 0, @p.emit_records
97
+ end
98
+
88
99
  test 'are not available with multi workers configuration in default' do
89
100
  assert_false @p.multi_workers_ready?
90
101
  end