fluentd 1.13.3 → 1.16.5

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 (179) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/{bug_report.yaml → bug_report.yml} +2 -0
  3. data/.github/ISSUE_TEMPLATE/config.yml +2 -2
  4. data/.github/ISSUE_TEMPLATE/{feature_request.yaml → feature_request.yml} +1 -0
  5. data/.github/workflows/stale-actions.yml +11 -9
  6. data/.github/workflows/test.yml +32 -0
  7. data/CHANGELOG.md +490 -10
  8. data/CONTRIBUTING.md +2 -2
  9. data/MAINTAINERS.md +7 -5
  10. data/README.md +3 -23
  11. data/Rakefile +1 -1
  12. data/SECURITY.md +14 -0
  13. data/fluentd.gemspec +7 -8
  14. data/lib/fluent/command/cat.rb +13 -3
  15. data/lib/fluent/command/ctl.rb +6 -3
  16. data/lib/fluent/command/fluentd.rb +73 -65
  17. data/lib/fluent/command/plugin_config_formatter.rb +1 -1
  18. data/lib/fluent/compat/output.rb +9 -6
  19. data/lib/fluent/config/dsl.rb +1 -1
  20. data/lib/fluent/config/error.rb +12 -0
  21. data/lib/fluent/config/literal_parser.rb +2 -2
  22. data/lib/fluent/config/parser.rb +1 -1
  23. data/lib/fluent/config/v1_parser.rb +3 -3
  24. data/lib/fluent/config/yaml_parser/fluent_value.rb +47 -0
  25. data/lib/fluent/config/yaml_parser/loader.rb +108 -0
  26. data/lib/fluent/config/yaml_parser/parser.rb +166 -0
  27. data/lib/fluent/config/yaml_parser/section_builder.rb +107 -0
  28. data/lib/fluent/config/yaml_parser.rb +56 -0
  29. data/lib/fluent/config.rb +14 -1
  30. data/lib/fluent/counter/server.rb +1 -1
  31. data/lib/fluent/counter/validator.rb +3 -3
  32. data/lib/fluent/daemon.rb +2 -4
  33. data/lib/fluent/engine.rb +1 -1
  34. data/lib/fluent/env.rb +4 -0
  35. data/lib/fluent/error.rb +3 -0
  36. data/lib/fluent/event.rb +8 -4
  37. data/lib/fluent/event_router.rb +47 -2
  38. data/lib/fluent/file_wrapper.rb +137 -0
  39. data/lib/fluent/log/console_adapter.rb +66 -0
  40. data/lib/fluent/log.rb +44 -5
  41. data/lib/fluent/match.rb +1 -1
  42. data/lib/fluent/msgpack_factory.rb +6 -1
  43. data/lib/fluent/oj_options.rb +1 -2
  44. data/lib/fluent/plugin/bare_output.rb +49 -8
  45. data/lib/fluent/plugin/base.rb +26 -9
  46. data/lib/fluent/plugin/buf_file.rb +34 -5
  47. data/lib/fluent/plugin/buf_file_single.rb +32 -3
  48. data/lib/fluent/plugin/buffer/file_chunk.rb +1 -1
  49. data/lib/fluent/plugin/buffer.rb +216 -70
  50. data/lib/fluent/plugin/filter.rb +35 -1
  51. data/lib/fluent/plugin/filter_record_transformer.rb +1 -1
  52. data/lib/fluent/plugin/in_forward.rb +2 -2
  53. data/lib/fluent/plugin/in_http.rb +39 -10
  54. data/lib/fluent/plugin/in_monitor_agent.rb +4 -2
  55. data/lib/fluent/plugin/in_sample.rb +1 -1
  56. data/lib/fluent/plugin/in_syslog.rb +13 -1
  57. data/lib/fluent/plugin/in_tail/group_watch.rb +204 -0
  58. data/lib/fluent/plugin/in_tail/position_file.rb +33 -33
  59. data/lib/fluent/plugin/in_tail.rb +216 -84
  60. data/lib/fluent/plugin/in_tcp.rb +47 -2
  61. data/lib/fluent/plugin/input.rb +39 -1
  62. data/lib/fluent/plugin/metrics.rb +119 -0
  63. data/lib/fluent/plugin/metrics_local.rb +96 -0
  64. data/lib/fluent/plugin/multi_output.rb +43 -6
  65. data/lib/fluent/plugin/out_copy.rb +1 -1
  66. data/lib/fluent/plugin/out_exec_filter.rb +2 -2
  67. data/lib/fluent/plugin/out_file.rb +20 -2
  68. data/lib/fluent/plugin/out_forward/ack_handler.rb +19 -4
  69. data/lib/fluent/plugin/out_forward/socket_cache.rb +2 -0
  70. data/lib/fluent/plugin/out_forward.rb +17 -9
  71. data/lib/fluent/plugin/out_secondary_file.rb +39 -22
  72. data/lib/fluent/plugin/output.rb +167 -78
  73. data/lib/fluent/plugin/parser.rb +3 -4
  74. data/lib/fluent/plugin/parser_apache2.rb +1 -1
  75. data/lib/fluent/plugin/parser_json.rb +1 -1
  76. data/lib/fluent/plugin/parser_syslog.rb +1 -1
  77. data/lib/fluent/plugin/storage_local.rb +3 -5
  78. data/lib/fluent/plugin.rb +10 -1
  79. data/lib/fluent/plugin_helper/child_process.rb +3 -0
  80. data/lib/fluent/plugin_helper/event_emitter.rb +8 -1
  81. data/lib/fluent/plugin_helper/event_loop.rb +2 -2
  82. data/lib/fluent/plugin_helper/http_server/server.rb +2 -1
  83. data/lib/fluent/plugin_helper/metrics.rb +129 -0
  84. data/lib/fluent/plugin_helper/record_accessor.rb +1 -1
  85. data/lib/fluent/plugin_helper/retry_state.rb +14 -4
  86. data/lib/fluent/plugin_helper/server.rb +35 -6
  87. data/lib/fluent/plugin_helper/service_discovery.rb +2 -2
  88. data/lib/fluent/plugin_helper/socket.rb +13 -2
  89. data/lib/fluent/plugin_helper/thread.rb +3 -3
  90. data/lib/fluent/plugin_helper.rb +1 -0
  91. data/lib/fluent/plugin_id.rb +3 -2
  92. data/lib/fluent/registry.rb +2 -1
  93. data/lib/fluent/root_agent.rb +6 -0
  94. data/lib/fluent/rpc.rb +4 -3
  95. data/lib/fluent/supervisor.rb +283 -259
  96. data/lib/fluent/system_config.rb +13 -3
  97. data/lib/fluent/test/driver/base.rb +11 -5
  98. data/lib/fluent/test/driver/filter.rb +4 -0
  99. data/lib/fluent/test/startup_shutdown.rb +6 -8
  100. data/lib/fluent/time.rb +21 -20
  101. data/lib/fluent/version.rb +1 -1
  102. data/lib/fluent/win32api.rb +38 -0
  103. data/lib/fluent/winsvc.rb +5 -8
  104. data/templates/new_gem/test/helper.rb.erb +0 -1
  105. data/test/command/test_cat.rb +31 -2
  106. data/test/command/test_ctl.rb +1 -2
  107. data/test/command/test_fluentd.rb +209 -24
  108. data/test/command/test_plugin_config_formatter.rb +0 -1
  109. data/test/compat/test_parser.rb +6 -6
  110. data/test/config/test_system_config.rb +13 -11
  111. data/test/config/test_types.rb +1 -1
  112. data/test/log/test_console_adapter.rb +110 -0
  113. data/test/plugin/in_tail/test_io_handler.rb +26 -8
  114. data/test/plugin/in_tail/test_position_file.rb +48 -59
  115. data/test/plugin/out_forward/test_ack_handler.rb +39 -0
  116. data/test/plugin/out_forward/test_socket_cache.rb +26 -1
  117. data/test/plugin/test_bare_output.rb +14 -1
  118. data/test/plugin/test_base.rb +133 -1
  119. data/test/plugin/test_buf_file.rb +62 -23
  120. data/test/plugin/test_buf_file_single.rb +65 -0
  121. data/test/plugin/test_buffer.rb +267 -3
  122. data/test/plugin/test_buffer_chunk.rb +11 -0
  123. data/test/plugin/test_filter.rb +12 -1
  124. data/test/plugin/test_filter_parser.rb +1 -1
  125. data/test/plugin/test_filter_stdout.rb +2 -2
  126. data/test/plugin/test_in_forward.rb +9 -11
  127. data/test/plugin/test_in_http.rb +65 -3
  128. data/test/plugin/test_in_monitor_agent.rb +216 -11
  129. data/test/plugin/test_in_object_space.rb +9 -3
  130. data/test/plugin/test_in_syslog.rb +35 -0
  131. data/test/plugin/test_in_tail.rb +1393 -385
  132. data/test/plugin/test_in_tcp.rb +87 -2
  133. data/test/plugin/test_in_udp.rb +28 -0
  134. data/test/plugin/test_in_unix.rb +2 -2
  135. data/test/plugin/test_input.rb +12 -1
  136. data/test/plugin/test_metrics.rb +294 -0
  137. data/test/plugin/test_metrics_local.rb +96 -0
  138. data/test/plugin/test_multi_output.rb +25 -1
  139. data/test/plugin/test_out_exec.rb +6 -4
  140. data/test/plugin/test_out_exec_filter.rb +6 -2
  141. data/test/plugin/test_out_file.rb +34 -17
  142. data/test/plugin/test_out_forward.rb +78 -77
  143. data/test/plugin/test_out_http.rb +1 -0
  144. data/test/plugin/test_out_stdout.rb +2 -2
  145. data/test/plugin/test_output.rb +297 -12
  146. data/test/plugin/test_output_as_buffered.rb +44 -44
  147. data/test/plugin/test_output_as_buffered_compress.rb +32 -18
  148. data/test/plugin/test_output_as_buffered_retries.rb +54 -7
  149. data/test/plugin/test_output_as_buffered_secondary.rb +4 -4
  150. data/test/plugin/test_parser_regexp.rb +1 -6
  151. data/test/plugin/test_parser_syslog.rb +1 -1
  152. data/test/plugin_helper/test_cert_option.rb +1 -1
  153. data/test/plugin_helper/test_child_process.rb +38 -16
  154. data/test/plugin_helper/test_event_emitter.rb +29 -0
  155. data/test/plugin_helper/test_http_server_helper.rb +1 -1
  156. data/test/plugin_helper/test_metrics.rb +137 -0
  157. data/test/plugin_helper/test_retry_state.rb +602 -38
  158. data/test/plugin_helper/test_server.rb +78 -6
  159. data/test/plugin_helper/test_timer.rb +2 -2
  160. data/test/test_config.rb +191 -24
  161. data/test/test_event_router.rb +17 -0
  162. data/test/test_file_wrapper.rb +53 -0
  163. data/test/test_formatter.rb +24 -21
  164. data/test/test_log.rb +122 -40
  165. data/test/test_msgpack_factory.rb +32 -0
  166. data/test/test_plugin_classes.rb +102 -0
  167. data/test/test_root_agent.rb +30 -1
  168. data/test/test_supervisor.rb +477 -257
  169. data/test/test_time_parser.rb +22 -0
  170. metadata +55 -34
  171. data/.drone.yml +0 -35
  172. data/.github/workflows/issue-auto-closer.yml +0 -12
  173. data/.github/workflows/linux-test.yaml +0 -36
  174. data/.github/workflows/macos-test.yaml +0 -30
  175. data/.github/workflows/windows-test.yaml +0 -46
  176. data/.gitlab-ci.yml +0 -103
  177. data/lib/fluent/plugin/file_wrapper.rb +0 -187
  178. data/test/plugin/test_file_wrapper.rb +0 -126
  179. data/test/test_logger_initializer.rb +0 -46
@@ -16,14 +16,20 @@ class ServerPluginHelperTest < Test::Unit::TestCase
16
16
 
17
17
  setup do
18
18
  @port = unused_port
19
- @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
20
- if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
21
- FileUtils.rm_f @socket_manager_path
19
+ if Fluent.windows?
20
+ @socket_manager_server = ServerEngine::SocketManager::Server.open
21
+ @socket_manager_path = @socket_manager_server.path
22
+ else
23
+ @socket_manager_path = ServerEngine::SocketManager::Server.generate_path
24
+ if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
25
+ FileUtils.rm_f @socket_manager_path
26
+ end
27
+ @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
22
28
  end
23
- @socket_manager_server = ServerEngine::SocketManager::Server.open(@socket_manager_path)
24
29
  ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_path.to_s
25
30
 
26
31
  @d = Dummy.new
32
+ @d.under_plugin_development = true
27
33
  @d.start
28
34
  @d.after_start
29
35
  end
@@ -37,7 +43,7 @@ class ServerPluginHelperTest < Test::Unit::TestCase
37
43
  (@d.terminated? || @d.terminate) rescue nil
38
44
 
39
45
  @socket_manager_server.close
40
- if @socket_manager_server.is_a?(String) && File.exist?(@socket_manager_path)
46
+ if @socket_manager_path.is_a?(String) && File.exist?(@socket_manager_path)
41
47
  FileUtils.rm_f @socket_manager_path
42
48
  end
43
49
  end
@@ -64,6 +70,24 @@ class ServerPluginHelperTest < Test::Unit::TestCase
64
70
  end
65
71
  assert d.plugin_id
66
72
  assert d.log
73
+ assert_equal 0, d.transport_config.linger_timeout
74
+ end
75
+
76
+ test 'can change linger_timeout option' do
77
+ d = Dummy.new
78
+
79
+ transport_opts = {
80
+ 'linger_timeout' => 1,
81
+ }
82
+ transport_conf = config_element('transport', 'tcp', transport_opts)
83
+ conf = config_element('source', 'tag.*', {}, [transport_conf])
84
+
85
+ assert_nothing_raised do
86
+ d.configure(conf)
87
+ end
88
+ assert d.plugin_id
89
+ assert d.log
90
+ assert_equal 1, d.transport_config.linger_timeout
67
91
  end
68
92
  end
69
93
 
@@ -771,6 +795,50 @@ class ServerPluginHelperTest < Test::Unit::TestCase
771
795
  end
772
796
  end
773
797
  end
798
+
799
+ sub_test_case 'over max_bytes' do
800
+ data("cut off on Non-Windows", { max_bytes: 32, records: ["a" * 40], expected: ["a" * 32] }, keep: true) unless Fluent.windows?
801
+ data("drop on Windows", { max_bytes: 32, records: ["a" * 40], expected: [] }, keep: true) if Fluent.windows?
802
+ test 'with sock' do |data|
803
+ max_bytes, records, expected = data.values
804
+
805
+ actual_records = []
806
+ @d.server_create_udp(:myserver, @port, max_bytes: max_bytes) do |data, sock|
807
+ actual_records << data
808
+ end
809
+
810
+ open_client(:udp, "127.0.0.1", @port) do |sock|
811
+ records.each do |record|
812
+ sock.send(record, 0)
813
+ end
814
+ end
815
+
816
+ waiting(10) { sleep 0.1 until actual_records.size >= expected.size }
817
+ sleep 1 if expected.size == 0 # To confirm no record recieved.
818
+
819
+ assert_equal expected, actual_records
820
+ end
821
+
822
+ test 'without sock' do |data|
823
+ max_bytes, records, expected = data.values
824
+
825
+ actual_records = []
826
+ @d.server_create_udp(:myserver, @port, max_bytes: max_bytes) do |data|
827
+ actual_records << data
828
+ end
829
+
830
+ open_client(:udp, "127.0.0.1", @port) do |sock|
831
+ records.each do |record|
832
+ sock.send(record, 0)
833
+ end
834
+ end
835
+
836
+ waiting(10) { sleep 0.1 until actual_records.size >= expected.size }
837
+ sleep 1 if expected.size == 0 # To confirm no record recieved.
838
+
839
+ assert_equal expected, actual_records
840
+ end
841
+ end
774
842
  end
775
843
 
776
844
  module CertUtil
@@ -1261,7 +1329,7 @@ class ServerPluginHelperTest < Test::Unit::TestCase
1261
1329
  # OpenSSL 1.1.1: "TLSv1.2"
1262
1330
  if tls_version == "TLSv1/SSLv3" || tls_version == "TLSv1.2"
1263
1331
  matched = true
1264
- unless cipher_name.match(/#{conf.ciphers}/)
1332
+ unless cipher_name.match?(/#{conf.ciphers}/)
1265
1333
  matched = false
1266
1334
  break
1267
1335
  end
@@ -1552,6 +1620,10 @@ class ServerPluginHelperTest < Test::Unit::TestCase
1552
1620
 
1553
1621
  def open_client(proto, addr, port)
1554
1622
  client = case proto
1623
+ when :udp
1624
+ c = UDPSocket.open
1625
+ c.connect(addr, port)
1626
+ c
1555
1627
  when :tcp
1556
1628
  TCPSocket.open(addr, port)
1557
1629
  when :tls
@@ -90,8 +90,8 @@ class TimerTest < Test::Unit::TestCase
90
90
  assert{ counter1 >= 4 && counter1 <= 5 }
91
91
  assert{ counter2 == 2 }
92
92
  msg = "Unexpected error raised. Stopping the timer. title=:t2"
93
- assert{ d1.log.out.logs.any?{|line| line.include?("[error]:") && line.include?(msg) && line.include?("abort!!!!!!") } }
94
- assert{ d1.log.out.logs.any?{|line| line.include?("[error]:") && line.include?("Timer detached. title=:t2") } }
93
+ assert(d1.log.out.logs.any?{|line| line.include?("[error]:") && line.include?(msg) && line.include?("abort!!!!!!") })
94
+ assert(d1.log.out.logs.any?{|line| line.include?("[error]:") && line.include?("Timer detached. title=:t2") })
95
95
 
96
96
  d1.shutdown; d1.close; d1.terminate
97
97
  end
data/test/test_config.rb CHANGED
@@ -10,11 +10,18 @@ class ConfigTest < Test::Unit::TestCase
10
10
 
11
11
  TMP_DIR = File.dirname(__FILE__) + "/tmp/config#{ENV['TEST_ENV_NUMBER']}"
12
12
 
13
- def read_config(path)
13
+ def read_config(path, use_yaml: false)
14
14
  path = File.expand_path(path)
15
- File.open(path) { |io|
16
- Fluent::Config::Parser.parse(io, File.basename(path), File.dirname(path))
17
- }
15
+ if use_yaml
16
+ context = Kernel.binding
17
+
18
+ s = Fluent::Config::YamlParser::Loader.new(context).load(Pathname.new(path))
19
+ Fluent::Config::YamlParser::Parser.new(s).build.to_element
20
+ else
21
+ File.open(path) { |io|
22
+ Fluent::Config::Parser.parse(io, File.basename(path), File.dirname(path))
23
+ }
24
+ end
18
25
  end
19
26
 
20
27
  def prepare_config
@@ -151,30 +158,190 @@ class ConfigTest < Test::Unit::TestCase
151
158
  assert_equal before_size, match_conf.unused.size
152
159
  end
153
160
 
154
- def write_config(path, data, encoding: 'utf-8')
155
- FileUtils.mkdir_p(File.dirname(path))
156
- File.open(path, "w:#{encoding}:utf-8") {|f| f.write data }
157
- end
161
+ sub_test_case "yaml config" do
162
+ def test_included
163
+ write_config "#{TMP_DIR}/config_test_not_fetched.yaml", <<-EOS
164
+ config:
165
+ - source:
166
+ $type: dummy
167
+ tag: tag.dummy
168
+ - source:
169
+ $type: tcp
170
+ tag: tag.tcp
171
+ parse:
172
+ $arg:
173
+ - why.parse.section.doesnot.have.arg
174
+ - huh
175
+ $type: none
176
+ - match:
177
+ $tag: tag.*
178
+ $type: stdout
179
+ buffer:
180
+ $type: memory
181
+ flush_interval: 1s
182
+ - !include fluent-included.yaml
183
+ EOS
184
+ write_config "#{TMP_DIR}/fluent-included.yaml", <<-EOS
185
+ - label:
186
+ $name: '@FLUENT_LOG'
187
+ config:
188
+ - match:
189
+ $type: "null"
190
+ $tag: "**"
191
+ buffer:
192
+ $type: memory
193
+ flush_mode: interval
194
+ flush_interval: 1s
195
+ EOS
196
+ root_conf = read_config("#{TMP_DIR}/config_test_not_fetched.yaml", use_yaml: true)
197
+ dummy_source_conf = root_conf.elements.first
198
+ tcp_source_conf = root_conf.elements[1]
199
+ parse_tcp_conf = tcp_source_conf.elements.first
200
+ match_conf = root_conf.elements[2]
201
+ label_conf = root_conf.elements[3]
202
+ fluent_log_conf = label_conf.elements.first
203
+ fluent_log_buffer_conf = fluent_log_conf.elements.first
158
204
 
159
- def test_inline
160
- prepare_config
161
- opts = {
162
- :config_path => "#{TMP_DIR}/config_test_1.conf",
163
- :inline_config => "<source>\n type http\n port 2222\n </source>",
164
- :use_v1_config => false
165
- }
166
- assert_nothing_raised do
167
- Fluent::Supervisor.new(opts)
205
+ assert_equal(
206
+ [
207
+ 'dummy',
208
+ 'tag.dummy',
209
+ 'tcp',
210
+ 'tag.tcp',
211
+ 'none',
212
+ 'why.parse.section.doesnot.have.arg,huh',
213
+ 'stdout',
214
+ 'tag.*',
215
+ 'null',
216
+ '**',
217
+ '@FLUENT_LOG',
218
+ 'memory',
219
+ 'interval',
220
+ '1s',
221
+ ],
222
+ [
223
+ dummy_source_conf['@type'],
224
+ dummy_source_conf['tag'],
225
+ tcp_source_conf['@type'],
226
+ tcp_source_conf['tag'],
227
+ parse_tcp_conf['@type'],
228
+ parse_tcp_conf.arg,
229
+ match_conf['@type'],
230
+ match_conf.arg,
231
+ fluent_log_conf['@type'],
232
+ fluent_log_conf.arg,
233
+ label_conf.arg,
234
+ fluent_log_buffer_conf['@type'],
235
+ fluent_log_buffer_conf['flush_mode'],
236
+ fluent_log_buffer_conf['flush_interval'],
237
+ ])
238
+ end
239
+
240
+ def test_included_glob
241
+ write_config "#{TMP_DIR}/config.yaml", <<-EOS
242
+ config:
243
+ - !include "include/*.yaml"
244
+ EOS
245
+ write_config "#{TMP_DIR}/include/02_source2.yaml", <<-EOS
246
+ - source:
247
+ $type: dummy
248
+ tag: tag.dummy
249
+ EOS
250
+ write_config "#{TMP_DIR}/include/01_source1.yaml", <<-EOS
251
+ - source:
252
+ $type: tcp
253
+ tag: tag.tcp
254
+ parse:
255
+ $arg:
256
+ - why.parse.section.doesnot.have.arg
257
+ - huh
258
+ $type: none
259
+ EOS
260
+ write_config "#{TMP_DIR}/include/03_match1.yaml", <<-EOS
261
+ - match:
262
+ $tag: tag.*
263
+ $type: stdout
264
+ buffer:
265
+ $type: memory
266
+ flush_interval: 1s
267
+ EOS
268
+ root_conf = read_config("#{TMP_DIR}/config.yaml", use_yaml: true)
269
+ tcp_source_conf = root_conf.elements.first
270
+ dummy_source_conf = root_conf.elements[1]
271
+ parse_tcp_conf = tcp_source_conf.elements.first
272
+ match_conf = root_conf.elements[2]
273
+
274
+ assert_equal(
275
+ [
276
+ 'tcp',
277
+ 'tag.tcp',
278
+ 'none',
279
+ 'why.parse.section.doesnot.have.arg,huh',
280
+ 'dummy',
281
+ 'tag.dummy',
282
+ 'stdout',
283
+ 'tag.*',
284
+ ],
285
+ [
286
+ tcp_source_conf['@type'],
287
+ tcp_source_conf['tag'],
288
+ parse_tcp_conf['@type'],
289
+ parse_tcp_conf.arg,
290
+ dummy_source_conf['@type'],
291
+ dummy_source_conf['tag'],
292
+ match_conf['@type'],
293
+ match_conf.arg,
294
+ ])
295
+ end
296
+
297
+ def test_check_not_fetchd
298
+ write_config "#{TMP_DIR}/config_test_not_fetched.yaml", <<-EOS
299
+ config:
300
+ - match:
301
+ $arg: dummy
302
+ $type: rewrite
303
+ add_prefix: filtered
304
+ rule:
305
+ key: path
306
+ pattern: "^[A-Z]+"
307
+ replace: true
308
+ EOS
309
+ root_conf = read_config("#{TMP_DIR}/config_test_not_fetched.yaml", use_yaml: true)
310
+ match_conf = root_conf.elements.first
311
+ rule_conf = match_conf.elements.first
312
+
313
+ not_fetched = []; root_conf.check_not_fetched {|key, e| not_fetched << key }
314
+ assert_equal %w[@type $arg add_prefix key pattern replace], not_fetched
315
+
316
+ not_fetched = []; match_conf.check_not_fetched {|key, e| not_fetched << key }
317
+ assert_equal %w[@type $arg add_prefix key pattern replace], not_fetched
318
+
319
+ not_fetched = []; rule_conf.check_not_fetched {|key, e| not_fetched << key }
320
+ assert_equal %w[key pattern replace], not_fetched
321
+
322
+ # accessing should delete
323
+ match_conf['type']
324
+ rule_conf['key']
325
+
326
+ not_fetched = []; root_conf.check_not_fetched {|key, e| not_fetched << key }
327
+ assert_equal %w[@type $arg add_prefix pattern replace], not_fetched
328
+
329
+ not_fetched = []; match_conf.check_not_fetched {|key, e| not_fetched << key }
330
+ assert_equal %w[@type $arg add_prefix pattern replace], not_fetched
331
+
332
+ not_fetched = []; rule_conf.check_not_fetched {|key, e| not_fetched << key }
333
+ assert_equal %w[pattern replace], not_fetched
334
+
335
+ # repeatedly accessing should not grow memory usage
336
+ before_size = match_conf.unused.size
337
+ 10.times { match_conf['type'] }
338
+ assert_equal before_size, match_conf.unused.size
168
339
  end
169
- create_warn_dummy_logger
170
340
  end
171
341
 
172
- def create_warn_dummy_logger
173
- dl_opts = {}
174
- dl_opts[:log_level] = ServerEngine::DaemonLogger::WARN
175
- logdev = Fluent::Test::DummyLogDevice.new
176
- logger = ServerEngine::DaemonLogger.new(logdev, dl_opts)
177
- $log = Fluent::Log.new(logger)
342
+ def write_config(path, data, encoding: 'utf-8')
343
+ FileUtils.mkdir_p(File.dirname(path))
344
+ File.open(path, "w:#{encoding}:utf-8") {|f| f.write data }
178
345
  end
179
346
 
180
347
  sub_test_case '.build' do
@@ -326,6 +326,23 @@ class EventRouterTest < ::Test::Unit::TestCase
326
326
  event_router.emit('test', Engine.now, 'k' => 'v')
327
327
  end
328
328
  end
329
+
330
+ test 'can pass records modified by filters to handle_emits_error' do
331
+ filter = Class.new(FluentTestFilter) {
332
+ def filter_stream(_tag, es); end
333
+ }.new
334
+ event_router.add_rule('test', filter)
335
+ event_router.add_rule('test', error_output)
336
+
337
+ time = Engine.now
338
+ modified_es = OneEventStream.new(time, 'modified_label' => 'modified_value')
339
+
340
+ assert_rr do
341
+ stub(filter).filter_stream { modified_es }
342
+ mock(emit_handler).handle_emits_error('test', modified_es, is_a(RuntimeError))
343
+ event_router.emit('test', time, 'pre_label' => 'pre_value')
344
+ end
345
+ end
329
346
  end
330
347
  end
331
348
  end
@@ -0,0 +1,53 @@
1
+ require_relative 'helper'
2
+ require 'fluent/file_wrapper'
3
+
4
+ class FileWrapperTest < Test::Unit::TestCase
5
+ TMP_DIR = File.dirname(__FILE__) + "/../tmp/file_wrapper#{ENV['TEST_ENV_NUMBER']}"
6
+
7
+ def setup
8
+ FileUtils.mkdir_p(TMP_DIR)
9
+ end
10
+
11
+ def teardown
12
+ FileUtils.rm_rf(TMP_DIR)
13
+ end
14
+
15
+ sub_test_case 'WindowsFile exceptions' do
16
+ test 'nothing raised' do
17
+ begin
18
+ path = "#{TMP_DIR}/test_windows_file.txt"
19
+ file1 = file2 = nil
20
+ file1 = File.open(path, "wb") do |f|
21
+ end
22
+ assert_nothing_raised do
23
+ file2 = Fluent::WindowsFile.new(path)
24
+ ensure
25
+ file2.close
26
+ end
27
+ ensure
28
+ file1.close if file1
29
+ end
30
+ end
31
+
32
+ test 'Errno::ENOENT raised' do
33
+ path = "#{TMP_DIR}/nofile.txt"
34
+ file = nil
35
+ assert_raise(Errno::ENOENT) do
36
+ file = Fluent::WindowsFile.new(path)
37
+ ensure
38
+ file.close if file
39
+ end
40
+ end
41
+
42
+ test 'Errno::ENOENT raised on DeletePending' do
43
+ path = "#{TMP_DIR}/deletepending.txt"
44
+ file = Fluent::WindowsFile.new(path, mode='w')
45
+ File.delete(path)
46
+ assert_raise(Errno::ENOENT) do
47
+ file.stat
48
+ ensure
49
+ file.close if file
50
+ end
51
+ end
52
+ end
53
+ end if Fluent.windows?
@@ -18,7 +18,7 @@ module FormatterTest
18
18
 
19
19
  def test_call
20
20
  formatter = Formatter.new
21
- formatter.configure({})
21
+ formatter.configure(config_element())
22
22
  assert_raise NotImplementedError do
23
23
  formatter.format('tag', Engine.now, {})
24
24
  end
@@ -130,7 +130,7 @@ module FormatterTest
130
130
  include FormatterTest
131
131
 
132
132
  def setup
133
- @formatter = TextFormatter::MessagePackFormatter.new
133
+ @formatter = Fluent::Test::FormatterTestDriver.new(TextFormatter::MessagePackFormatter)
134
134
  @time = Engine.now
135
135
  end
136
136
 
@@ -146,7 +146,7 @@ module FormatterTest
146
146
  include FormatterTest
147
147
 
148
148
  def setup
149
- @formatter = TextFormatter::LabeledTSVFormatter.new
149
+ @formatter = Fluent::Test::FormatterTestDriver.new(TextFormatter::LabeledTSVFormatter)
150
150
  @time = Engine.now
151
151
  @newline = if Fluent.windows?
152
152
  "\r\n"
@@ -156,16 +156,16 @@ module FormatterTest
156
156
  end
157
157
 
158
158
  def test_config_params
159
- assert_equal "\t", @formatter.delimiter
160
- assert_equal ":", @formatter.label_delimiter
159
+ assert_equal "\t", @formatter.instance.delimiter
160
+ assert_equal ":", @formatter.instance.label_delimiter
161
161
 
162
162
  @formatter.configure(
163
163
  'delimiter' => ',',
164
164
  'label_delimiter' => '=',
165
165
  )
166
166
 
167
- assert_equal ",", @formatter.delimiter
168
- assert_equal "=", @formatter.label_delimiter
167
+ assert_equal ",", @formatter.instance.delimiter
168
+ assert_equal "=", @formatter.instance.label_delimiter
169
169
  end
170
170
 
171
171
  def test_format
@@ -220,14 +220,14 @@ module FormatterTest
220
220
  include FormatterTest
221
221
 
222
222
  def setup
223
- @formatter = TextFormatter::CsvFormatter.new
223
+ @formatter = Fluent::Test::FormatterTestDriver.new(TextFormatter::CsvFormatter)
224
224
  @time = Engine.now
225
225
  end
226
226
 
227
227
  def test_config_params
228
- assert_equal ',', @formatter.delimiter
229
- assert_equal true, @formatter.force_quotes
230
- assert_nil @formatter.fields
228
+ assert_equal ',', @formatter.instance.delimiter
229
+ assert_equal true, @formatter.instance.force_quotes
230
+ assert_nil @formatter.instance.fields
231
231
  end
232
232
 
233
233
  data(
@@ -237,8 +237,8 @@ module FormatterTest
237
237
  def test_config_params_with_customized_delimiters(data)
238
238
  expected, target = data
239
239
  @formatter.configure('delimiter' => target, 'fields' => 'a,b,c')
240
- assert_equal expected, @formatter.delimiter
241
- assert_equal ['a', 'b', 'c'], @formatter.fields
240
+ assert_equal expected, @formatter.instance.delimiter
241
+ assert_equal ['a', 'b', 'c'], @formatter.instance.fields
242
242
  end
243
243
 
244
244
  def test_format
@@ -299,7 +299,7 @@ module FormatterTest
299
299
  'blank' => 'one,,two,three')
300
300
  def test_config_params_with_fields(data)
301
301
  @formatter.configure('fields' => data)
302
- assert_equal %w(one two three), @formatter.fields
302
+ assert_equal %w(one two three), @formatter.instance.fields
303
303
  end
304
304
  end
305
305
 
@@ -313,31 +313,34 @@ module FormatterTest
313
313
  end
314
314
  end
315
315
 
316
+ def create_driver(klass_or_str)
317
+ Fluent::Test::FormatterTestDriver.new(klass_or_str)
318
+ end
316
319
 
317
320
  def test_config_params
318
- formatter = TextFormatter::SingleValueFormatter.new
319
- assert_equal "message", formatter.message_key
321
+ formatter = create_driver(TextFormatter::SingleValueFormatter)
322
+ assert_equal "message", formatter.instance.message_key
320
323
 
321
324
  formatter.configure('message_key' => 'foobar')
322
- assert_equal "foobar", formatter.message_key
325
+ assert_equal "foobar", formatter.instance.message_key
323
326
  end
324
327
 
325
328
  def test_format
326
- formatter = Fluent::Plugin.new_formatter('single_value')
329
+ formatter = create_driver('single_value')
327
330
  formatter.configure({})
328
331
  formatted = formatter.format('tag', Engine.now, {'message' => 'awesome'})
329
332
  assert_equal("awesome#{@newline}", formatted)
330
333
  end
331
334
 
332
335
  def test_format_without_newline
333
- formatter = Fluent::Plugin.new_formatter('single_value')
336
+ formatter = create_driver('single_value')
334
337
  formatter.configure('add_newline' => 'false')
335
338
  formatted = formatter.format('tag', Engine.now, {'message' => 'awesome'})
336
339
  assert_equal("awesome", formatted)
337
340
  end
338
341
 
339
342
  def test_format_with_message_key
340
- formatter = TextFormatter::SingleValueFormatter.new
343
+ formatter = create_driver(TextFormatter::SingleValueFormatter)
341
344
  formatter.configure('message_key' => 'foobar')
342
345
  formatted = formatter.format('tag', Engine.now, {'foobar' => 'foo'})
343
346
 
@@ -349,7 +352,7 @@ module FormatterTest
349
352
  include FormatterTest
350
353
 
351
354
  def test_unknown_format
352
- assert_raise ConfigError do
355
+ assert_raise NotFoundPluginError do
353
356
  Fluent::Plugin.new_formatter('unknown')
354
357
  end
355
358
  end