fluentd 0.12.40 → 1.6.2

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 (428) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  4. data/.github/ISSUE_TEMPLATE.md +17 -0
  5. data/.github/PULL_REQUEST_TEMPLATE.md +13 -0
  6. data/.gitignore +5 -0
  7. data/.gitlab/cicd-template.yaml +10 -0
  8. data/.gitlab-ci.yml +147 -0
  9. data/.travis.yml +56 -20
  10. data/ADOPTERS.md +5 -0
  11. data/CHANGELOG.md +1369 -0
  12. data/CONTRIBUTING.md +16 -5
  13. data/GOVERNANCE.md +55 -0
  14. data/Gemfile +5 -0
  15. data/GithubWorkflow.md +78 -0
  16. data/LICENSE +202 -0
  17. data/MAINTAINERS.md +7 -0
  18. data/README.md +23 -11
  19. data/Rakefile +48 -2
  20. data/Vagrantfile +17 -0
  21. data/appveyor.yml +37 -0
  22. data/bin/fluent-binlog-reader +7 -0
  23. data/bin/fluent-ca-generate +6 -0
  24. data/bin/fluent-plugin-config-format +5 -0
  25. data/bin/fluent-plugin-generate +5 -0
  26. data/bin/fluentd +3 -0
  27. data/code-of-conduct.md +3 -0
  28. data/example/copy_roundrobin.conf +39 -0
  29. data/example/counter.conf +18 -0
  30. data/example/in_dummy_blocks.conf +17 -0
  31. data/example/in_dummy_with_compression.conf +23 -0
  32. data/example/in_forward.conf +7 -0
  33. data/example/in_forward_client.conf +37 -0
  34. data/example/in_forward_shared_key.conf +15 -0
  35. data/example/in_forward_tls.conf +14 -0
  36. data/example/in_forward_users.conf +24 -0
  37. data/example/in_forward_workers.conf +21 -0
  38. data/example/in_http.conf +3 -1
  39. data/example/in_out_forward.conf +17 -0
  40. data/example/logevents.conf +25 -0
  41. data/example/multi_filters.conf +61 -0
  42. data/example/out_exec_filter.conf +42 -0
  43. data/example/out_forward.conf +13 -13
  44. data/example/out_forward_buf_file.conf +23 -0
  45. data/example/out_forward_client.conf +109 -0
  46. data/example/out_forward_heartbeat_none.conf +16 -0
  47. data/example/out_forward_shared_key.conf +36 -0
  48. data/example/out_forward_tls.conf +18 -0
  49. data/example/out_forward_users.conf +65 -0
  50. data/example/out_null.conf +36 -0
  51. data/example/secondary_file.conf +42 -0
  52. data/example/suppress_config_dump.conf +7 -0
  53. data/example/worker_section.conf +36 -0
  54. data/fluent.conf +29 -0
  55. data/fluentd.gemspec +21 -11
  56. data/lib/fluent/agent.rb +67 -90
  57. data/lib/fluent/clock.rb +62 -0
  58. data/lib/fluent/command/binlog_reader.rb +244 -0
  59. data/lib/fluent/command/ca_generate.rb +181 -0
  60. data/lib/fluent/command/cat.rb +42 -18
  61. data/lib/fluent/command/debug.rb +12 -10
  62. data/lib/fluent/command/fluentd.rb +153 -5
  63. data/lib/fluent/command/plugin_config_formatter.rb +292 -0
  64. data/lib/fluent/command/plugin_generator.rb +324 -0
  65. data/lib/fluent/compat/call_super_mixin.rb +67 -0
  66. data/lib/fluent/compat/detach_process_mixin.rb +33 -0
  67. data/lib/fluent/compat/exec_util.rb +129 -0
  68. data/lib/fluent/compat/file_util.rb +54 -0
  69. data/lib/fluent/compat/filter.rb +68 -0
  70. data/lib/fluent/compat/formatter.rb +111 -0
  71. data/lib/fluent/compat/formatter_utils.rb +85 -0
  72. data/lib/fluent/compat/handle_tag_and_time_mixin.rb +62 -0
  73. data/lib/fluent/compat/handle_tag_name_mixin.rb +53 -0
  74. data/lib/fluent/compat/input.rb +49 -0
  75. data/lib/fluent/compat/output.rb +718 -0
  76. data/lib/fluent/compat/output_chain.rb +60 -0
  77. data/lib/fluent/compat/parser.rb +310 -0
  78. data/lib/fluent/compat/parser_utils.rb +40 -0
  79. data/lib/fluent/compat/propagate_default.rb +62 -0
  80. data/lib/fluent/compat/record_filter_mixin.rb +34 -0
  81. data/lib/fluent/compat/set_tag_key_mixin.rb +50 -0
  82. data/lib/fluent/compat/set_time_key_mixin.rb +69 -0
  83. data/lib/fluent/compat/socket_util.rb +165 -0
  84. data/lib/fluent/compat/string_util.rb +34 -0
  85. data/lib/fluent/compat/structured_format_mixin.rb +26 -0
  86. data/lib/fluent/compat/type_converter.rb +90 -0
  87. data/lib/fluent/config/configure_proxy.rb +210 -62
  88. data/lib/fluent/config/dsl.rb +12 -5
  89. data/lib/fluent/config/element.rb +107 -9
  90. data/lib/fluent/config/literal_parser.rb +9 -3
  91. data/lib/fluent/config/parser.rb +4 -4
  92. data/lib/fluent/config/section.rb +51 -14
  93. data/lib/fluent/config/types.rb +28 -13
  94. data/lib/fluent/config/v1_parser.rb +3 -5
  95. data/lib/fluent/config.rb +23 -20
  96. data/lib/fluent/configurable.rb +79 -21
  97. data/lib/fluent/counter/base_socket.rb +46 -0
  98. data/lib/fluent/counter/client.rb +297 -0
  99. data/lib/fluent/counter/error.rb +86 -0
  100. data/lib/fluent/counter/mutex_hash.rb +163 -0
  101. data/lib/fluent/counter/server.rb +273 -0
  102. data/lib/fluent/counter/store.rb +205 -0
  103. data/lib/fluent/counter/validator.rb +145 -0
  104. data/lib/fluent/counter.rb +23 -0
  105. data/lib/fluent/daemon.rb +15 -0
  106. data/lib/fluent/engine.rb +102 -65
  107. data/lib/fluent/env.rb +7 -3
  108. data/lib/fluent/error.rb +30 -0
  109. data/lib/fluent/event.rb +197 -21
  110. data/lib/fluent/event_router.rb +93 -10
  111. data/lib/fluent/filter.rb +2 -50
  112. data/lib/fluent/formatter.rb +4 -293
  113. data/lib/fluent/input.rb +2 -32
  114. data/lib/fluent/label.rb +10 -2
  115. data/lib/fluent/load.rb +3 -3
  116. data/lib/fluent/log.rb +348 -81
  117. data/lib/fluent/match.rb +37 -36
  118. data/lib/fluent/mixin.rb +12 -176
  119. data/lib/fluent/msgpack_factory.rb +62 -0
  120. data/lib/fluent/output.rb +10 -612
  121. data/lib/fluent/output_chain.rb +23 -0
  122. data/lib/fluent/parser.rb +4 -800
  123. data/lib/fluent/plugin/bare_output.rb +63 -0
  124. data/lib/fluent/plugin/base.rb +192 -0
  125. data/lib/fluent/plugin/buf_file.rb +128 -174
  126. data/lib/fluent/plugin/buf_memory.rb +9 -92
  127. data/lib/fluent/plugin/buffer/chunk.rb +221 -0
  128. data/lib/fluent/plugin/buffer/file_chunk.rb +383 -0
  129. data/lib/fluent/plugin/buffer/memory_chunk.rb +90 -0
  130. data/lib/fluent/plugin/buffer.rb +779 -0
  131. data/lib/fluent/plugin/compressable.rb +92 -0
  132. data/lib/fluent/plugin/exec_util.rb +3 -108
  133. data/lib/fluent/plugin/file_util.rb +4 -34
  134. data/lib/fluent/plugin/file_wrapper.rb +120 -0
  135. data/lib/fluent/plugin/filter.rb +93 -0
  136. data/lib/fluent/plugin/filter_grep.rb +117 -34
  137. data/lib/fluent/plugin/filter_parser.rb +85 -62
  138. data/lib/fluent/plugin/filter_record_transformer.rb +27 -39
  139. data/lib/fluent/plugin/filter_stdout.rb +15 -12
  140. data/lib/fluent/plugin/formatter.rb +50 -0
  141. data/lib/fluent/plugin/formatter_csv.rb +52 -0
  142. data/lib/fluent/plugin/formatter_hash.rb +33 -0
  143. data/lib/fluent/plugin/formatter_json.rb +55 -0
  144. data/lib/fluent/plugin/formatter_ltsv.rb +42 -0
  145. data/lib/fluent/plugin/formatter_msgpack.rb +33 -0
  146. data/lib/fluent/plugin/formatter_out_file.rb +51 -0
  147. data/lib/fluent/plugin/formatter_single_value.rb +34 -0
  148. data/lib/fluent/plugin/formatter_stdout.rb +76 -0
  149. data/lib/fluent/plugin/formatter_tsv.rb +38 -0
  150. data/lib/fluent/plugin/in_debug_agent.rb +17 -6
  151. data/lib/fluent/plugin/in_dummy.rb +47 -20
  152. data/lib/fluent/plugin/in_exec.rb +55 -123
  153. data/lib/fluent/plugin/in_forward.rb +299 -216
  154. data/lib/fluent/plugin/in_gc_stat.rb +14 -36
  155. data/lib/fluent/plugin/in_http.rb +204 -91
  156. data/lib/fluent/plugin/in_monitor_agent.rb +186 -258
  157. data/lib/fluent/plugin/in_object_space.rb +13 -41
  158. data/lib/fluent/plugin/in_syslog.rb +112 -134
  159. data/lib/fluent/plugin/in_tail.rb +408 -745
  160. data/lib/fluent/plugin/in_tcp.rb +66 -9
  161. data/lib/fluent/plugin/in_udp.rb +60 -11
  162. data/lib/fluent/plugin/{in_stream.rb → in_unix.rb} +8 -4
  163. data/lib/fluent/plugin/input.rb +37 -0
  164. data/lib/fluent/plugin/multi_output.rb +158 -0
  165. data/lib/fluent/plugin/out_copy.rb +23 -35
  166. data/lib/fluent/plugin/out_exec.rb +67 -70
  167. data/lib/fluent/plugin/out_exec_filter.rb +204 -271
  168. data/lib/fluent/plugin/out_file.rb +267 -73
  169. data/lib/fluent/plugin/out_forward.rb +854 -325
  170. data/lib/fluent/plugin/out_null.rb +42 -9
  171. data/lib/fluent/plugin/out_relabel.rb +9 -5
  172. data/lib/fluent/plugin/out_roundrobin.rb +18 -37
  173. data/lib/fluent/plugin/out_secondary_file.rb +133 -0
  174. data/lib/fluent/plugin/out_stdout.rb +43 -10
  175. data/lib/fluent/plugin/out_stream.rb +7 -2
  176. data/lib/fluent/plugin/output.rb +1498 -0
  177. data/lib/fluent/plugin/owned_by_mixin.rb +42 -0
  178. data/lib/fluent/plugin/parser.rb +191 -0
  179. data/lib/fluent/plugin/parser_apache.rb +28 -0
  180. data/lib/fluent/plugin/parser_apache2.rb +88 -0
  181. data/lib/fluent/plugin/parser_apache_error.rb +26 -0
  182. data/lib/fluent/plugin/parser_csv.rb +39 -0
  183. data/lib/fluent/plugin/parser_json.rb +94 -0
  184. data/lib/fluent/plugin/parser_ltsv.rb +49 -0
  185. data/lib/fluent/plugin/parser_msgpack.rb +50 -0
  186. data/lib/fluent/plugin/parser_multiline.rb +106 -0
  187. data/lib/fluent/plugin/parser_nginx.rb +28 -0
  188. data/lib/fluent/plugin/parser_none.rb +36 -0
  189. data/lib/fluent/plugin/parser_regexp.rb +68 -0
  190. data/lib/fluent/plugin/parser_syslog.rb +142 -0
  191. data/lib/fluent/plugin/parser_tsv.rb +42 -0
  192. data/lib/fluent/plugin/socket_util.rb +3 -143
  193. data/lib/fluent/plugin/storage.rb +84 -0
  194. data/lib/fluent/plugin/storage_local.rb +164 -0
  195. data/lib/fluent/plugin/string_util.rb +3 -15
  196. data/lib/fluent/plugin.rb +122 -121
  197. data/lib/fluent/plugin_helper/cert_option.rb +178 -0
  198. data/lib/fluent/plugin_helper/child_process.rb +364 -0
  199. data/lib/fluent/plugin_helper/compat_parameters.rb +333 -0
  200. data/lib/fluent/plugin_helper/counter.rb +51 -0
  201. data/lib/fluent/plugin_helper/event_emitter.rb +93 -0
  202. data/lib/fluent/plugin_helper/event_loop.rb +170 -0
  203. data/lib/fluent/plugin_helper/extract.rb +104 -0
  204. data/lib/fluent/plugin_helper/formatter.rb +147 -0
  205. data/lib/fluent/plugin_helper/http_server/app.rb +79 -0
  206. data/lib/fluent/plugin_helper/http_server/compat/server.rb +81 -0
  207. data/lib/fluent/plugin_helper/http_server/compat/webrick_handler.rb +58 -0
  208. data/lib/fluent/plugin_helper/http_server/methods.rb +35 -0
  209. data/lib/fluent/plugin_helper/http_server/request.rb +42 -0
  210. data/lib/fluent/plugin_helper/http_server/router.rb +54 -0
  211. data/lib/fluent/plugin_helper/http_server/server.rb +87 -0
  212. data/lib/fluent/plugin_helper/http_server.rb +76 -0
  213. data/lib/fluent/plugin_helper/inject.rb +151 -0
  214. data/lib/fluent/plugin_helper/parser.rb +147 -0
  215. data/lib/fluent/plugin_helper/record_accessor.rb +210 -0
  216. data/lib/fluent/plugin_helper/retry_state.rb +205 -0
  217. data/lib/fluent/plugin_helper/server.rb +807 -0
  218. data/lib/fluent/plugin_helper/socket.rb +250 -0
  219. data/lib/fluent/plugin_helper/socket_option.rb +80 -0
  220. data/lib/fluent/plugin_helper/storage.rb +349 -0
  221. data/lib/fluent/plugin_helper/thread.rb +179 -0
  222. data/lib/fluent/plugin_helper/timer.rb +92 -0
  223. data/lib/fluent/plugin_helper.rb +73 -0
  224. data/lib/fluent/plugin_id.rb +80 -0
  225. data/lib/fluent/process.rb +3 -489
  226. data/lib/fluent/registry.rb +52 -10
  227. data/lib/fluent/root_agent.rb +204 -42
  228. data/lib/fluent/supervisor.rb +597 -359
  229. data/lib/fluent/system_config.rb +131 -42
  230. data/lib/fluent/test/base.rb +6 -54
  231. data/lib/fluent/test/driver/base.rb +224 -0
  232. data/lib/fluent/test/driver/base_owned.rb +70 -0
  233. data/lib/fluent/test/driver/base_owner.rb +135 -0
  234. data/lib/fluent/test/driver/event_feeder.rb +98 -0
  235. data/lib/fluent/test/driver/filter.rb +57 -0
  236. data/lib/fluent/test/driver/formatter.rb +30 -0
  237. data/lib/fluent/test/driver/input.rb +31 -0
  238. data/lib/fluent/test/driver/multi_output.rb +53 -0
  239. data/lib/fluent/test/driver/output.rb +102 -0
  240. data/lib/fluent/test/driver/parser.rb +30 -0
  241. data/lib/fluent/test/driver/test_event_router.rb +45 -0
  242. data/lib/fluent/test/filter_test.rb +0 -1
  243. data/lib/fluent/test/formatter_test.rb +4 -1
  244. data/lib/fluent/test/helpers.rb +58 -10
  245. data/lib/fluent/test/input_test.rb +27 -19
  246. data/lib/fluent/test/log.rb +79 -0
  247. data/lib/fluent/test/output_test.rb +28 -39
  248. data/lib/fluent/test/parser_test.rb +3 -1
  249. data/lib/fluent/test/startup_shutdown.rb +46 -0
  250. data/lib/fluent/test.rb +33 -1
  251. data/lib/fluent/time.rb +450 -1
  252. data/lib/fluent/timezone.rb +27 -3
  253. data/lib/fluent/{status.rb → unique_id.rb} +15 -24
  254. data/lib/fluent/version.rb +1 -1
  255. data/lib/fluent/winsvc.rb +85 -0
  256. data/templates/new_gem/Gemfile +3 -0
  257. data/templates/new_gem/README.md.erb +43 -0
  258. data/templates/new_gem/Rakefile +13 -0
  259. data/templates/new_gem/fluent-plugin.gemspec.erb +27 -0
  260. data/templates/new_gem/lib/fluent/plugin/filter.rb.erb +14 -0
  261. data/templates/new_gem/lib/fluent/plugin/formatter.rb.erb +14 -0
  262. data/templates/new_gem/lib/fluent/plugin/input.rb.erb +11 -0
  263. data/templates/new_gem/lib/fluent/plugin/output.rb.erb +11 -0
  264. data/templates/new_gem/lib/fluent/plugin/parser.rb.erb +15 -0
  265. data/templates/new_gem/test/helper.rb.erb +8 -0
  266. data/templates/new_gem/test/plugin/test_filter.rb.erb +18 -0
  267. data/templates/new_gem/test/plugin/test_formatter.rb.erb +18 -0
  268. data/templates/new_gem/test/plugin/test_input.rb.erb +18 -0
  269. data/templates/new_gem/test/plugin/test_output.rb.erb +18 -0
  270. data/templates/new_gem/test/plugin/test_parser.rb.erb +18 -0
  271. data/templates/plugin_config_formatter/param.md-compact.erb +25 -0
  272. data/templates/plugin_config_formatter/param.md.erb +34 -0
  273. data/templates/plugin_config_formatter/section.md.erb +12 -0
  274. data/test/command/test_binlog_reader.rb +346 -0
  275. data/test/command/test_ca_generate.rb +70 -0
  276. data/test/command/test_fluentd.rb +901 -0
  277. data/test/command/test_plugin_config_formatter.rb +276 -0
  278. data/test/command/test_plugin_generator.rb +92 -0
  279. data/test/compat/test_calls_super.rb +166 -0
  280. data/test/compat/test_parser.rb +92 -0
  281. data/test/config/test_config_parser.rb +126 -2
  282. data/test/config/test_configurable.rb +946 -187
  283. data/test/config/test_configure_proxy.rb +424 -74
  284. data/test/config/test_dsl.rb +11 -11
  285. data/test/config/test_element.rb +500 -0
  286. data/test/config/test_literal_parser.rb +8 -0
  287. data/test/config/test_plugin_configuration.rb +56 -0
  288. data/test/config/test_section.rb +79 -7
  289. data/test/config/test_system_config.rb +122 -35
  290. data/test/config/test_types.rb +38 -0
  291. data/test/counter/test_client.rb +559 -0
  292. data/test/counter/test_error.rb +44 -0
  293. data/test/counter/test_mutex_hash.rb +179 -0
  294. data/test/counter/test_server.rb +589 -0
  295. data/test/counter/test_store.rb +258 -0
  296. data/test/counter/test_validator.rb +137 -0
  297. data/test/helper.rb +89 -6
  298. data/test/helpers/fuzzy_assert.rb +89 -0
  299. data/test/plugin/test_bare_output.rb +118 -0
  300. data/test/plugin/test_base.rb +115 -0
  301. data/test/plugin/test_buf_file.rb +823 -460
  302. data/test/plugin/test_buf_memory.rb +32 -194
  303. data/test/plugin/test_buffer.rb +1233 -0
  304. data/test/plugin/test_buffer_chunk.rb +198 -0
  305. data/test/plugin/test_buffer_file_chunk.rb +844 -0
  306. data/test/plugin/test_buffer_memory_chunk.rb +338 -0
  307. data/test/plugin/test_compressable.rb +84 -0
  308. data/test/plugin/test_filter.rb +357 -0
  309. data/test/plugin/test_filter_grep.rb +540 -29
  310. data/test/plugin/test_filter_parser.rb +439 -452
  311. data/test/plugin/test_filter_record_transformer.rb +123 -166
  312. data/test/plugin/test_filter_stdout.rb +160 -72
  313. data/test/plugin/test_formatter_csv.rb +111 -0
  314. data/test/plugin/test_formatter_hash.rb +35 -0
  315. data/test/plugin/test_formatter_json.rb +51 -0
  316. data/test/plugin/test_formatter_ltsv.rb +62 -0
  317. data/test/plugin/test_formatter_msgpack.rb +28 -0
  318. data/test/plugin/test_formatter_out_file.rb +95 -0
  319. data/test/plugin/test_formatter_single_value.rb +38 -0
  320. data/test/plugin/test_formatter_tsv.rb +68 -0
  321. data/test/plugin/test_in_debug_agent.rb +24 -1
  322. data/test/plugin/test_in_dummy.rb +111 -18
  323. data/test/plugin/test_in_exec.rb +200 -113
  324. data/test/plugin/test_in_forward.rb +990 -387
  325. data/test/plugin/test_in_gc_stat.rb +10 -8
  326. data/test/plugin/test_in_http.rb +600 -224
  327. data/test/plugin/test_in_monitor_agent.rb +690 -0
  328. data/test/plugin/test_in_object_space.rb +24 -8
  329. data/test/plugin/test_in_syslog.rb +154 -215
  330. data/test/plugin/test_in_tail.rb +1006 -707
  331. data/test/plugin/test_in_tcp.rb +125 -48
  332. data/test/plugin/test_in_udp.rb +204 -63
  333. data/test/plugin/{test_in_stream.rb → test_in_unix.rb} +14 -13
  334. data/test/plugin/test_input.rb +126 -0
  335. data/test/plugin/test_metadata.rb +89 -0
  336. data/test/plugin/test_multi_output.rb +180 -0
  337. data/test/plugin/test_out_copy.rb +117 -112
  338. data/test/plugin/test_out_exec.rb +258 -53
  339. data/test/plugin/test_out_exec_filter.rb +538 -115
  340. data/test/plugin/test_out_file.rb +865 -178
  341. data/test/plugin/test_out_forward.rb +998 -210
  342. data/test/plugin/test_out_null.rb +105 -0
  343. data/test/plugin/test_out_relabel.rb +28 -0
  344. data/test/plugin/test_out_roundrobin.rb +36 -29
  345. data/test/plugin/test_out_secondary_file.rb +458 -0
  346. data/test/plugin/test_out_stdout.rb +135 -37
  347. data/test/plugin/test_out_stream.rb +18 -0
  348. data/test/plugin/test_output.rb +984 -0
  349. data/test/plugin/test_output_as_buffered.rb +2021 -0
  350. data/test/plugin/test_output_as_buffered_backup.rb +312 -0
  351. data/test/plugin/test_output_as_buffered_compress.rb +165 -0
  352. data/test/plugin/test_output_as_buffered_overflow.rb +250 -0
  353. data/test/plugin/test_output_as_buffered_retries.rb +911 -0
  354. data/test/plugin/test_output_as_buffered_secondary.rb +874 -0
  355. data/test/plugin/test_output_as_standard.rb +374 -0
  356. data/test/plugin/test_owned_by.rb +35 -0
  357. data/test/plugin/test_parser.rb +359 -0
  358. data/test/plugin/test_parser_apache.rb +42 -0
  359. data/test/plugin/test_parser_apache2.rb +47 -0
  360. data/test/plugin/test_parser_apache_error.rb +45 -0
  361. data/test/plugin/test_parser_csv.rb +103 -0
  362. data/test/plugin/test_parser_json.rb +138 -0
  363. data/test/plugin/test_parser_labeled_tsv.rb +145 -0
  364. data/test/plugin/test_parser_multiline.rb +100 -0
  365. data/test/plugin/test_parser_nginx.rb +88 -0
  366. data/test/plugin/test_parser_none.rb +52 -0
  367. data/test/plugin/test_parser_regexp.rb +289 -0
  368. data/test/plugin/test_parser_syslog.rb +441 -0
  369. data/test/plugin/test_parser_tsv.rb +122 -0
  370. data/test/plugin/test_storage.rb +167 -0
  371. data/test/plugin/test_storage_local.rb +335 -0
  372. data/test/plugin_helper/data/cert/cert-key.pem +27 -0
  373. data/test/plugin_helper/data/cert/cert-with-no-newline.pem +19 -0
  374. data/test/plugin_helper/data/cert/cert.pem +19 -0
  375. data/test/plugin_helper/http_server/test_app.rb +65 -0
  376. data/test/plugin_helper/http_server/test_route.rb +32 -0
  377. data/test/plugin_helper/test_cert_option.rb +16 -0
  378. data/test/plugin_helper/test_child_process.rb +794 -0
  379. data/test/plugin_helper/test_compat_parameters.rb +353 -0
  380. data/test/plugin_helper/test_event_emitter.rb +51 -0
  381. data/test/plugin_helper/test_event_loop.rb +52 -0
  382. data/test/plugin_helper/test_extract.rb +194 -0
  383. data/test/plugin_helper/test_formatter.rb +255 -0
  384. data/test/plugin_helper/test_http_server_helper.rb +205 -0
  385. data/test/plugin_helper/test_inject.rb +519 -0
  386. data/test/plugin_helper/test_parser.rb +264 -0
  387. data/test/plugin_helper/test_record_accessor.rb +197 -0
  388. data/test/plugin_helper/test_retry_state.rb +442 -0
  389. data/test/plugin_helper/test_server.rb +1714 -0
  390. data/test/plugin_helper/test_storage.rb +542 -0
  391. data/test/plugin_helper/test_thread.rb +164 -0
  392. data/test/plugin_helper/test_timer.rb +132 -0
  393. data/test/scripts/exec_script.rb +0 -6
  394. data/test/scripts/fluent/plugin/formatter1/formatter_test1.rb +7 -0
  395. data/test/scripts/fluent/plugin/formatter2/formatter_test2.rb +7 -0
  396. data/test/scripts/fluent/plugin/out_test.rb +23 -15
  397. data/test/scripts/fluent/plugin/out_test2.rb +80 -0
  398. data/test/test_clock.rb +164 -0
  399. data/test/test_config.rb +16 -7
  400. data/test/test_configdsl.rb +2 -2
  401. data/test/test_event.rb +360 -13
  402. data/test/test_event_router.rb +108 -11
  403. data/test/test_event_time.rb +199 -0
  404. data/test/test_filter.rb +48 -6
  405. data/test/test_formatter.rb +11 -391
  406. data/test/test_input.rb +1 -1
  407. data/test/test_log.rb +591 -31
  408. data/test/test_mixin.rb +1 -1
  409. data/test/test_output.rb +121 -185
  410. data/test/test_plugin.rb +251 -0
  411. data/test/test_plugin_classes.rb +177 -10
  412. data/test/test_plugin_helper.rb +81 -0
  413. data/test/test_plugin_id.rb +101 -0
  414. data/test/test_process.rb +8 -42
  415. data/test/test_root_agent.rb +766 -21
  416. data/test/test_supervisor.rb +481 -0
  417. data/test/test_test_drivers.rb +135 -0
  418. data/test/test_time_formatter.rb +282 -0
  419. data/test/test_time_parser.rb +231 -0
  420. data/test/test_unique_id.rb +47 -0
  421. metadata +454 -60
  422. data/COPYING +0 -14
  423. data/ChangeLog +0 -666
  424. data/lib/fluent/buffer.rb +0 -365
  425. data/lib/fluent/plugin/in_status.rb +0 -76
  426. data/test/plugin/test_in_status.rb +0 -38
  427. data/test/test_buffer.rb +0 -624
  428. data/test/test_parser.rb +0 -1305
@@ -0,0 +1,911 @@
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
+ require 'timecop'
10
+
11
+ module FluentPluginOutputAsBufferedRetryTest
12
+ class DummyBareOutput < Fluent::Plugin::Output
13
+ def register(name, &block)
14
+ instance_variable_set("@#{name}", block)
15
+ end
16
+ end
17
+ class DummySyncOutput < DummyBareOutput
18
+ def initialize
19
+ super
20
+ @process = nil
21
+ end
22
+ def process(tag, es)
23
+ @process ? @process.call(tag, es) : nil
24
+ end
25
+ end
26
+ class DummyFullFeatureOutput < DummyBareOutput
27
+ def initialize
28
+ super
29
+ @prefer_buffered_processing = nil
30
+ @prefer_delayed_commit = nil
31
+ @process = nil
32
+ @format = nil
33
+ @write = nil
34
+ @try_write = nil
35
+ end
36
+ def prefer_buffered_processing
37
+ @prefer_buffered_processing ? @prefer_buffered_processing.call : false
38
+ end
39
+ def prefer_delayed_commit
40
+ @prefer_delayed_commit ? @prefer_delayed_commit.call : false
41
+ end
42
+ def process(tag, es)
43
+ @process ? @process.call(tag, es) : nil
44
+ end
45
+ def format(tag, time, record)
46
+ @format ? @format.call(tag, time, record) : [tag, time, record].to_json
47
+ end
48
+ def write(chunk)
49
+ @write ? @write.call(chunk) : nil
50
+ end
51
+ def try_write(chunk)
52
+ @try_write ? @try_write.call(chunk) : nil
53
+ end
54
+ end
55
+ class DummyFullFeatureOutput2 < DummyFullFeatureOutput
56
+ def prefer_buffered_processing; true; end
57
+ def prefer_delayed_commit; super; end
58
+ def format(tag, time, record); super; end
59
+ def write(chunk); super; end
60
+ def try_write(chunk); super; end
61
+ end
62
+ end
63
+
64
+ class BufferedOutputRetryTest < Test::Unit::TestCase
65
+ def create_output(type=:full)
66
+ case type
67
+ when :bare then FluentPluginOutputAsBufferedRetryTest::DummyBareOutput.new
68
+ when :sync then FluentPluginOutputAsBufferedRetryTest::DummySyncOutput.new
69
+ when :full then FluentPluginOutputAsBufferedRetryTest::DummyFullFeatureOutput.new
70
+ else
71
+ raise ArgumentError, "unknown type: #{type}"
72
+ end
73
+ end
74
+ def create_metadata(timekey: nil, tag: nil, variables: nil)
75
+ Fluent::Plugin::Buffer::Metadata.new(timekey, tag, variables)
76
+ end
77
+ def waiting(seconds)
78
+ begin
79
+ Timeout.timeout(seconds) do
80
+ yield
81
+ end
82
+ rescue Timeout::Error
83
+ STDERR.print(*@i.log.out.logs)
84
+ raise
85
+ end
86
+ end
87
+ def dummy_event_stream
88
+ Fluent::ArrayEventStream.new([
89
+ [ event_time('2016-04-13 18:33:00'), {"name" => "moris", "age" => 36, "message" => "data1"} ],
90
+ [ event_time('2016-04-13 18:33:13'), {"name" => "moris", "age" => 36, "message" => "data2"} ],
91
+ [ event_time('2016-04-13 18:33:32'), {"name" => "moris", "age" => 36, "message" => "data3"} ],
92
+ ])
93
+ end
94
+ def get_log_time(msg, logs)
95
+ log_time = nil
96
+ log = logs.select{|l| l.include?(msg) }.first
97
+ if log && /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-+]\d{4}) \[error\]/ =~ log
98
+ log_time = Time.parse($1)
99
+ end
100
+ log_time
101
+ end
102
+
103
+ setup do
104
+ @i = create_output
105
+ end
106
+
107
+ teardown do
108
+ if @i
109
+ @i.stop unless @i.stopped?
110
+ @i.before_shutdown unless @i.before_shutdown?
111
+ @i.shutdown unless @i.shutdown?
112
+ @i.after_shutdown unless @i.after_shutdown?
113
+ @i.close unless @i.closed?
114
+ @i.terminate unless @i.terminated?
115
+ end
116
+ Timecop.return
117
+ end
118
+
119
+ sub_test_case 'buffered output for retries with exponential backoff' do
120
+ test 'exponential backoff is default strategy for retries' do
121
+ chunk_key = 'tag'
122
+ hash = {
123
+ 'flush_interval' => 1,
124
+ 'flush_thread_burst_interval' => 0.1,
125
+ 'retry_randomize' => false,
126
+ 'queued_chunks_limit_size' => 100
127
+ }
128
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
129
+ @i.register(:prefer_buffered_processing){ true }
130
+ @i.start
131
+ @i.after_start
132
+
133
+ assert_equal :exponential_backoff, @i.buffer_config.retry_type
134
+ assert_equal 1, @i.buffer_config.retry_wait
135
+ assert_equal 2.0, @i.buffer_config.retry_exponential_backoff_base
136
+ assert !@i.buffer_config.retry_randomize
137
+
138
+ now = Time.parse('2016-04-13 18:17:00 -0700')
139
+ Timecop.freeze( now )
140
+
141
+ retry_state = @i.retry_state( @i.buffer_config.retry_randomize )
142
+ retry_state.step
143
+ assert_equal 1, (retry_state.next_time - now)
144
+ retry_state.step
145
+ assert_equal (1 * (2 ** 1)), (retry_state.next_time - now)
146
+ retry_state.step
147
+ assert_equal (1 * (2 ** 2)), (retry_state.next_time - now)
148
+ retry_state.step
149
+ assert_equal (1 * (2 ** 3)), (retry_state.next_time - now)
150
+ end
151
+
152
+ test 'does retries correctly when #write fails' do
153
+ chunk_key = 'tag'
154
+ hash = {
155
+ 'flush_interval' => 1,
156
+ 'flush_thread_burst_interval' => 0.1,
157
+ 'retry_randomize' => false,
158
+ 'retry_max_interval' => 60 * 60,
159
+ }
160
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
161
+ @i.register(:prefer_buffered_processing){ true }
162
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
163
+ @i.register(:write){|chunk| raise "yay, your #write must fail" }
164
+ @i.start
165
+ @i.after_start
166
+
167
+ @i.interrupt_flushes
168
+
169
+ now = Time.parse('2016-04-13 18:33:30 -0700')
170
+ Timecop.freeze( now )
171
+
172
+ @i.emit_events("test.tag.1", dummy_event_stream())
173
+
174
+ now = Time.parse('2016-04-13 18:33:32 -0700')
175
+ Timecop.freeze( now )
176
+
177
+ @i.enqueue_thread_wait
178
+
179
+ @i.flush_thread_wakeup
180
+ waiting(4){ Thread.pass until @i.write_count > 0 }
181
+
182
+ assert{ @i.write_count > 0 }
183
+ assert{ @i.num_errors > 0 }
184
+
185
+ now = @i.next_flush_time
186
+ Timecop.freeze( now )
187
+ @i.flush_thread_wakeup
188
+ waiting(4){ Thread.pass until @i.write_count > 1 }
189
+
190
+ assert{ @i.write_count > 1 }
191
+ assert{ @i.num_errors > 1 }
192
+ end
193
+
194
+ test 'max retry interval is limited by retry_max_interval' do
195
+ chunk_key = 'tag'
196
+ hash = {
197
+ 'flush_interval' => 1,
198
+ 'flush_thread_burst_interval' => 0.1,
199
+ 'retry_randomize' => false,
200
+ 'retry_max_interval' => 60,
201
+ }
202
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
203
+ @i.register(:prefer_buffered_processing){ true }
204
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
205
+ @i.register(:write){|chunk| raise "yay, your #write must fail" }
206
+ @i.start
207
+ @i.after_start
208
+
209
+ @i.interrupt_flushes
210
+
211
+ now = Time.parse('2016-04-13 18:33:30 -0700')
212
+ Timecop.freeze( now )
213
+
214
+ @i.emit_events("test.tag.1", dummy_event_stream())
215
+
216
+ now = Time.parse('2016-04-13 18:33:32 -0700')
217
+ Timecop.freeze( now )
218
+
219
+ @i.enqueue_thread_wait
220
+
221
+ @i.flush_thread_wakeup
222
+ waiting(4){ Thread.pass until @i.write_count > 0 && @i.num_errors > 0 }
223
+
224
+ assert{ @i.write_count > 0 }
225
+ assert{ @i.num_errors > 0 }
226
+
227
+ prev_write_count = @i.write_count
228
+ prev_num_errors = @i.num_errors
229
+
230
+ 10.times do
231
+ now = @i.next_flush_time
232
+ Timecop.freeze( now )
233
+ @i.flush_thread_wakeup
234
+ waiting(4){ Thread.pass until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
235
+
236
+ assert{ @i.write_count > prev_write_count }
237
+ assert{ @i.num_errors > prev_num_errors }
238
+
239
+ prev_write_count = @i.write_count
240
+ prev_num_errors = @i.num_errors
241
+ end
242
+ # exponential backoff interval: 1 * 2 ** 10 == 1024
243
+ # but it should be limited by retry_max_interval=60
244
+ assert_equal 60, (@i.next_flush_time - now)
245
+ end
246
+
247
+ test 'output plugin give retries up by retry_timeout, and clear queue in buffer' do
248
+ written_tags = []
249
+
250
+ chunk_key = 'tag'
251
+ hash = {
252
+ 'flush_interval' => 1,
253
+ 'flush_thread_burst_interval' => 0.1,
254
+ 'retry_randomize' => false,
255
+ 'retry_timeout' => 3600,
256
+ 'queued_chunks_limit_size' => 100
257
+ }
258
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
259
+ @i.register(:prefer_buffered_processing){ true }
260
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
261
+ @i.register(:write){|chunk| written_tags << chunk.metadata.tag; raise "yay, your #write must fail" }
262
+ @i.start
263
+ @i.after_start
264
+
265
+ @i.interrupt_flushes
266
+
267
+ now = Time.parse('2016-04-13 18:33:30 -0700')
268
+ Timecop.freeze( now )
269
+
270
+ @i.emit_events("test.tag.1", dummy_event_stream())
271
+
272
+ now = Time.parse('2016-04-13 18:33:31 -0700')
273
+ Timecop.freeze( now )
274
+
275
+ @i.emit_events("test.tag.2", dummy_event_stream())
276
+
277
+ assert_equal 0, @i.write_count
278
+ assert_equal 0, @i.num_errors
279
+
280
+ @i.enqueue_thread_wait
281
+ @i.flush_thread_wakeup
282
+ waiting(4){ Thread.pass until @i.write_count > 0 && @i.num_errors > 0 }
283
+
284
+ assert{ @i.buffer.queue.size > 0 }
285
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
286
+
287
+ assert{ @i.write_count > 0 }
288
+ assert{ @i.num_errors > 0 }
289
+
290
+ prev_write_count = @i.write_count
291
+ prev_num_errors = @i.num_errors
292
+
293
+ first_failure = @i.retry.start
294
+
295
+ 15.times do |i| # large enough
296
+ now = @i.next_flush_time
297
+ # p({i: i, now: now, diff: (now - Time.now)})
298
+ # * if loop count is 12:
299
+ # {:i=>0, :now=>2016-04-13 18:33:32 -0700, :diff=>1.0}
300
+ # {:i=>1, :now=>2016-04-13 18:33:34 -0700, :diff=>2.0}
301
+ # {:i=>2, :now=>2016-04-13 18:33:38 -0700, :diff=>4.0}
302
+ # {:i=>3, :now=>2016-04-13 18:33:46 -0700, :diff=>8.0}
303
+ # {:i=>4, :now=>2016-04-13 18:34:02 -0700, :diff=>16.0}
304
+ # {:i=>5, :now=>2016-04-13 18:34:34 -0700, :diff=>32.0}
305
+ # {:i=>6, :now=>2016-04-13 18:35:38 -0700, :diff=>64.0}
306
+ # {:i=>7, :now=>2016-04-13 18:37:46 -0700, :diff=>128.0}
307
+ # {:i=>8, :now=>2016-04-13 18:42:02 -0700, :diff=>256.0}
308
+ # {:i=>9, :now=>2016-04-13 18:50:34 -0700, :diff=>512.0}
309
+ # {:i=>10, :now=>2016-04-13 19:07:38 -0700, :diff=>1024.0}
310
+ # {:i=>11, :now=>2016-04-13 19:33:31 -0700, :diff=>1553.0} # clear_queue!
311
+
312
+ Timecop.freeze( now )
313
+ @i.enqueue_thread_wait
314
+ @i.flush_thread_wakeup
315
+ waiting(4){ Thread.pass until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
316
+
317
+ assert{ @i.write_count > prev_write_count }
318
+ assert{ @i.num_errors > prev_num_errors }
319
+
320
+ break if @i.buffer.queue.size == 0
321
+
322
+ prev_write_count = @i.write_count
323
+ prev_num_errors = @i.num_errors
324
+
325
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
326
+ end
327
+ assert{ now >= first_failure + 3600 }
328
+
329
+ assert{ @i.buffer.stage.size == 0 }
330
+ assert{ written_tags.all?{|t| t == 'test.tag.1' } }
331
+
332
+ @i.emit_events("test.tag.3", dummy_event_stream())
333
+
334
+ logs = @i.log.out.logs
335
+ assert{ logs.any?{|l| l.include?("[error]: failed to flush the buffer, and hit limit for retries. dropping all chunks in the buffer queue.") } }
336
+ end
337
+
338
+ test 'output plugin give retries up by retry_max_times, and clear queue in buffer' do
339
+ written_tags = []
340
+
341
+ chunk_key = 'tag'
342
+ hash = {
343
+ 'flush_interval' => 1,
344
+ 'flush_thread_burst_interval' => 0.1,
345
+ 'retry_randomize' => false,
346
+ 'retry_max_times' => 10,
347
+ 'queued_chunks_limit_size' => 100
348
+ }
349
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
350
+ @i.register(:prefer_buffered_processing){ true }
351
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
352
+ @i.register(:write){|chunk| written_tags << chunk.metadata.tag; raise "yay, your #write must fail" }
353
+ @i.start
354
+ @i.after_start
355
+
356
+ @i.interrupt_flushes
357
+
358
+ now = Time.parse('2016-04-13 18:33:30 -0700')
359
+ Timecop.freeze( now )
360
+
361
+ @i.emit_events("test.tag.1", dummy_event_stream())
362
+
363
+ now = Time.parse('2016-04-13 18:33:31 -0700')
364
+ Timecop.freeze( now )
365
+
366
+ @i.emit_events("test.tag.2", dummy_event_stream())
367
+
368
+ assert_equal 0, @i.write_count
369
+ assert_equal 0, @i.num_errors
370
+
371
+ @i.enqueue_thread_wait
372
+ @i.flush_thread_wakeup
373
+ waiting(4){ Thread.pass until @i.write_count > 0 && @i.num_errors > 0 }
374
+
375
+ assert{ @i.buffer.queue.size > 0 }
376
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
377
+
378
+ assert{ @i.write_count > 0 }
379
+ assert{ @i.num_errors > 0 }
380
+
381
+ prev_write_count = @i.write_count
382
+ prev_num_errors = @i.num_errors
383
+
384
+ _first_failure = @i.retry.start
385
+
386
+ chunks = @i.buffer.queue.dup
387
+
388
+ 20.times do |i| # large times enough
389
+ now = @i.next_flush_time
390
+
391
+ Timecop.freeze( now )
392
+ @i.enqueue_thread_wait
393
+ @i.flush_thread_wakeup
394
+ waiting(4){ Thread.pass until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
395
+
396
+ assert{ @i.write_count > prev_write_count }
397
+ assert{ @i.num_errors > prev_num_errors }
398
+
399
+ break if @i.buffer.queue.size == 0
400
+
401
+ prev_write_count = @i.write_count
402
+ prev_num_errors = @i.num_errors
403
+
404
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
405
+ end
406
+ assert{ @i.buffer.stage.size == 0 }
407
+ assert{ written_tags.all?{|t| t == 'test.tag.1' } }
408
+
409
+ @i.emit_events("test.tag.3", dummy_event_stream())
410
+
411
+ logs = @i.log.out.logs
412
+ assert{ logs.any?{|l| l.include?("[error]: failed to flush the buffer, and hit limit for retries. dropping all chunks in the buffer queue.") && l.include?("retry_times=10") } }
413
+
414
+ assert{ @i.buffer.queue.size == 0 }
415
+ assert{ @i.buffer.stage.size == 1 }
416
+ assert{ chunks.all?{|c| c.empty? } }
417
+ end
418
+
419
+ test 'output plugin limits queued chunks via queued_chunks_limit_size' do
420
+ chunk_key = 'tag'
421
+ hash = {
422
+ 'flush_interval' => 1,
423
+ 'flush_thread_burst_interval' => 0.1,
424
+ 'retry_randomize' => false,
425
+ 'retry_max_times' => 7,
426
+ 'queued_chunks_limit_size' => 2,
427
+ }
428
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
429
+ @i.register(:prefer_buffered_processing) { true }
430
+ @i.register(:format) { |tag,time,record| [tag,time.to_i,record].to_json + "\n" }
431
+ @i.register(:write) { |chunk| raise "yay, your #write must fail" }
432
+ @i.start
433
+ @i.after_start
434
+
435
+ @i.interrupt_flushes
436
+
437
+ now = Time.parse('2016-04-13 18:33:30 -0700')
438
+ Timecop.freeze(now)
439
+
440
+ @i.emit_events("test.tag.1", dummy_event_stream())
441
+
442
+ now = Time.parse('2016-04-13 18:33:31 -0700')
443
+ Timecop.freeze(now)
444
+
445
+ @i.emit_events("test.tag.2", dummy_event_stream())
446
+
447
+ @i.enqueue_thread_wait
448
+ @i.flush_thread_wakeup
449
+ waiting(4) { Thread.pass until @i.write_count > 0 && @i.num_errors > 0 }
450
+
451
+ assert { @i.buffer.queue.size > 0 }
452
+ assert { @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
453
+
454
+ assert { @i.write_count > 0 }
455
+ assert { @i.num_errors > 0 }
456
+
457
+ prev_write_count = @i.write_count
458
+ prev_num_errors = @i.num_errors
459
+
460
+ 20.times do |i| # large times enough
461
+ now = @i.next_flush_time
462
+
463
+ Timecop.freeze(now)
464
+ @i.enqueue_thread_wait
465
+ @i.flush_thread_wakeup
466
+ waiting(4) { Thread.pass until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
467
+
468
+ @i.emit_events("test.tag.1", dummy_event_stream())
469
+ assert { @i.buffer.queue.size <= 2 }
470
+ assert { @i.buffer.stage.size == 1 } # all new data is stored into staged chunk
471
+
472
+ break if @i.buffer.queue.size == 0
473
+
474
+ prev_write_count = @i.write_count
475
+ prev_num_errors = @i.num_errors
476
+ end
477
+ end
478
+ end
479
+
480
+ sub_test_case 'bufferd output for retries with periodical retry' do
481
+ test 'periodical retries should retry to write in failing status per retry_wait' do
482
+ chunk_key = 'tag'
483
+ hash = {
484
+ 'flush_interval' => 1,
485
+ 'flush_thread_burst_interval' => 0.1,
486
+ 'retry_type' => :periodic,
487
+ 'retry_wait' => 3,
488
+ 'retry_randomize' => false,
489
+ 'queued_chunks_limit_size' => 100
490
+ }
491
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
492
+ @i.register(:prefer_buffered_processing){ true }
493
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
494
+ @i.register(:write){|chunk| raise "yay, your #write must fail" }
495
+ @i.start
496
+ @i.after_start
497
+
498
+ @i.interrupt_flushes
499
+
500
+ now = Time.parse('2016-04-13 18:33:30 -0700')
501
+ Timecop.freeze( now )
502
+
503
+ @i.emit_events("test.tag.1", dummy_event_stream())
504
+
505
+ now = Time.parse('2016-04-13 18:33:32 -0700')
506
+ Timecop.freeze( now )
507
+
508
+ @i.enqueue_thread_wait
509
+
510
+ @i.flush_thread_wakeup
511
+ waiting(4){ Thread.pass until @i.write_count > 0 }
512
+
513
+ assert{ @i.write_count > 0 }
514
+ assert{ @i.num_errors > 0 }
515
+
516
+ now = @i.next_flush_time
517
+ Timecop.freeze( now )
518
+ @i.flush_thread_wakeup
519
+ waiting(4){ Thread.pass until @i.write_count > 1 }
520
+
521
+ assert{ @i.write_count > 1 }
522
+ assert{ @i.num_errors > 1 }
523
+ end
524
+
525
+ test 'output plugin give retries up by retry_timeout, and clear queue in buffer' do
526
+ written_tags = []
527
+
528
+ chunk_key = 'tag'
529
+ hash = {
530
+ 'flush_interval' => 1,
531
+ 'flush_thread_burst_interval' => 0.1,
532
+ 'retry_type' => :periodic,
533
+ 'retry_wait' => 30,
534
+ 'retry_randomize' => false,
535
+ 'retry_timeout' => 120,
536
+ 'queued_chunks_limit_size' => 100
537
+ }
538
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
539
+ @i.register(:prefer_buffered_processing){ true }
540
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
541
+ @i.register(:write){|chunk| written_tags << chunk.metadata.tag; raise "yay, your #write must fail" }
542
+ @i.start
543
+ @i.after_start
544
+
545
+ @i.interrupt_flushes
546
+
547
+ now = Time.parse('2016-04-13 18:33:30 -0700')
548
+ Timecop.freeze( now )
549
+
550
+ @i.emit_events("test.tag.1", dummy_event_stream())
551
+
552
+ now = Time.parse('2016-04-13 18:33:31 -0700')
553
+ Timecop.freeze( now )
554
+
555
+ @i.emit_events("test.tag.2", dummy_event_stream())
556
+
557
+ assert_equal 0, @i.write_count
558
+ assert_equal 0, @i.num_errors
559
+
560
+ @i.enqueue_thread_wait
561
+ @i.flush_thread_wakeup
562
+ waiting(4){ Thread.pass until @i.write_count > 0 && @i.num_errors > 0 }
563
+
564
+ assert{ @i.buffer.queue.size > 0 }
565
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
566
+
567
+ assert{ @i.write_count > 0 }
568
+ assert{ @i.num_errors > 0 }
569
+
570
+ prev_write_count = @i.write_count
571
+ prev_num_errors = @i.num_errors
572
+
573
+ first_failure = @i.retry.start
574
+
575
+ 3.times do |i|
576
+ now = @i.next_flush_time
577
+
578
+ Timecop.freeze( now )
579
+ @i.enqueue_thread_wait
580
+ @i.flush_thread_wakeup
581
+ waiting(4){ Thread.pass until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
582
+
583
+ assert{ @i.write_count > prev_write_count }
584
+ assert{ @i.num_errors > prev_num_errors }
585
+
586
+ prev_write_count = @i.write_count
587
+ prev_num_errors = @i.num_errors
588
+ end
589
+
590
+ assert{ @i.next_flush_time >= first_failure + 120 }
591
+
592
+ assert{ @i.buffer.queue.size == 2 }
593
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
594
+ assert{ @i.buffer.stage.size == 0 }
595
+
596
+ assert{ written_tags.all?{|t| t == 'test.tag.1' } }
597
+
598
+ chunks = @i.buffer.queue.dup
599
+
600
+ @i.emit_events("test.tag.3", dummy_event_stream())
601
+
602
+ now = @i.next_flush_time
603
+ Timecop.freeze( now )
604
+ @i.flush_thread_wakeup
605
+ waiting(4){ Thread.pass until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
606
+
607
+ logs = @i.log.out.logs
608
+
609
+ target_time = Time.parse("2016-04-13 18:35:31 -0700")
610
+ target_msg = "[error]: failed to flush the buffer, and hit limit for retries. dropping all chunks in the buffer queue."
611
+ assert{ logs.any?{|l| l.include?(target_msg) } }
612
+
613
+ log_time = get_log_time(target_msg, logs)
614
+ assert_equal target_time.localtime, log_time.localtime
615
+
616
+ assert{ @i.buffer.queue.size == 0 }
617
+ assert{ @i.buffer.stage.size == 1 }
618
+ assert{ chunks.all?{|c| c.empty? } }
619
+ end
620
+
621
+ test 'retry_max_times can limit maximum times for retries' do
622
+ written_tags = []
623
+
624
+ chunk_key = 'tag'
625
+ hash = {
626
+ 'flush_interval' => 1,
627
+ 'flush_thread_burst_interval' => 0.1,
628
+ 'retry_type' => :periodic,
629
+ 'retry_wait' => 3,
630
+ 'retry_randomize' => false,
631
+ 'retry_max_times' => 10,
632
+ 'queued_chunks_limit_size' => 100
633
+ }
634
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
635
+ @i.register(:prefer_buffered_processing){ true }
636
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
637
+ @i.register(:write){|chunk| written_tags << chunk.metadata.tag; raise "yay, your #write must fail" }
638
+ @i.start
639
+ @i.after_start
640
+
641
+ @i.interrupt_flushes
642
+
643
+ now = Time.parse('2016-04-13 18:33:30 -0700')
644
+ Timecop.freeze( now )
645
+
646
+ @i.emit_events("test.tag.1", dummy_event_stream())
647
+
648
+ now = Time.parse('2016-04-13 18:33:31 -0700')
649
+ Timecop.freeze( now )
650
+
651
+ @i.emit_events("test.tag.2", dummy_event_stream())
652
+
653
+ assert_equal 0, @i.write_count
654
+ assert_equal 0, @i.num_errors
655
+
656
+ @i.enqueue_thread_wait
657
+ @i.flush_thread_wakeup
658
+ waiting(4){ Thread.pass until @i.write_count > 0 && @i.num_errors > 0 }
659
+
660
+ assert{ @i.buffer.queue.size > 0 }
661
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
662
+
663
+ assert{ @i.write_count > 0 }
664
+ assert{ @i.num_errors > 0 }
665
+
666
+ prev_write_count = @i.write_count
667
+ prev_num_errors = @i.num_errors
668
+
669
+ _first_failure = @i.retry.start
670
+
671
+ chunks = @i.buffer.queue.dup
672
+
673
+ 20.times do |i|
674
+ now = @i.next_flush_time
675
+
676
+ Timecop.freeze( now )
677
+ @i.enqueue_thread_wait
678
+ @i.flush_thread_wakeup
679
+ waiting(4){ Thread.pass until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
680
+
681
+ assert{ @i.write_count > prev_write_count }
682
+ assert{ @i.num_errors > prev_num_errors }
683
+
684
+ break if @i.buffer.queue.size == 0
685
+
686
+ prev_write_count = @i.write_count
687
+ prev_num_errors = @i.num_errors
688
+
689
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
690
+ end
691
+ assert{ @i.buffer.stage.size == 0 }
692
+ assert{ written_tags.all?{|t| t == 'test.tag.1' } }
693
+
694
+
695
+ @i.emit_events("test.tag.3", dummy_event_stream())
696
+
697
+ logs = @i.log.out.logs
698
+ assert{ logs.any?{|l| l.include?("[error]: failed to flush the buffer, and hit limit for retries. dropping all chunks in the buffer queue.") && l.include?("retry_times=10") } }
699
+
700
+ assert{ @i.buffer.queue.size == 0 }
701
+ assert{ @i.buffer.stage.size == 1 }
702
+ assert{ chunks.all?{|c| c.empty? } }
703
+ end
704
+ end
705
+
706
+ sub_test_case 'buffered output configured as retry_forever' do
707
+ setup do
708
+ Fluent::Plugin.register_output('output_retries_secondary_test', FluentPluginOutputAsBufferedRetryTest::DummyFullFeatureOutput2)
709
+ end
710
+
711
+ test 'warning logs are generated if secondary section is configured' do
712
+ chunk_key = 'tag'
713
+ hash = {
714
+ 'retry_forever' => true,
715
+ 'retry_randomize' => false,
716
+ }
717
+ i = create_output()
718
+ i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash),config_element('secondary','', {'@type' => 'output_retries_secondary_test'})]))
719
+ logs = i.log.out.logs
720
+ assert { logs.any? { |l| l.include?("<secondary> with 'retry_forever', only unrecoverable errors are moved to secondary") } }
721
+ end
722
+
723
+ test 'retry_timeout and retry_max_times will be ignored if retry_forever is true for exponential backoff' do
724
+ written_tags = []
725
+
726
+ chunk_key = 'tag'
727
+ hash = {
728
+ 'flush_interval' => 1,
729
+ 'flush_thread_burst_interval' => 0.1,
730
+ 'retry_type' => :exponential_backoff,
731
+ 'retry_forever' => true,
732
+ 'retry_randomize' => false,
733
+ 'retry_timeout' => 3600,
734
+ 'retry_max_times' => 10,
735
+ 'queued_chunks_limit_size' => 100
736
+ }
737
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
738
+ @i.register(:prefer_buffered_processing){ true }
739
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
740
+ @i.register(:write){|chunk| written_tags << chunk.metadata.tag; raise "yay, your #write must fail" }
741
+ @i.start
742
+ @i.after_start
743
+
744
+ @i.interrupt_flushes
745
+
746
+ now = Time.parse('2016-04-13 18:33:30 -0700')
747
+ Timecop.freeze( now )
748
+
749
+ @i.emit_events("test.tag.1", dummy_event_stream())
750
+
751
+ now = Time.parse('2016-04-13 18:33:31 -0700')
752
+ Timecop.freeze( now )
753
+
754
+ @i.emit_events("test.tag.2", dummy_event_stream())
755
+
756
+ assert_equal 0, @i.write_count
757
+ assert_equal 0, @i.num_errors
758
+
759
+ @i.enqueue_thread_wait
760
+ @i.flush_thread_wakeup
761
+ waiting(4){ sleep 0.1 until @i.write_count > 0 && @i.num_errors > 0 }
762
+
763
+ assert{ @i.buffer.queue.size > 0 }
764
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
765
+
766
+ assert{ @i.write_count > 0 }
767
+ assert{ @i.num_errors > 0 }
768
+
769
+ prev_write_count = @i.write_count
770
+ prev_num_errors = @i.num_errors
771
+
772
+ first_failure = @i.retry.start
773
+
774
+ 15.times do |i|
775
+ now = @i.next_flush_time
776
+
777
+ Timecop.freeze( now + 1 )
778
+ @i.enqueue_thread_wait
779
+ @i.flush_thread_wakeup
780
+ waiting(4){ sleep 0.1 until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
781
+
782
+ assert{ @i.write_count > prev_write_count }
783
+ assert{ @i.num_errors > prev_num_errors }
784
+
785
+ prev_write_count = @i.write_count
786
+ prev_num_errors = @i.num_errors
787
+ end
788
+
789
+ assert{ @i.buffer.queue.size == 2 }
790
+ assert{ @i.retry.steps > 10 }
791
+ assert{ now > first_failure + 3600 }
792
+ end
793
+
794
+ test 'retry_timeout and retry_max_times will be ignored if retry_forever is true for periodical retries' do
795
+ written_tags = []
796
+
797
+ chunk_key = 'tag'
798
+ hash = {
799
+ 'flush_interval' => 1,
800
+ 'flush_thread_burst_interval' => 0.1,
801
+ 'retry_type' => :periodic,
802
+ 'retry_forever' => true,
803
+ 'retry_randomize' => false,
804
+ 'retry_wait' => 30,
805
+ 'retry_timeout' => 360,
806
+ 'retry_max_times' => 10,
807
+ 'queued_chunks_limit_size' => 100
808
+ }
809
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
810
+ @i.register(:prefer_buffered_processing){ true }
811
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
812
+ @i.register(:write){|chunk| written_tags << chunk.metadata.tag; raise "yay, your #write must fail" }
813
+ @i.start
814
+ @i.after_start
815
+
816
+ @i.interrupt_flushes
817
+
818
+ now = Time.parse('2016-04-13 18:33:30 -0700')
819
+ Timecop.freeze( now )
820
+
821
+ @i.emit_events("test.tag.1", dummy_event_stream())
822
+
823
+ now = Time.parse('2016-04-13 18:33:31 -0700')
824
+ Timecop.freeze( now )
825
+
826
+ @i.emit_events("test.tag.2", dummy_event_stream())
827
+
828
+ assert_equal 0, @i.write_count
829
+ assert_equal 0, @i.num_errors
830
+
831
+ @i.enqueue_thread_wait
832
+ @i.flush_thread_wakeup
833
+ waiting(4){ sleep 0.1 until @i.write_count > 0 && @i.num_errors > 0 }
834
+
835
+ assert{ @i.buffer.queue.size > 0 }
836
+ assert{ @i.buffer.queue.first.metadata.tag == 'test.tag.1' }
837
+
838
+ assert{ @i.write_count > 0 }
839
+ assert{ @i.num_errors > 0 }
840
+
841
+ prev_write_count = @i.write_count
842
+ prev_num_errors = @i.num_errors
843
+
844
+ first_failure = @i.retry.start
845
+
846
+ 15.times do |i|
847
+ now = @i.next_flush_time
848
+
849
+ Timecop.freeze( now + 1 )
850
+ @i.enqueue_thread_wait
851
+ @i.flush_thread_wakeup
852
+ waiting(4){ sleep 0.1 until @i.write_count > prev_write_count && @i.num_errors > prev_num_errors }
853
+
854
+ assert{ @i.write_count > prev_write_count }
855
+ assert{ @i.num_errors > prev_num_errors }
856
+
857
+ prev_write_count = @i.write_count
858
+ prev_num_errors = @i.num_errors
859
+ end
860
+
861
+ assert{ @i.buffer.queue.size == 2 }
862
+ assert{ @i.retry.steps > 10 }
863
+ assert{ now > first_failure + 360 }
864
+ end
865
+ end
866
+
867
+ sub_test_case 'buffered output with delayed commit' do
868
+ test 'does retries correctly when #try_write fails' do
869
+ chunk_key = 'tag'
870
+ hash = {
871
+ 'flush_interval' => 1,
872
+ 'flush_thread_burst_interval' => 0.1,
873
+ 'retry_randomize' => false,
874
+ 'retry_max_interval' => 60 * 60,
875
+ }
876
+ @i.configure(config_element('ROOT','',{},[config_element('buffer',chunk_key,hash)]))
877
+ @i.register(:prefer_buffered_processing){ true }
878
+ @i.register(:prefer_delayed_commit){ true }
879
+ @i.register(:format){|tag,time,record| [tag,time.to_i,record].to_json + "\n" }
880
+ @i.register(:try_write){|chunk| raise "yay, your #write must fail" }
881
+ @i.start
882
+ @i.after_start
883
+
884
+ @i.interrupt_flushes
885
+
886
+ now = Time.parse('2016-04-13 18:33:30 -0700')
887
+ Timecop.freeze( now )
888
+
889
+ @i.emit_events("test.tag.1", dummy_event_stream())
890
+
891
+ now = Time.parse('2016-04-13 18:33:32 -0700')
892
+ Timecop.freeze( now )
893
+
894
+ @i.enqueue_thread_wait
895
+
896
+ @i.flush_thread_wakeup
897
+ waiting(4){ Thread.pass until @i.write_count > 0 }
898
+
899
+ assert{ @i.write_count > 0 }
900
+ assert{ @i.num_errors > 0 }
901
+
902
+ now = @i.next_flush_time
903
+ Timecop.freeze( now )
904
+ @i.flush_thread_wakeup
905
+ waiting(4){ Thread.pass until @i.write_count > 1 }
906
+
907
+ assert{ @i.write_count > 1 }
908
+ assert{ @i.num_errors > 1 }
909
+ end
910
+ end
911
+ end