fluentd 0.12.40 → 0.14.0

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 (252) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +6 -0
  3. data/.gitignore +2 -0
  4. data/.travis.yml +33 -21
  5. data/CONTRIBUTING.md +1 -0
  6. data/ChangeLog +810 -237
  7. data/README.md +0 -25
  8. data/Rakefile +2 -1
  9. data/Vagrantfile +17 -0
  10. data/appveyor.yml +35 -0
  11. data/example/filter_stdout.conf +5 -5
  12. data/example/in_forward.conf +2 -2
  13. data/example/in_http.conf +2 -2
  14. data/example/in_out_forward.conf +17 -0
  15. data/example/in_syslog.conf +2 -2
  16. data/example/in_tail.conf +2 -2
  17. data/example/in_tcp.conf +2 -2
  18. data/example/in_udp.conf +2 -2
  19. data/example/out_copy.conf +4 -4
  20. data/example/out_file.conf +2 -2
  21. data/example/out_forward.conf +2 -2
  22. data/example/out_forward_buf_file.conf +23 -0
  23. data/example/v0_12_filter.conf +8 -8
  24. data/fluent.conf +29 -0
  25. data/fluentd.gemspec +18 -11
  26. data/lib/fluent/agent.rb +60 -58
  27. data/lib/fluent/command/cat.rb +1 -1
  28. data/lib/fluent/command/debug.rb +7 -5
  29. data/lib/fluent/command/fluentd.rb +97 -2
  30. data/lib/fluent/compat/call_super_mixin.rb +67 -0
  31. data/lib/fluent/compat/filter.rb +50 -0
  32. data/lib/fluent/compat/formatter.rb +109 -0
  33. data/lib/fluent/compat/input.rb +50 -0
  34. data/lib/fluent/compat/output.rb +617 -0
  35. data/lib/fluent/compat/output_chain.rb +60 -0
  36. data/lib/fluent/compat/parser.rb +163 -0
  37. data/lib/fluent/compat/propagate_default.rb +62 -0
  38. data/lib/fluent/config.rb +23 -20
  39. data/lib/fluent/config/configure_proxy.rb +119 -70
  40. data/lib/fluent/config/dsl.rb +5 -18
  41. data/lib/fluent/config/element.rb +72 -8
  42. data/lib/fluent/config/error.rb +0 -3
  43. data/lib/fluent/config/literal_parser.rb +0 -2
  44. data/lib/fluent/config/parser.rb +4 -4
  45. data/lib/fluent/config/section.rb +39 -28
  46. data/lib/fluent/config/types.rb +2 -13
  47. data/lib/fluent/config/v1_parser.rb +1 -3
  48. data/lib/fluent/configurable.rb +48 -16
  49. data/lib/fluent/daemon.rb +15 -0
  50. data/lib/fluent/engine.rb +26 -52
  51. data/lib/fluent/env.rb +6 -4
  52. data/lib/fluent/event.rb +58 -11
  53. data/lib/fluent/event_router.rb +5 -5
  54. data/lib/fluent/filter.rb +2 -50
  55. data/lib/fluent/formatter.rb +4 -293
  56. data/lib/fluent/input.rb +2 -32
  57. data/lib/fluent/label.rb +2 -2
  58. data/lib/fluent/load.rb +3 -2
  59. data/lib/fluent/log.rb +107 -38
  60. data/lib/fluent/match.rb +0 -36
  61. data/lib/fluent/mixin.rb +117 -7
  62. data/lib/fluent/msgpack_factory.rb +62 -0
  63. data/lib/fluent/output.rb +7 -612
  64. data/lib/fluent/output_chain.rb +23 -0
  65. data/lib/fluent/parser.rb +4 -800
  66. data/lib/fluent/plugin.rb +100 -121
  67. data/lib/fluent/plugin/bare_output.rb +63 -0
  68. data/lib/fluent/plugin/base.rb +121 -0
  69. data/lib/fluent/plugin/buf_file.rb +101 -182
  70. data/lib/fluent/plugin/buf_memory.rb +9 -92
  71. data/lib/fluent/plugin/buffer.rb +473 -0
  72. data/lib/fluent/plugin/buffer/chunk.rb +135 -0
  73. data/lib/fluent/plugin/buffer/file_chunk.rb +339 -0
  74. data/lib/fluent/plugin/buffer/memory_chunk.rb +100 -0
  75. data/lib/fluent/plugin/exec_util.rb +80 -75
  76. data/lib/fluent/plugin/file_util.rb +33 -28
  77. data/lib/fluent/plugin/file_wrapper.rb +120 -0
  78. data/lib/fluent/plugin/filter.rb +51 -0
  79. data/lib/fluent/plugin/filter_grep.rb +13 -40
  80. data/lib/fluent/plugin/filter_record_transformer.rb +22 -18
  81. data/lib/fluent/plugin/formatter.rb +93 -0
  82. data/lib/fluent/plugin/formatter_csv.rb +48 -0
  83. data/lib/fluent/plugin/formatter_hash.rb +32 -0
  84. data/lib/fluent/plugin/formatter_json.rb +47 -0
  85. data/lib/fluent/plugin/formatter_ltsv.rb +42 -0
  86. data/lib/fluent/plugin/formatter_msgpack.rb +32 -0
  87. data/lib/fluent/plugin/formatter_out_file.rb +45 -0
  88. data/lib/fluent/plugin/formatter_single_value.rb +34 -0
  89. data/lib/fluent/plugin/formatter_stdout.rb +39 -0
  90. data/lib/fluent/plugin/in_debug_agent.rb +4 -0
  91. data/lib/fluent/plugin/in_dummy.rb +22 -18
  92. data/lib/fluent/plugin/in_exec.rb +18 -8
  93. data/lib/fluent/plugin/in_forward.rb +36 -79
  94. data/lib/fluent/plugin/in_gc_stat.rb +4 -0
  95. data/lib/fluent/plugin/in_http.rb +21 -18
  96. data/lib/fluent/plugin/in_monitor_agent.rb +15 -48
  97. data/lib/fluent/plugin/in_object_space.rb +6 -1
  98. data/lib/fluent/plugin/in_stream.rb +7 -3
  99. data/lib/fluent/plugin/in_syslog.rb +46 -95
  100. data/lib/fluent/plugin/in_tail.rb +51 -595
  101. data/lib/fluent/plugin/in_tcp.rb +8 -1
  102. data/lib/fluent/plugin/in_udp.rb +8 -14
  103. data/lib/fluent/plugin/input.rb +33 -0
  104. data/lib/fluent/plugin/multi_output.rb +95 -0
  105. data/lib/fluent/plugin/out_buffered_null.rb +59 -0
  106. data/lib/fluent/plugin/out_copy.rb +11 -7
  107. data/lib/fluent/plugin/out_exec.rb +15 -11
  108. data/lib/fluent/plugin/out_exec_filter.rb +18 -10
  109. data/lib/fluent/plugin/out_file.rb +34 -5
  110. data/lib/fluent/plugin/out_forward.rb +19 -9
  111. data/lib/fluent/plugin/out_null.rb +0 -14
  112. data/lib/fluent/plugin/out_roundrobin.rb +11 -7
  113. data/lib/fluent/plugin/out_stdout.rb +5 -7
  114. data/lib/fluent/plugin/out_stream.rb +3 -1
  115. data/lib/fluent/plugin/output.rb +979 -0
  116. data/lib/fluent/plugin/owned_by_mixin.rb +42 -0
  117. data/lib/fluent/plugin/parser.rb +244 -0
  118. data/lib/fluent/plugin/parser_apache.rb +24 -0
  119. data/lib/fluent/plugin/parser_apache2.rb +84 -0
  120. data/lib/fluent/plugin/parser_apache_error.rb +21 -0
  121. data/lib/fluent/plugin/parser_csv.rb +31 -0
  122. data/lib/fluent/plugin/parser_json.rb +79 -0
  123. data/lib/fluent/plugin/parser_ltsv.rb +50 -0
  124. data/lib/fluent/plugin/parser_multiline.rb +102 -0
  125. data/lib/fluent/plugin/parser_nginx.rb +24 -0
  126. data/lib/fluent/plugin/parser_none.rb +36 -0
  127. data/lib/fluent/plugin/parser_syslog.rb +82 -0
  128. data/lib/fluent/plugin/parser_tsv.rb +37 -0
  129. data/lib/fluent/plugin/socket_util.rb +120 -114
  130. data/lib/fluent/plugin/storage.rb +84 -0
  131. data/lib/fluent/plugin/storage_local.rb +116 -0
  132. data/lib/fluent/plugin/string_util.rb +16 -13
  133. data/lib/fluent/plugin_helper.rb +39 -0
  134. data/lib/fluent/plugin_helper/child_process.rb +298 -0
  135. data/lib/fluent/plugin_helper/compat_parameters.rb +99 -0
  136. data/lib/fluent/plugin_helper/event_emitter.rb +80 -0
  137. data/lib/fluent/plugin_helper/event_loop.rb +118 -0
  138. data/lib/fluent/plugin_helper/retry_state.rb +177 -0
  139. data/lib/fluent/plugin_helper/storage.rb +308 -0
  140. data/lib/fluent/plugin_helper/thread.rb +147 -0
  141. data/lib/fluent/plugin_helper/timer.rb +85 -0
  142. data/lib/fluent/plugin_id.rb +63 -0
  143. data/lib/fluent/process.rb +21 -30
  144. data/lib/fluent/registry.rb +21 -9
  145. data/lib/fluent/root_agent.rb +115 -40
  146. data/lib/fluent/supervisor.rb +330 -320
  147. data/lib/fluent/system_config.rb +42 -18
  148. data/lib/fluent/test.rb +6 -1
  149. data/lib/fluent/test/base.rb +23 -3
  150. data/lib/fluent/test/driver/base.rb +247 -0
  151. data/lib/fluent/test/driver/event_feeder.rb +98 -0
  152. data/lib/fluent/test/driver/filter.rb +35 -0
  153. data/lib/fluent/test/driver/input.rb +31 -0
  154. data/lib/fluent/test/driver/output.rb +78 -0
  155. data/lib/fluent/test/driver/test_event_router.rb +45 -0
  156. data/lib/fluent/test/filter_test.rb +0 -1
  157. data/lib/fluent/test/formatter_test.rb +2 -1
  158. data/lib/fluent/test/input_test.rb +23 -17
  159. data/lib/fluent/test/output_test.rb +28 -39
  160. data/lib/fluent/test/parser_test.rb +1 -1
  161. data/lib/fluent/time.rb +104 -1
  162. data/lib/fluent/{status.rb → unique_id.rb} +15 -24
  163. data/lib/fluent/version.rb +1 -1
  164. data/lib/fluent/winsvc.rb +72 -0
  165. data/test/compat/test_calls_super.rb +164 -0
  166. data/test/config/test_config_parser.rb +83 -0
  167. data/test/config/test_configurable.rb +547 -274
  168. data/test/config/test_configure_proxy.rb +146 -29
  169. data/test/config/test_dsl.rb +3 -181
  170. data/test/config/test_element.rb +274 -0
  171. data/test/config/test_literal_parser.rb +1 -1
  172. data/test/config/test_section.rb +79 -7
  173. data/test/config/test_system_config.rb +21 -0
  174. data/test/config/test_types.rb +3 -26
  175. data/test/helper.rb +78 -8
  176. data/test/plugin/test_bare_output.rb +118 -0
  177. data/test/plugin/test_base.rb +75 -0
  178. data/test/plugin/test_buf_file.rb +420 -521
  179. data/test/plugin/test_buf_memory.rb +32 -194
  180. data/test/plugin/test_buffer.rb +981 -0
  181. data/test/plugin/test_buffer_chunk.rb +110 -0
  182. data/test/plugin/test_buffer_file_chunk.rb +770 -0
  183. data/test/plugin/test_buffer_memory_chunk.rb +265 -0
  184. data/test/plugin/test_filter.rb +255 -0
  185. data/test/plugin/test_filter_grep.rb +2 -73
  186. data/test/plugin/test_filter_record_transformer.rb +24 -68
  187. data/test/plugin/test_filter_stdout.rb +6 -6
  188. data/test/plugin/test_in_debug_agent.rb +2 -0
  189. data/test/plugin/test_in_dummy.rb +11 -17
  190. data/test/plugin/test_in_exec.rb +6 -25
  191. data/test/plugin/test_in_forward.rb +112 -151
  192. data/test/plugin/test_in_gc_stat.rb +2 -0
  193. data/test/plugin/test_in_http.rb +106 -157
  194. data/test/plugin/test_in_object_space.rb +21 -5
  195. data/test/plugin/test_in_stream.rb +14 -13
  196. data/test/plugin/test_in_syslog.rb +30 -275
  197. data/test/plugin/test_in_tail.rb +95 -234
  198. data/test/plugin/test_in_tcp.rb +14 -0
  199. data/test/plugin/test_in_udp.rb +21 -13
  200. data/test/plugin/test_input.rb +122 -0
  201. data/test/plugin/test_multi_output.rb +180 -0
  202. data/test/plugin/test_out_buffered_null.rb +79 -0
  203. data/test/plugin/test_out_copy.rb +15 -2
  204. data/test/plugin/test_out_exec.rb +75 -25
  205. data/test/plugin/test_out_exec_filter.rb +74 -8
  206. data/test/plugin/test_out_file.rb +61 -7
  207. data/test/plugin/test_out_forward.rb +92 -15
  208. data/test/plugin/test_out_roundrobin.rb +1 -0
  209. data/test/plugin/test_out_stdout.rb +22 -13
  210. data/test/plugin/test_out_stream.rb +18 -0
  211. data/test/plugin/test_output.rb +515 -0
  212. data/test/plugin/test_output_as_buffered.rb +1540 -0
  213. data/test/plugin/test_output_as_buffered_overflow.rb +247 -0
  214. data/test/plugin/test_output_as_buffered_retries.rb +808 -0
  215. data/test/plugin/test_output_as_buffered_secondary.rb +776 -0
  216. data/test/plugin/test_output_as_standard.rb +362 -0
  217. data/test/plugin/test_owned_by.rb +35 -0
  218. data/test/plugin/test_storage.rb +167 -0
  219. data/test/plugin/test_storage_local.rb +8 -0
  220. data/test/plugin_helper/test_child_process.rb +599 -0
  221. data/test/plugin_helper/test_compat_parameters.rb +175 -0
  222. data/test/plugin_helper/test_event_emitter.rb +51 -0
  223. data/test/plugin_helper/test_event_loop.rb +52 -0
  224. data/test/plugin_helper/test_retry_state.rb +399 -0
  225. data/test/plugin_helper/test_storage.rb +411 -0
  226. data/test/plugin_helper/test_thread.rb +164 -0
  227. data/test/plugin_helper/test_timer.rb +100 -0
  228. data/test/scripts/exec_script.rb +0 -6
  229. data/test/scripts/fluent/plugin/out_test.rb +3 -0
  230. data/test/test_config.rb +13 -4
  231. data/test/test_event.rb +24 -13
  232. data/test/test_event_router.rb +8 -7
  233. data/test/test_event_time.rb +187 -0
  234. data/test/test_formatter.rb +13 -51
  235. data/test/test_input.rb +1 -1
  236. data/test/test_log.rb +239 -16
  237. data/test/test_mixin.rb +1 -1
  238. data/test/test_output.rb +53 -66
  239. data/test/test_parser.rb +105 -323
  240. data/test/test_plugin_helper.rb +81 -0
  241. data/test/test_root_agent.rb +4 -52
  242. data/test/test_supervisor.rb +272 -0
  243. data/test/test_unique_id.rb +47 -0
  244. metadata +180 -54
  245. data/lib/fluent/buffer.rb +0 -365
  246. data/lib/fluent/plugin/filter_parser.rb +0 -107
  247. data/lib/fluent/plugin/in_status.rb +0 -76
  248. data/lib/fluent/test/helpers.rb +0 -86
  249. data/test/plugin/data/log/foo/bar2 +0 -0
  250. data/test/plugin/test_filter_parser.rb +0 -744
  251. data/test/plugin/test_in_status.rb +0 -38
  252. data/test/test_buffer.rb +0 -624
@@ -1,5 +1,6 @@
1
1
  require_relative '../helper'
2
2
  require 'fluent/test'
3
+ require 'fluent/plugin/out_forward'
3
4
 
4
5
  class ForwardOutputTest < Test::Unit::TestCase
5
6
  def setup
@@ -10,6 +11,7 @@ class ForwardOutputTest < Test::Unit::TestCase
10
11
  TARGET_PORT = 13999
11
12
  CONFIG = %[
12
13
  send_timeout 51
14
+ heartbeat_type udp
13
15
  <server>
14
16
  name test
15
17
  host #{TARGET_HOST}
@@ -39,21 +41,20 @@ class ForwardOutputTest < Test::Unit::TestCase
39
41
  @exceptions << e
40
42
  raise e
41
43
  end
42
-
43
- # Fluentd v0.12 BufferedOutputTestDriver calls this method.
44
- # BufferedOutput#format_stream calls format method, but ForwardOutput#format is not defined.
45
- # Because ObjectBufferedOutput#emit calls es.to_msgpack_stream directly.
46
- def format_stream(tag, es)
47
- es.to_msgpack_stream
48
- end
49
44
  }.configure(conf)
50
45
  end
51
46
 
52
47
  def test_configure
53
- d = create_driver
48
+ d = create_driver(%[
49
+ <server>
50
+ name test
51
+ host #{TARGET_HOST}
52
+ port #{TARGET_PORT}
53
+ </server>
54
+ ])
54
55
  nodes = d.instance.nodes
55
- assert_equal 51, d.instance.send_timeout
56
- assert_equal :udp, d.instance.heartbeat_type
56
+ assert_equal 60, d.instance.send_timeout
57
+ assert_equal :tcp, d.instance.heartbeat_type
57
58
  assert_equal 1, nodes.length
58
59
  node = nodes.first
59
60
  assert_equal "test", node.name
@@ -61,9 +62,9 @@ class ForwardOutputTest < Test::Unit::TestCase
61
62
  assert_equal 13999, node.port
62
63
  end
63
64
 
64
- def test_configure_tcp_heartbeat
65
- d = create_driver(CONFIG + "\nheartbeat_type tcp")
66
- assert_equal :tcp, d.instance.heartbeat_type
65
+ def test_configure_udp_heartbeat
66
+ d = create_driver(CONFIG + "\nheartbeat_type udp")
67
+ assert_equal :udp, d.instance.heartbeat_type
67
68
  end
68
69
 
69
70
  def test_configure_none_heartbeat
@@ -119,6 +120,75 @@ class ForwardOutputTest < Test::Unit::TestCase
119
120
  assert_equal 2, d.instance.ack_response_timeout
120
121
  end
121
122
 
123
+ def test_send_with_time_as_integer
124
+ target_input_driver = create_target_input_driver
125
+
126
+ d = create_driver(CONFIG + %[flush_interval 1s])
127
+
128
+ time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
129
+
130
+ records = [
131
+ {"a" => 1},
132
+ {"a" => 2}
133
+ ]
134
+ d.register_run_post_condition do
135
+ d.instance.responses.length == 1
136
+ end
137
+
138
+ target_input_driver.run do
139
+ d.run do
140
+ records.each do |record|
141
+ d.emit record, time
142
+ end
143
+ end
144
+ end
145
+
146
+ emits = target_input_driver.emits
147
+ assert_equal ['test', time, records[0]], emits[0]
148
+ assert_equal ['test', time, records[1]], emits[1]
149
+ assert(emits[0][1].is_a?(Integer))
150
+ assert(emits[1][1].is_a?(Integer))
151
+
152
+ assert_equal [nil], d.instance.responses # not attempt to receive responses, so nil is returned
153
+ assert_empty d.instance.exceptions
154
+ end
155
+
156
+ def test_send_without_time_as_integer
157
+ target_input_driver = create_target_input_driver
158
+
159
+ d = create_driver(CONFIG + %[
160
+ flush_interval 1s
161
+ time_as_integer false
162
+ ])
163
+
164
+ time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
165
+
166
+ records = [
167
+ {"a" => 1},
168
+ {"a" => 2}
169
+ ]
170
+ d.register_run_post_condition do
171
+ d.instance.responses.length == 1
172
+ end
173
+
174
+ target_input_driver.run do
175
+ d.run do
176
+ records.each do |record|
177
+ d.emit record, time
178
+ end
179
+ end
180
+ end
181
+
182
+ emits = target_input_driver.emits
183
+ assert_equal ['test', time, records[0]], emits[0]
184
+ assert_equal ['test', time, records[1]], emits[1]
185
+ assert_equal_event_time(time, emits[0][1])
186
+ assert_equal_event_time(time, emits[1][1])
187
+
188
+ assert_equal [nil], d.instance.responses # not attempt to receive responses, so nil is returned
189
+ assert_empty d.instance.exceptions
190
+ end
191
+
122
192
  def test_send_to_a_node_supporting_responses
123
193
  target_input_driver = create_target_input_driver(true)
124
194
 
@@ -305,6 +375,7 @@ class ForwardOutputTest < Test::Unit::TestCase
305
375
  def create_target_input_driver(do_respond=false, disconnect=false, conf=TARGET_CONFIG)
306
376
  require 'fluent/plugin/in_forward'
307
377
 
378
+ # TODO: Support actual TCP heartbeat test
308
379
  DummyEngineDriver.new(Fluent::ForwardInput) {
309
380
  handler_class = Class.new(Fluent::ForwardInput::Handler) { |klass|
310
381
  attr_reader :chunk_counter # for checking if received data is successfully deserialized
@@ -314,12 +385,14 @@ class ForwardOutputTest < Test::Unit::TestCase
314
385
  @log = log
315
386
  @chunk_counter = 0
316
387
  @on_message = on_message
388
+ @source = nil
317
389
  end
318
390
 
319
391
  if do_respond
320
392
  def write(data)
321
393
  @sock.write data
322
- rescue => e
394
+ rescue
395
+ @sock.close_write
323
396
  @sock.close
324
397
  end
325
398
  else
@@ -338,7 +411,7 @@ class ForwardOutputTest < Test::Unit::TestCase
338
411
 
339
412
  define_method(:start) do
340
413
  @thread = Thread.new do
341
- Socket.tcp_server_loop(@host, @port) do |sock, client_addrinfo|
414
+ Socket.tcp_server_loop(@bind, @port) do |sock, client_addrinfo|
342
415
  begin
343
416
  handler = handler_class.new(sock, @log, method(:on_message))
344
417
  loop do
@@ -416,6 +489,10 @@ class ForwardOutputTest < Test::Unit::TestCase
416
489
  @emit_streams ||= []
417
490
  end
418
491
 
492
+ def clear!
493
+ @emit_streams = []
494
+ end
495
+
419
496
  def emit_stream(tag, es)
420
497
  @emit_streams << [tag, es.to_a]
421
498
  end
@@ -1,5 +1,6 @@
1
1
  require_relative '../helper'
2
2
  require 'fluent/test'
3
+ require 'fluent/plugin/out_roundrobin'
3
4
 
4
5
  class RoundRobinOutputTest < Test::Unit::TestCase
5
6
  class << self
@@ -1,5 +1,6 @@
1
1
  require_relative '../helper'
2
- require 'fluent/test'
2
+ require 'fluent/test/driver/output'
3
+ require 'fluent/plugin/out_stdout'
3
4
 
4
5
  class StdoutOutputTest < Test::Unit::TestCase
5
6
  def setup
@@ -10,7 +11,7 @@ class StdoutOutputTest < Test::Unit::TestCase
10
11
  ]
11
12
 
12
13
  def create_driver(conf = CONFIG)
13
- Fluent::Test::OutputTestDriver.new(Fluent::StdoutOutput).configure(conf)
14
+ Fluent::Test::Driver::Output.new(Fluent::Plugin::StdoutOutput).configure(conf)
14
15
  end
15
16
 
16
17
  def test_configure
@@ -33,28 +34,36 @@ class StdoutOutputTest < Test::Unit::TestCase
33
34
  data('oj' => 'oj', 'yajl' => 'yajl')
34
35
  def test_emit_json(data)
35
36
  d = create_driver(CONFIG + "\noutput_type json\njson_parser #{data}")
36
- time = Time.now
37
- out = capture_log { d.emit({'test' => 'test'}, time) }
38
- assert_equal "#{time.localtime} test: {\"test\":\"test\"}\n", out
37
+ time = event_time()
38
+ out = capture_log do
39
+ d.run(default_tag: 'test') do
40
+ d.feed(time, {'test' => 'test'})
41
+ end
42
+ end
43
+ assert_equal "#{Time.at(time).localtime} test: {\"test\":\"test\"}\n", out
39
44
 
40
45
  if data == 'yajl'
41
46
  # NOTE: Float::NAN is not jsonable
42
- assert_raise(Yajl::EncodeError) { d.emit({'test' => Float::NAN}, time) }
47
+ assert_raise(Yajl::EncodeError) { d.feed('test', time, {'test' => Float::NAN}) }
43
48
  else
44
- out = capture_log { d.emit({'test' => Float::NAN}, time) }
45
- assert_equal "#{time.localtime} test: {\"test\":NaN}\n", out
49
+ out = capture_log { d.feed('test', time, {'test' => Float::NAN}) }
50
+ assert_equal "#{Time.at(time).localtime} test: {\"test\":NaN}\n", out
46
51
  end
47
52
  end
48
53
 
49
54
  def test_emit_hash
50
55
  d = create_driver(CONFIG + "\noutput_type hash")
51
- time = Time.now
52
- out = capture_log { d.emit({'test' => 'test'}, time) }
53
- assert_equal "#{time.localtime} test: {\"test\"=>\"test\"}\n", out
56
+ time = event_time()
57
+ out = capture_log do
58
+ d.run(default_tag: 'test') do
59
+ d.feed(time, {'test' => 'test'})
60
+ end
61
+ end
62
+ assert_equal "#{Time.at(time).localtime} test: {\"test\"=>\"test\"}\n", out
54
63
 
55
64
  # NOTE: Float::NAN is not jsonable, but hash string can output it.
56
- out = capture_log { d.emit({'test' => Float::NAN}, time) }
57
- assert_equal "#{time.localtime} test: {\"test\"=>NaN}\n", out
65
+ out = capture_log { d.feed('test', time, {'test' => Float::NAN}) }
66
+ assert_equal "#{Time.at(time).localtime} test: {\"test\"=>NaN}\n", out
58
67
  end
59
68
 
60
69
  private
@@ -1,5 +1,6 @@
1
1
  require_relative '../helper'
2
2
  require 'fluent/test'
3
+ require 'fluent/plugin/out_stream'
3
4
 
4
5
  module StreamOutputTest
5
6
  def setup
@@ -22,6 +23,23 @@ module StreamOutputTest
22
23
  assert_equal(expect, result)
23
24
  end
24
25
 
26
+ def test_write_event_time
27
+ d = create_driver
28
+
29
+ time = Fluent::EventTime.parse("2011-01-02 13:14:15 UTC")
30
+ d.emit({"a"=>1}, time)
31
+ d.emit({"a"=>2}, time)
32
+
33
+ expect = ["test",
34
+ Fluent::Engine.msgpack_factory.packer.write([time,{"a"=>1}]).to_s +
35
+ Fluent::Engine.msgpack_factory.packer.write([time,{"a"=>2}]).to_s
36
+ ]
37
+ expect = Fluent::Engine.msgpack_factory.packer.write(expect).to_s
38
+
39
+ result = d.run
40
+ assert_equal(expect, result)
41
+ end
42
+
25
43
  def create_driver(klass, conf)
26
44
  Fluent::Test::BufferedOutputTestDriver.new(klass) do
27
45
  def write(chunk)
@@ -0,0 +1,515 @@
1
+ require_relative '../helper'
2
+ require 'fluent/plugin/output'
3
+ require 'fluent/plugin/buffer'
4
+ require 'fluent/event'
5
+
6
+ require 'json'
7
+ require 'time'
8
+ require 'timeout'
9
+
10
+ module FluentPluginOutputTest
11
+ class DummyBareOutput < Fluent::Plugin::Output
12
+ def register(name, &block)
13
+ instance_variable_set("@#{name}", block)
14
+ end
15
+ end
16
+ class DummySyncOutput < DummyBareOutput
17
+ def initialize
18
+ super
19
+ @process = nil
20
+ end
21
+ def process(tag, es)
22
+ @process ? @process.call(tag, es) : nil
23
+ end
24
+ end
25
+ class DummyAsyncOutput < DummyBareOutput
26
+ def initialize
27
+ super
28
+ @format = nil
29
+ @write = nil
30
+ end
31
+ def format(tag, time, record)
32
+ @format ? @format.call(tag, time, record) : [tag, time, record].to_json
33
+ end
34
+ def write(chunk)
35
+ @write ? @write.call(chunk) : nil
36
+ end
37
+ end
38
+ class DummyAsyncStandardOutput < DummyBareOutput
39
+ def initialize
40
+ super
41
+ @write = nil
42
+ end
43
+ def write(chunk)
44
+ @write ? @write.call(chunk) : nil
45
+ end
46
+ end
47
+ class DummyDelayedOutput < DummyBareOutput
48
+ def initialize
49
+ super
50
+ @format = nil
51
+ @try_write = nil
52
+ end
53
+ def format(tag, time, record)
54
+ @format ? @format.call(tag, time, record) : [tag, time, record].to_json
55
+ end
56
+ def try_write(chunk)
57
+ @try_write ? @try_write.call(chunk) : nil
58
+ end
59
+ end
60
+ class DummyDelayedStandardOutput < DummyBareOutput
61
+ def initialize
62
+ super
63
+ @try_write = nil
64
+ end
65
+ def try_write(chunk)
66
+ @try_write ? @try_write.call(chunk) : nil
67
+ end
68
+ end
69
+ class DummyFullFeatureOutput < DummyBareOutput
70
+ def initialize
71
+ super
72
+ @prefer_buffered_processing = nil
73
+ @prefer_delayed_commit = nil
74
+ @process = nil
75
+ @format = nil
76
+ @write = nil
77
+ @try_write = nil
78
+ end
79
+ def prefer_buffered_processing
80
+ @prefer_buffered_processing ? @prefer_buffered_processing.call : false
81
+ end
82
+ def prefer_delayed_commit
83
+ @prefer_delayed_commit ? @prefer_delayed_commit.call : false
84
+ end
85
+ def process(tag, es)
86
+ @process ? @process.call(tag, es) : nil
87
+ end
88
+ def format(tag, time, record)
89
+ @format ? @format.call(tag, time, record) : [tag, time, record].to_json
90
+ end
91
+ def write(chunk)
92
+ @write ? @write.call(chunk) : nil
93
+ end
94
+ def try_write(chunk)
95
+ @try_write ? @try_write.call(chunk) : nil
96
+ end
97
+ end
98
+ end
99
+
100
+ class OutputTest < Test::Unit::TestCase
101
+ def create_output(type=:full)
102
+ case type
103
+ when :bare then FluentPluginOutputTest::DummyBareOutput.new
104
+ when :sync then FluentPluginOutputTest::DummySyncOutput.new
105
+ when :buffered then FluentPluginOutputTest::DummyAsyncOutput.new
106
+ when :standard then FluentPluginOutputTest::DummyAsyncStandardOutput.new
107
+ when :delayed then FluentPluginOutputTest::DummyDelayedOutput.new
108
+ when :sdelayed then FluentPluginOutputTest::DummyDelayedStandardOutput.new
109
+ when :full then FluentPluginOutputTest::DummyFullFeatureOutput.new
110
+ else
111
+ raise ArgumentError, "unknown type: #{type}"
112
+ end
113
+ end
114
+ def create_metadata(timekey: nil, tag: nil, variables: nil)
115
+ Fluent::Plugin::Buffer::Metadata.new(timekey, tag, variables)
116
+ end
117
+ def waiting(seconds)
118
+ begin
119
+ Timeout.timeout(seconds) do
120
+ yield
121
+ end
122
+ rescue Timeout::Error
123
+ STDERR.print(*@i.log.out.logs)
124
+ raise
125
+ end
126
+ end
127
+
128
+ sub_test_case 'basic output feature' do
129
+ setup do
130
+ @i = create_output(:full)
131
+ end
132
+
133
+ test '#implement? can return features for plugin instances' do
134
+ i1 = FluentPluginOutputTest::DummyBareOutput.new
135
+ assert !i1.implement?(:synchronous)
136
+ assert !i1.implement?(:buffered)
137
+ assert !i1.implement?(:delayed_commit)
138
+ assert !i1.implement?(:custom_format)
139
+
140
+ i2 = FluentPluginOutputTest::DummySyncOutput.new
141
+ assert i2.implement?(:synchronous)
142
+ assert !i2.implement?(:buffered)
143
+ assert !i2.implement?(:delayed_commit)
144
+ assert !i2.implement?(:custom_format)
145
+
146
+ i3 = FluentPluginOutputTest::DummyAsyncOutput.new
147
+ assert !i3.implement?(:synchronous)
148
+ assert i3.implement?(:buffered)
149
+ assert !i3.implement?(:delayed_commit)
150
+ assert i3.implement?(:custom_format)
151
+
152
+ i4 = FluentPluginOutputTest::DummyAsyncStandardOutput.new
153
+ assert !i4.implement?(:synchronous)
154
+ assert i4.implement?(:buffered)
155
+ assert !i4.implement?(:delayed_commit)
156
+ assert !i4.implement?(:custom_format)
157
+
158
+ i5 = FluentPluginOutputTest::DummyDelayedOutput.new
159
+ assert !i5.implement?(:synchronous)
160
+ assert !i5.implement?(:buffered)
161
+ assert i5.implement?(:delayed_commit)
162
+ assert i5.implement?(:custom_format)
163
+
164
+ i6 = FluentPluginOutputTest::DummyDelayedStandardOutput.new
165
+ assert !i6.implement?(:synchronous)
166
+ assert !i6.implement?(:buffered)
167
+ assert i6.implement?(:delayed_commit)
168
+ assert !i6.implement?(:custom_format)
169
+
170
+ i6 = FluentPluginOutputTest::DummyFullFeatureOutput.new
171
+ assert i6.implement?(:synchronous)
172
+ assert i6.implement?(:buffered)
173
+ assert i6.implement?(:delayed_commit)
174
+ assert i6.implement?(:custom_format)
175
+ end
176
+
177
+ test 'plugin lifecycle for configure/start/stop/before_shutdown/shutdown/after_shutdown/close/terminate' do
178
+ assert !@i.configured?
179
+ @i.configure(config_element())
180
+ assert @i.configured?
181
+ assert !@i.started?
182
+ @i.start
183
+ assert @i.started?
184
+ assert !@i.stopped?
185
+ @i.stop
186
+ assert @i.stopped?
187
+ assert !@i.before_shutdown?
188
+ @i.before_shutdown
189
+ assert @i.before_shutdown?
190
+ assert !@i.shutdown?
191
+ @i.shutdown
192
+ assert @i.shutdown?
193
+ assert !@i.after_shutdown?
194
+ @i.after_shutdown
195
+ assert @i.after_shutdown?
196
+ assert !@i.closed?
197
+ @i.close
198
+ assert @i.closed?
199
+ assert !@i.terminated?
200
+ @i.terminate
201
+ assert @i.terminated?
202
+ end
203
+
204
+ test '#extract_placeholders does nothing if chunk key is not specified' do
205
+ @i.configure(config_element('ROOT', '', {}, [config_element('buffer', '')]))
206
+ assert !@i.chunk_key_time
207
+ assert !@i.chunk_key_tag
208
+ assert_equal [], @i.chunk_keys
209
+ tmpl = "/mypath/%Y/%m/%d/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
210
+ t = event_time('2016-04-11 20:30:00 +0900')
211
+ v = {key1: "value1", key2: "value2"}
212
+ m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
213
+ assert_equal tmpl, @i.extract_placeholders(tmpl, m)
214
+ end
215
+
216
+ test '#extract_placeholders can extract time if time key and range are configured' do
217
+ @i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'time', {'timekey' => 60*30, 'timekey_zone' => "+0900"})]))
218
+ assert @i.chunk_key_time
219
+ assert !@i.chunk_key_tag
220
+ assert_equal [], @i.chunk_keys
221
+ tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
222
+ t = event_time('2016-04-11 20:30:00 +0900')
223
+ v = {key1: "value1", key2: "value2"}
224
+ m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
225
+ assert_equal "/mypath/2016/04/11/20-30/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail", @i.extract_placeholders(tmpl, m)
226
+ end
227
+
228
+ test '#extract_placeholders can extract tag and parts of tag if tag is configured' do
229
+ @i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'tag', {})]))
230
+ assert !@i.chunk_key_time
231
+ assert @i.chunk_key_tag
232
+ assert_equal [], @i.chunk_keys
233
+ tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
234
+ t = event_time('2016-04-11 20:30:00 +0900')
235
+ v = {key1: "value1", key2: "value2"}
236
+ m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
237
+ assert_equal "/mypath/%Y/%m/%d/%H-%M/fluentd.test.output/test/output/${key1}/${key2}/tail", @i.extract_placeholders(tmpl, m)
238
+ end
239
+
240
+ test '#extract_placeholders can extract variables if variables are configured' do
241
+ @i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'key1,key2', {})]))
242
+ assert !@i.chunk_key_time
243
+ assert !@i.chunk_key_tag
244
+ assert_equal ['key1','key2'], @i.chunk_keys
245
+ tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
246
+ t = event_time('2016-04-11 20:30:00 +0900')
247
+ v = {key1: "value1", key2: "value2"}
248
+ m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
249
+ assert_equal "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/value1/value2/tail", @i.extract_placeholders(tmpl, m)
250
+ end
251
+
252
+ test '#extract_placeholders can extract all chunk keys if configured' do
253
+ @i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'time,tag,key1,key2', {'timekey' => 60*30, 'timekey_zone' => "+0900"})]))
254
+ assert @i.chunk_key_time
255
+ assert @i.chunk_key_tag
256
+ assert_equal ['key1','key2'], @i.chunk_keys
257
+ tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[1]}/${tag[2]}/${key1}/${key2}/tail"
258
+ t = event_time('2016-04-11 20:30:00 +0900')
259
+ v = {key1: "value1", key2: "value2"}
260
+ m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
261
+ assert_equal "/mypath/2016/04/11/20-30/fluentd.test.output/test/output/value1/value2/tail", @i.extract_placeholders(tmpl, m)
262
+ end
263
+
264
+ test '#extract_placeholders removes out-of-range tag part and unknown variable placeholders' do
265
+ @i.configure(config_element('ROOT', '', {}, [config_element('buffer', 'time,tag,key1,key2', {'timekey' => 60*30, 'timekey_zone' => "+0900"})]))
266
+ assert @i.chunk_key_time
267
+ assert @i.chunk_key_tag
268
+ assert_equal ['key1','key2'], @i.chunk_keys
269
+ tmpl = "/mypath/%Y/%m/%d/%H-%M/${tag}/${tag[3]}/${tag[4]}/${key3}/${key4}/tail"
270
+ t = event_time('2016-04-11 20:30:00 +0900')
271
+ v = {key1: "value1", key2: "value2"}
272
+ m = create_metadata(timekey: t, tag: 'fluentd.test.output', variables: v)
273
+ assert_equal "/mypath/2016/04/11/20-30/fluentd.test.output/////tail", @i.extract_placeholders(tmpl, m)
274
+ end
275
+
276
+ test '#metadata returns object which contains tag/timekey/variables from records as specified in configuration' do
277
+ tag = 'test.output'
278
+ time = event_time('2016-04-12 15:31:23 -0700')
279
+ timekey = event_time('2016-04-12 15:00:00 -0700')
280
+ record = {"key1" => "value1", "num1" => 1, "message" => "my message"}
281
+
282
+ i1 = create_output(:buffered)
283
+ i1.configure(config_element('ROOT','',{},[config_element('buffer', '')]))
284
+ assert_equal create_metadata(), i1.metadata(tag, time, record)
285
+
286
+ i2 = create_output(:buffered)
287
+ i2.configure(config_element('ROOT','',{},[config_element('buffer', 'tag')]))
288
+ assert_equal create_metadata(tag: tag), i2.metadata(tag, time, record)
289
+
290
+ i3 = create_output(:buffered)
291
+ i3.configure(config_element('ROOT','',{},[config_element('buffer', 'time', {"timekey" => 3600, "timekey_zone" => "-0700"})]))
292
+ assert_equal create_metadata(timekey: timekey), i3.metadata(tag, time, record)
293
+
294
+ i4 = create_output(:buffered)
295
+ i4.configure(config_element('ROOT','',{},[config_element('buffer', 'key1', {})]))
296
+ assert_equal create_metadata(variables: {key1: "value1"}), i4.metadata(tag, time, record)
297
+
298
+ i5 = create_output(:buffered)
299
+ i5.configure(config_element('ROOT','',{},[config_element('buffer', 'key1,num1', {})]))
300
+ assert_equal create_metadata(variables: {key1: "value1", num1: 1}), i5.metadata(tag, time, record)
301
+
302
+ i6 = create_output(:buffered)
303
+ i6.configure(config_element('ROOT','',{},[config_element('buffer', 'tag,time', {"timekey" => 3600, "timekey_zone" => "-0700"})]))
304
+ assert_equal create_metadata(timekey: timekey, tag: tag), i6.metadata(tag, time, record)
305
+
306
+ i7 = create_output(:buffered)
307
+ i7.configure(config_element('ROOT','',{},[config_element('buffer', 'tag,num1', {"timekey" => 3600, "timekey_zone" => "-0700"})]))
308
+ assert_equal create_metadata(tag: tag, variables: {num1: 1}), i7.metadata(tag, time, record)
309
+
310
+ i8 = create_output(:buffered)
311
+ i8.configure(config_element('ROOT','',{},[config_element('buffer', 'time,tag,key1', {"timekey" => 3600, "timekey_zone" => "-0700"})]))
312
+ assert_equal create_metadata(timekey: timekey, tag: tag, variables: {key1: "value1"}), i8.metadata(tag, time, record)
313
+ end
314
+
315
+ test '#emit calls #process via #emit_sync for non-buffered output' do
316
+ i = create_output(:sync)
317
+ process_called = false
318
+ i.register(:process){|tag, es| process_called = true }
319
+ i.configure(config_element())
320
+ i.start
321
+
322
+ t = event_time()
323
+ i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
324
+
325
+ assert process_called
326
+
327
+ i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
328
+ end
329
+
330
+ test '#emit calls #format for buffered output' do
331
+ i = create_output(:buffered)
332
+ format_called_times = 0
333
+ i.register(:format){|tag, time, record| format_called_times += 1; '' }
334
+ i.configure(config_element())
335
+ i.start
336
+
337
+ t = event_time()
338
+ i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
339
+
340
+ assert_equal 2, format_called_times
341
+
342
+ i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
343
+ end
344
+
345
+ test '#prefer_buffered_processing (returns false) decides non-buffered without <buffer> section' do
346
+ i = create_output(:full)
347
+
348
+ process_called = false
349
+ format_called_times = 0
350
+ i.register(:process){|tag, es| process_called = true }
351
+ i.register(:format){|tag, time, record| format_called_times += 1; '' }
352
+
353
+ i.configure(config_element())
354
+ i.register(:prefer_buffered_processing){ false } # delayed decision is possible to change after (output's) configure
355
+ i.start
356
+
357
+ assert !i.prefer_buffered_processing
358
+
359
+ t = event_time()
360
+ i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
361
+
362
+ waiting(4){ Thread.pass until process_called }
363
+
364
+ assert process_called
365
+ assert_equal 0, format_called_times
366
+
367
+ i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
368
+ end
369
+
370
+ test '#prefer_buffered_processing (returns true) decides buffered without <buffer> section' do
371
+ i = create_output(:full)
372
+
373
+ process_called = false
374
+ format_called_times = 0
375
+ i.register(:process){|tag, es| process_called = true }
376
+ i.register(:format){|tag, time, record| format_called_times += 1; '' }
377
+
378
+ i.configure(config_element())
379
+ i.register(:prefer_buffered_processing){ true } # delayed decision is possible to change after (output's) configure
380
+ i.start
381
+
382
+ assert i.prefer_buffered_processing
383
+
384
+ t = event_time()
385
+ i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
386
+
387
+ assert !process_called
388
+ assert_equal 2, format_called_times
389
+
390
+ i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
391
+ end
392
+
393
+ test 'output plugin will call #write for normal buffered plugin to flush buffer chunks' do
394
+ i = create_output(:buffered)
395
+ write_called = false
396
+ i.register(:write){ |chunk| write_called = true }
397
+
398
+ i.configure(config_element('ROOT', '', {}, [config_element('buffer', '', {"flush_mode" => "immediate"})]))
399
+ i.start
400
+
401
+ t = event_time()
402
+ i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
403
+ i.force_flush
404
+
405
+ waiting(4){ Thread.pass until write_called }
406
+
407
+ assert write_called
408
+
409
+ i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
410
+ end
411
+
412
+ test 'output plugin will call #try_write for plugin supports delayed commit only to flush buffer chunks' do
413
+ i = create_output(:delayed)
414
+ try_write_called = false
415
+ i.register(:try_write){|chunk| try_write_called = true; commit_write(chunk.unique_id) }
416
+
417
+ i.configure(config_element('ROOT', '', {}, [config_element('buffer', '', {"flush_mode" => "immediate"})]))
418
+ i.start
419
+
420
+ t = event_time()
421
+ i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
422
+ i.force_flush
423
+
424
+ waiting(4){ Thread.pass until try_write_called }
425
+
426
+ assert try_write_called
427
+
428
+ i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
429
+ end
430
+
431
+ test '#prefer_delayed_commit (returns false) decides delayed commit is disabled if both are implemented' do
432
+ i = create_output(:full)
433
+ write_called = false
434
+ try_write_called = false
435
+ i.register(:write){ |chunk| write_called = true }
436
+ i.register(:try_write){|chunk| try_write_called = true; commit_write(chunk.unique_id) }
437
+
438
+ i.configure(config_element('ROOT', '', {}, [config_element('buffer', '', {"flush_mode" => "immediate"})]))
439
+ i.register(:prefer_delayed_commit){ false } # delayed decision is possible to change after (output's) configure
440
+ i.start
441
+
442
+ assert !i.prefer_delayed_commit
443
+
444
+ t = event_time()
445
+ i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
446
+ i.force_flush
447
+
448
+ waiting(4){ Thread.pass until write_called || try_write_called }
449
+
450
+ assert write_called
451
+ assert !try_write_called
452
+
453
+ i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
454
+ end
455
+
456
+ test '#prefer_delayed_commit (returns true) decides delayed commit is enabled if both are implemented' do
457
+ i = create_output(:full)
458
+ write_called = false
459
+ try_write_called = false
460
+ i.register(:write){ |chunk| write_called = true }
461
+ i.register(:try_write){|chunk| try_write_called = true; commit_write(chunk.unique_id) }
462
+
463
+ i.configure(config_element('ROOT', '', {}, [config_element('buffer', '', {"flush_mode" => "immediate"})]))
464
+ i.register(:prefer_delayed_commit){ true } # delayed decision is possible to change after (output's) configure
465
+ i.start
466
+
467
+ assert i.prefer_delayed_commit
468
+
469
+ t = event_time()
470
+ i.emit_events('tag', Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ]))
471
+ i.force_flush
472
+
473
+ waiting(4){ Thread.pass until write_called || try_write_called }
474
+
475
+ assert !write_called
476
+ assert try_write_called
477
+
478
+ i.stop; i.before_shutdown; i.shutdown; i.after_shutdown; i.close; i.terminate
479
+ end
480
+ end
481
+
482
+ sub_test_case 'sync output feature' do
483
+ setup do
484
+ @i = create_output(:sync)
485
+ end
486
+
487
+ test 'raises configuration error if <buffer> section is specified' do
488
+ assert_raise Fluent::ConfigError do
489
+ @i.configure(config_element('ROOT','',{},[config_element('buffer', '')]))
490
+ end
491
+ end
492
+
493
+ test 'raises configuration error if <secondary> section is specified' do
494
+ assert_raise Fluent::ConfigError do
495
+ @i.configure(config_element('ROOT','',{},[config_element('secondary','')]))
496
+ end
497
+ end
498
+
499
+ test '#process is called for each event streams' do
500
+ ary = []
501
+ @i.register(:process){|tag, es| ary << [tag, es] }
502
+ @i.configure(config_element())
503
+ @i.start
504
+
505
+ t = event_time()
506
+ es = Fluent::ArrayEventStream.new([ [t, {"key" => "value1"}], [t, {"key" => "value2"}] ])
507
+ 5.times do
508
+ @i.emit_events('tag', es)
509
+ end
510
+ assert_equal 5, ary.size
511
+
512
+ @i.stop; @i.before_shutdown; @i.shutdown; @i.after_shutdown; @i.close; @i.terminate
513
+ end
514
+ end
515
+ end