fluentd 1.20.0-aarch64-mingw-ucrt

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +116 -0
  3. data/ADOPTERS.md +5 -0
  4. data/AGENTS.md +46 -0
  5. data/AUTHORS +2 -0
  6. data/CHANGELOG.md +3324 -0
  7. data/CONTRIBUTING.md +45 -0
  8. data/GOVERNANCE.md +55 -0
  9. data/GithubWorkflow.md +78 -0
  10. data/LICENSE +202 -0
  11. data/MAINTAINERS.md +19 -0
  12. data/README.md +73 -0
  13. data/Rakefile +89 -0
  14. data/SECURITY.md +47 -0
  15. data/bin/fluent-binlog-reader +7 -0
  16. data/bin/fluent-ca-generate +6 -0
  17. data/bin/fluent-cap-ctl +7 -0
  18. data/bin/fluent-cat +5 -0
  19. data/bin/fluent-ctl +7 -0
  20. data/bin/fluent-debug +5 -0
  21. data/bin/fluent-gem +9 -0
  22. data/bin/fluent-plugin-config-format +5 -0
  23. data/bin/fluent-plugin-generate +5 -0
  24. data/bin/fluentd +15 -0
  25. data/code-of-conduct.md +3 -0
  26. data/docs/SECURITY_AUDIT.pdf +0 -0
  27. data/example/copy_roundrobin.conf +39 -0
  28. data/example/counter.conf +18 -0
  29. data/example/filter_stdout.conf +22 -0
  30. data/example/in_forward.conf +14 -0
  31. data/example/in_forward_client.conf +37 -0
  32. data/example/in_forward_shared_key.conf +15 -0
  33. data/example/in_forward_tls.conf +14 -0
  34. data/example/in_forward_users.conf +24 -0
  35. data/example/in_forward_workers.conf +21 -0
  36. data/example/in_http.conf +16 -0
  37. data/example/in_out_forward.conf +17 -0
  38. data/example/in_sample_blocks.conf +17 -0
  39. data/example/in_sample_with_compression.conf +23 -0
  40. data/example/in_syslog.conf +15 -0
  41. data/example/in_tail.conf +14 -0
  42. data/example/in_tcp.conf +13 -0
  43. data/example/in_udp.conf +13 -0
  44. data/example/logevents.conf +25 -0
  45. data/example/multi_filters.conf +61 -0
  46. data/example/out_copy.conf +20 -0
  47. data/example/out_exec_filter.conf +42 -0
  48. data/example/out_file.conf +13 -0
  49. data/example/out_forward.conf +35 -0
  50. data/example/out_forward_buf_file.conf +23 -0
  51. data/example/out_forward_client.conf +109 -0
  52. data/example/out_forward_heartbeat_none.conf +16 -0
  53. data/example/out_forward_sd.conf +17 -0
  54. data/example/out_forward_shared_key.conf +36 -0
  55. data/example/out_forward_tls.conf +18 -0
  56. data/example/out_forward_users.conf +65 -0
  57. data/example/out_null.conf +36 -0
  58. data/example/sd.yaml +8 -0
  59. data/example/secondary_file.conf +42 -0
  60. data/example/suppress_config_dump.conf +7 -0
  61. data/example/v0_12_filter.conf +78 -0
  62. data/example/v1_literal_example.conf +36 -0
  63. data/example/worker_section.conf +36 -0
  64. data/fluent.conf +139 -0
  65. data/lib/fluent/agent.rb +168 -0
  66. data/lib/fluent/capability.rb +87 -0
  67. data/lib/fluent/clock.rb +66 -0
  68. data/lib/fluent/command/binlog_reader.rb +244 -0
  69. data/lib/fluent/command/bundler_injection.rb +45 -0
  70. data/lib/fluent/command/ca_generate.rb +184 -0
  71. data/lib/fluent/command/cap_ctl.rb +174 -0
  72. data/lib/fluent/command/cat.rb +365 -0
  73. data/lib/fluent/command/ctl.rb +180 -0
  74. data/lib/fluent/command/debug.rb +103 -0
  75. data/lib/fluent/command/fluentd.rb +385 -0
  76. data/lib/fluent/command/plugin_config_formatter.rb +308 -0
  77. data/lib/fluent/command/plugin_generator.rb +365 -0
  78. data/lib/fluent/compat/call_super_mixin.rb +76 -0
  79. data/lib/fluent/compat/detach_process_mixin.rb +33 -0
  80. data/lib/fluent/compat/exec_util.rb +144 -0
  81. data/lib/fluent/compat/file_util.rb +54 -0
  82. data/lib/fluent/compat/filter.rb +68 -0
  83. data/lib/fluent/compat/formatter.rb +117 -0
  84. data/lib/fluent/compat/formatter_utils.rb +85 -0
  85. data/lib/fluent/compat/handle_tag_and_time_mixin.rb +62 -0
  86. data/lib/fluent/compat/handle_tag_name_mixin.rb +53 -0
  87. data/lib/fluent/compat/input.rb +49 -0
  88. data/lib/fluent/compat/output.rb +721 -0
  89. data/lib/fluent/compat/output_chain.rb +60 -0
  90. data/lib/fluent/compat/parser.rb +310 -0
  91. data/lib/fluent/compat/parser_utils.rb +40 -0
  92. data/lib/fluent/compat/propagate_default.rb +62 -0
  93. data/lib/fluent/compat/record_filter_mixin.rb +34 -0
  94. data/lib/fluent/compat/set_tag_key_mixin.rb +50 -0
  95. data/lib/fluent/compat/set_time_key_mixin.rb +69 -0
  96. data/lib/fluent/compat/socket_util.rb +165 -0
  97. data/lib/fluent/compat/string_util.rb +34 -0
  98. data/lib/fluent/compat/structured_format_mixin.rb +26 -0
  99. data/lib/fluent/compat/type_converter.rb +90 -0
  100. data/lib/fluent/config/basic_parser.rb +122 -0
  101. data/lib/fluent/config/configure_proxy.rb +424 -0
  102. data/lib/fluent/config/dsl.rb +152 -0
  103. data/lib/fluent/config/element.rb +265 -0
  104. data/lib/fluent/config/error.rb +44 -0
  105. data/lib/fluent/config/literal_parser.rb +305 -0
  106. data/lib/fluent/config/parser.rb +119 -0
  107. data/lib/fluent/config/section.rb +272 -0
  108. data/lib/fluent/config/types.rb +257 -0
  109. data/lib/fluent/config/v1_parser.rb +200 -0
  110. data/lib/fluent/config/yaml_parser/fluent_value.rb +47 -0
  111. data/lib/fluent/config/yaml_parser/loader.rb +124 -0
  112. data/lib/fluent/config/yaml_parser/parser.rb +179 -0
  113. data/lib/fluent/config/yaml_parser/section_builder.rb +107 -0
  114. data/lib/fluent/config/yaml_parser.rb +56 -0
  115. data/lib/fluent/config.rb +89 -0
  116. data/lib/fluent/configurable.rb +202 -0
  117. data/lib/fluent/counter/base_socket.rb +44 -0
  118. data/lib/fluent/counter/client.rb +297 -0
  119. data/lib/fluent/counter/error.rb +86 -0
  120. data/lib/fluent/counter/mutex_hash.rb +163 -0
  121. data/lib/fluent/counter/server.rb +273 -0
  122. data/lib/fluent/counter/store.rb +205 -0
  123. data/lib/fluent/counter/validator.rb +145 -0
  124. data/lib/fluent/counter.rb +23 -0
  125. data/lib/fluent/daemon.rb +14 -0
  126. data/lib/fluent/daemonizer.rb +88 -0
  127. data/lib/fluent/engine.rb +269 -0
  128. data/lib/fluent/env.rb +45 -0
  129. data/lib/fluent/error.rb +37 -0
  130. data/lib/fluent/event.rb +369 -0
  131. data/lib/fluent/event_router.rb +315 -0
  132. data/lib/fluent/ext_monitor_require.rb +28 -0
  133. data/lib/fluent/file_wrapper.rb +137 -0
  134. data/lib/fluent/filter.rb +21 -0
  135. data/lib/fluent/fluent_log_event_router.rb +139 -0
  136. data/lib/fluent/formatter.rb +23 -0
  137. data/lib/fluent/input.rb +21 -0
  138. data/lib/fluent/label.rb +46 -0
  139. data/lib/fluent/load.rb +33 -0
  140. data/lib/fluent/log/console_adapter.rb +66 -0
  141. data/lib/fluent/log.rb +775 -0
  142. data/lib/fluent/match.rb +187 -0
  143. data/lib/fluent/mixin.rb +31 -0
  144. data/lib/fluent/msgpack_factory.rb +111 -0
  145. data/lib/fluent/oj_options.rb +61 -0
  146. data/lib/fluent/output.rb +29 -0
  147. data/lib/fluent/output_chain.rb +23 -0
  148. data/lib/fluent/parser.rb +23 -0
  149. data/lib/fluent/plugin/bare_output.rb +88 -0
  150. data/lib/fluent/plugin/base.rb +219 -0
  151. data/lib/fluent/plugin/buf_file.rb +256 -0
  152. data/lib/fluent/plugin/buf_file_single.rb +272 -0
  153. data/lib/fluent/plugin/buf_memory.rb +34 -0
  154. data/lib/fluent/plugin/buffer/chunk.rb +313 -0
  155. data/lib/fluent/plugin/buffer/file_chunk.rb +432 -0
  156. data/lib/fluent/plugin/buffer/file_single_chunk.rb +325 -0
  157. data/lib/fluent/plugin/buffer/memory_chunk.rb +91 -0
  158. data/lib/fluent/plugin/buffer.rb +1063 -0
  159. data/lib/fluent/plugin/compressable.rb +87 -0
  160. data/lib/fluent/plugin/exec_util.rb +22 -0
  161. data/lib/fluent/plugin/extractor.rb +132 -0
  162. data/lib/fluent/plugin/file_util.rb +22 -0
  163. data/lib/fluent/plugin/filter.rb +119 -0
  164. data/lib/fluent/plugin/filter_grep.rb +189 -0
  165. data/lib/fluent/plugin/filter_parser.rb +124 -0
  166. data/lib/fluent/plugin/filter_record_transformer.rb +325 -0
  167. data/lib/fluent/plugin/filter_stdout.rb +53 -0
  168. data/lib/fluent/plugin/formatter.rb +75 -0
  169. data/lib/fluent/plugin/formatter_csv.rb +92 -0
  170. data/lib/fluent/plugin/formatter_hash.rb +35 -0
  171. data/lib/fluent/plugin/formatter_json.rb +62 -0
  172. data/lib/fluent/plugin/formatter_ltsv.rb +44 -0
  173. data/lib/fluent/plugin/formatter_msgpack.rb +33 -0
  174. data/lib/fluent/plugin/formatter_out_file.rb +55 -0
  175. data/lib/fluent/plugin/formatter_single_value.rb +36 -0
  176. data/lib/fluent/plugin/formatter_stdout.rb +76 -0
  177. data/lib/fluent/plugin/formatter_tsv.rb +40 -0
  178. data/lib/fluent/plugin/in_debug_agent.rb +71 -0
  179. data/lib/fluent/plugin/in_dummy.rb +18 -0
  180. data/lib/fluent/plugin/in_exec.rb +124 -0
  181. data/lib/fluent/plugin/in_forward.rb +489 -0
  182. data/lib/fluent/plugin/in_gc_stat.rb +72 -0
  183. data/lib/fluent/plugin/in_http.rb +737 -0
  184. data/lib/fluent/plugin/in_monitor_agent.rb +406 -0
  185. data/lib/fluent/plugin/in_object_space.rb +93 -0
  186. data/lib/fluent/plugin/in_sample.rb +148 -0
  187. data/lib/fluent/plugin/in_syslog.rb +346 -0
  188. data/lib/fluent/plugin/in_tail/compatibility.rb +111 -0
  189. data/lib/fluent/plugin/in_tail/dir_watcher.rb +713 -0
  190. data/lib/fluent/plugin/in_tail/group_watch.rb +204 -0
  191. data/lib/fluent/plugin/in_tail/io_handler.rb +391 -0
  192. data/lib/fluent/plugin/in_tail/line_feeder.rb +230 -0
  193. data/lib/fluent/plugin/in_tail/position_file.rb +269 -0
  194. data/lib/fluent/plugin/in_tail/stat_watcher.rb +52 -0
  195. data/lib/fluent/plugin/in_tail/tail_watcher.rb +276 -0
  196. data/lib/fluent/plugin/in_tail/worker_pool.rb +298 -0
  197. data/lib/fluent/plugin/in_tail.rb +917 -0
  198. data/lib/fluent/plugin/in_tcp.rb +230 -0
  199. data/lib/fluent/plugin/in_udp.rb +101 -0
  200. data/lib/fluent/plugin/in_unix.rb +197 -0
  201. data/lib/fluent/plugin/input.rb +71 -0
  202. data/lib/fluent/plugin/metrics.rb +119 -0
  203. data/lib/fluent/plugin/metrics_local.rb +96 -0
  204. data/lib/fluent/plugin/multi_output.rb +179 -0
  205. data/lib/fluent/plugin/out_buffer.rb +40 -0
  206. data/lib/fluent/plugin/out_copy.rb +120 -0
  207. data/lib/fluent/plugin/out_exec.rb +105 -0
  208. data/lib/fluent/plugin/out_exec_filter.rb +319 -0
  209. data/lib/fluent/plugin/out_file.rb +371 -0
  210. data/lib/fluent/plugin/out_forward/ack_handler.rb +176 -0
  211. data/lib/fluent/plugin/out_forward/connection_manager.rb +131 -0
  212. data/lib/fluent/plugin/out_forward/error.rb +28 -0
  213. data/lib/fluent/plugin/out_forward/failure_detector.rb +84 -0
  214. data/lib/fluent/plugin/out_forward/handshake_protocol.rb +125 -0
  215. data/lib/fluent/plugin/out_forward/load_balancer.rb +114 -0
  216. data/lib/fluent/plugin/out_forward/socket_cache.rb +177 -0
  217. data/lib/fluent/plugin/out_forward.rb +865 -0
  218. data/lib/fluent/plugin/out_http.rb +419 -0
  219. data/lib/fluent/plugin/out_null.rb +74 -0
  220. data/lib/fluent/plugin/out_relabel.rb +32 -0
  221. data/lib/fluent/plugin/out_roundrobin.rb +84 -0
  222. data/lib/fluent/plugin/out_secondary_file.rb +148 -0
  223. data/lib/fluent/plugin/out_stdout.rb +81 -0
  224. data/lib/fluent/plugin/out_stream.rb +130 -0
  225. data/lib/fluent/plugin/output.rb +1688 -0
  226. data/lib/fluent/plugin/owned_by_mixin.rb +41 -0
  227. data/lib/fluent/plugin/parser.rb +274 -0
  228. data/lib/fluent/plugin/parser_apache.rb +28 -0
  229. data/lib/fluent/plugin/parser_apache2.rb +88 -0
  230. data/lib/fluent/plugin/parser_apache_error.rb +26 -0
  231. data/lib/fluent/plugin/parser_csv.rb +124 -0
  232. data/lib/fluent/plugin/parser_json.rb +118 -0
  233. data/lib/fluent/plugin/parser_ltsv.rb +49 -0
  234. data/lib/fluent/plugin/parser_msgpack.rb +72 -0
  235. data/lib/fluent/plugin/parser_multiline.rb +152 -0
  236. data/lib/fluent/plugin/parser_nginx.rb +28 -0
  237. data/lib/fluent/plugin/parser_none.rb +36 -0
  238. data/lib/fluent/plugin/parser_regexp.rb +68 -0
  239. data/lib/fluent/plugin/parser_syslog.rb +543 -0
  240. data/lib/fluent/plugin/parser_tsv.rb +47 -0
  241. data/lib/fluent/plugin/sd_file.rb +157 -0
  242. data/lib/fluent/plugin/sd_srv.rb +135 -0
  243. data/lib/fluent/plugin/sd_static.rb +58 -0
  244. data/lib/fluent/plugin/service_discovery.rb +65 -0
  245. data/lib/fluent/plugin/socket_util.rb +22 -0
  246. data/lib/fluent/plugin/storage.rb +84 -0
  247. data/lib/fluent/plugin/storage_local.rb +166 -0
  248. data/lib/fluent/plugin/string_util.rb +22 -0
  249. data/lib/fluent/plugin.rb +206 -0
  250. data/lib/fluent/plugin_helper/cert_option.rb +199 -0
  251. data/lib/fluent/plugin_helper/child_process.rb +369 -0
  252. data/lib/fluent/plugin_helper/compat_parameters.rb +343 -0
  253. data/lib/fluent/plugin_helper/counter.rb +51 -0
  254. data/lib/fluent/plugin_helper/event_emitter.rb +112 -0
  255. data/lib/fluent/plugin_helper/event_loop.rb +170 -0
  256. data/lib/fluent/plugin_helper/extract.rb +104 -0
  257. data/lib/fluent/plugin_helper/formatter.rb +147 -0
  258. data/lib/fluent/plugin_helper/http_server/app.rb +81 -0
  259. data/lib/fluent/plugin_helper/http_server/methods.rb +35 -0
  260. data/lib/fluent/plugin_helper/http_server/request.rb +53 -0
  261. data/lib/fluent/plugin_helper/http_server/router.rb +54 -0
  262. data/lib/fluent/plugin_helper/http_server/server.rb +116 -0
  263. data/lib/fluent/plugin_helper/http_server/ssl_context_builder.rb +41 -0
  264. data/lib/fluent/plugin_helper/http_server.rb +129 -0
  265. data/lib/fluent/plugin_helper/inject.rb +154 -0
  266. data/lib/fluent/plugin_helper/metrics.rb +136 -0
  267. data/lib/fluent/plugin_helper/parser.rb +147 -0
  268. data/lib/fluent/plugin_helper/record_accessor.rb +207 -0
  269. data/lib/fluent/plugin_helper/retry_state.rb +219 -0
  270. data/lib/fluent/plugin_helper/server.rb +840 -0
  271. data/lib/fluent/plugin_helper/service_discovery/manager.rb +146 -0
  272. data/lib/fluent/plugin_helper/service_discovery/round_robin_balancer.rb +43 -0
  273. data/lib/fluent/plugin_helper/service_discovery.rb +125 -0
  274. data/lib/fluent/plugin_helper/socket.rb +288 -0
  275. data/lib/fluent/plugin_helper/socket_option.rb +98 -0
  276. data/lib/fluent/plugin_helper/storage.rb +349 -0
  277. data/lib/fluent/plugin_helper/thread.rb +180 -0
  278. data/lib/fluent/plugin_helper/timer.rb +92 -0
  279. data/lib/fluent/plugin_helper.rb +75 -0
  280. data/lib/fluent/plugin_id.rb +93 -0
  281. data/lib/fluent/process.rb +22 -0
  282. data/lib/fluent/registry.rb +117 -0
  283. data/lib/fluent/root_agent.rb +468 -0
  284. data/lib/fluent/rpc.rb +95 -0
  285. data/lib/fluent/source_only_buffer_agent.rb +102 -0
  286. data/lib/fluent/static_config_analysis.rb +195 -0
  287. data/lib/fluent/supervisor.rb +1347 -0
  288. data/lib/fluent/system_config.rb +213 -0
  289. data/lib/fluent/test/base.rb +83 -0
  290. data/lib/fluent/test/driver/base.rb +231 -0
  291. data/lib/fluent/test/driver/base_owned.rb +83 -0
  292. data/lib/fluent/test/driver/base_owner.rb +135 -0
  293. data/lib/fluent/test/driver/event_feeder.rb +98 -0
  294. data/lib/fluent/test/driver/filter.rb +61 -0
  295. data/lib/fluent/test/driver/formatter.rb +30 -0
  296. data/lib/fluent/test/driver/input.rb +31 -0
  297. data/lib/fluent/test/driver/multi_output.rb +53 -0
  298. data/lib/fluent/test/driver/output.rb +102 -0
  299. data/lib/fluent/test/driver/parser.rb +30 -0
  300. data/lib/fluent/test/driver/storage.rb +30 -0
  301. data/lib/fluent/test/driver/test_event_router.rb +45 -0
  302. data/lib/fluent/test/filter_test.rb +77 -0
  303. data/lib/fluent/test/formatter_test.rb +65 -0
  304. data/lib/fluent/test/helpers.rb +138 -0
  305. data/lib/fluent/test/input_test.rb +174 -0
  306. data/lib/fluent/test/log.rb +79 -0
  307. data/lib/fluent/test/output_test.rb +156 -0
  308. data/lib/fluent/test/parser_test.rb +70 -0
  309. data/lib/fluent/test/startup_shutdown.rb +44 -0
  310. data/lib/fluent/test.rb +61 -0
  311. data/lib/fluent/time.rb +513 -0
  312. data/lib/fluent/timezone.rb +171 -0
  313. data/lib/fluent/tls.rb +105 -0
  314. data/lib/fluent/unique_id.rb +39 -0
  315. data/lib/fluent/variable_store.rb +40 -0
  316. data/lib/fluent/version.rb +21 -0
  317. data/lib/fluent/win32api.rb +38 -0
  318. data/lib/fluent/winsvc.rb +130 -0
  319. data/templates/new_gem/.gitignore +8 -0
  320. data/templates/new_gem/Gemfile +3 -0
  321. data/templates/new_gem/README.md.erb +43 -0
  322. data/templates/new_gem/Rakefile +13 -0
  323. data/templates/new_gem/fluent-plugin.gemspec.erb +28 -0
  324. data/templates/new_gem/lib/fluent/plugin/filter.rb.erb +14 -0
  325. data/templates/new_gem/lib/fluent/plugin/formatter.rb.erb +14 -0
  326. data/templates/new_gem/lib/fluent/plugin/input.rb.erb +11 -0
  327. data/templates/new_gem/lib/fluent/plugin/output.rb.erb +11 -0
  328. data/templates/new_gem/lib/fluent/plugin/parser.rb.erb +15 -0
  329. data/templates/new_gem/lib/fluent/plugin/storage.rb.erb +40 -0
  330. data/templates/new_gem/test/helper.rb.erb +7 -0
  331. data/templates/new_gem/test/plugin/test_filter.rb.erb +18 -0
  332. data/templates/new_gem/test/plugin/test_formatter.rb.erb +18 -0
  333. data/templates/new_gem/test/plugin/test_input.rb.erb +18 -0
  334. data/templates/new_gem/test/plugin/test_output.rb.erb +18 -0
  335. data/templates/new_gem/test/plugin/test_parser.rb.erb +18 -0
  336. data/templates/new_gem/test/plugin/test_storage.rb.erb +18 -0
  337. data/templates/plugin_config_formatter/param.md-compact.erb +25 -0
  338. data/templates/plugin_config_formatter/param.md-table.erb +10 -0
  339. data/templates/plugin_config_formatter/param.md.erb +34 -0
  340. data/templates/plugin_config_formatter/section.md.erb +12 -0
  341. metadata +996 -0
@@ -0,0 +1,865 @@
1
+ #
2
+ # Fluentd
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'fluent/output'
18
+ require 'fluent/config/error'
19
+ require 'fluent/clock'
20
+ require 'fluent/tls'
21
+ require 'base64'
22
+ require 'forwardable'
23
+
24
+ require 'fluent/compat/socket_util'
25
+ require 'fluent/plugin/out_forward/handshake_protocol'
26
+ require 'fluent/plugin/out_forward/load_balancer'
27
+ require 'fluent/plugin/out_forward/socket_cache'
28
+ require 'fluent/plugin/out_forward/failure_detector'
29
+ require 'fluent/plugin/out_forward/error'
30
+ require 'fluent/plugin/out_forward/connection_manager'
31
+ require 'fluent/plugin/out_forward/ack_handler'
32
+
33
+ module Fluent::Plugin
34
+ class ForwardOutput < Output
35
+ Fluent::Plugin.register_output('forward', self)
36
+
37
+ helpers :socket, :server, :timer, :thread, :compat_parameters, :service_discovery
38
+
39
+ LISTEN_PORT = 24224
40
+
41
+ desc 'The transport protocol.'
42
+ config_param :transport, :enum, list: [:tcp, :tls], default: :tcp
43
+ # TODO: TLS session cache/tickets
44
+
45
+ desc 'The timeout time when sending event logs.'
46
+ config_param :send_timeout, :time, default: 60
47
+ desc 'The timeout time for socket connect'
48
+ config_param :connect_timeout, :time, default: nil
49
+ # TODO: add linger_timeout, recv_timeout
50
+
51
+ desc 'The protocol to use for heartbeats (default is the same with "transport").'
52
+ config_param :heartbeat_type, :enum, list: [:transport, :tcp, :udp, :none], default: :transport
53
+ desc 'The interval of the heartbeat packer.'
54
+ config_param :heartbeat_interval, :time, default: 1
55
+ desc 'The wait time before accepting a server fault recovery.'
56
+ config_param :recover_wait, :time, default: 10
57
+ desc 'The hard timeout used to detect server failure.'
58
+ config_param :hard_timeout, :time, default: 60
59
+ desc 'The threshold parameter used to detect server faults.'
60
+ config_param :phi_threshold, :integer, default: 16
61
+ desc 'Use the "Phi accrual failure detector" to detect server failure.'
62
+ config_param :phi_failure_detector, :bool, default: true
63
+
64
+ desc 'Change the protocol to at-least-once.'
65
+ config_param :require_ack_response, :bool, default: false # require in_forward to respond with ack
66
+
67
+ ## The reason of default value of :ack_response_timeout:
68
+ # Linux default tcp_syn_retries is 5 (in many environment)
69
+ # 3 + 6 + 12 + 24 + 48 + 96 -> 189 (sec)
70
+ desc 'This option is used when require_ack_response is true.'
71
+ config_param :ack_response_timeout, :time, default: 190
72
+
73
+ desc 'The interval while reading data from server'
74
+ config_param :read_interval_msec, :integer, default: 50 # 50ms
75
+ desc 'Reading data size from server'
76
+ config_param :read_length, :size, default: 512 # 512bytes
77
+
78
+ desc 'Set TTL to expire DNS cache in seconds.'
79
+ config_param :expire_dns_cache, :time, default: nil # 0 means disable cache
80
+ desc 'Enable client-side DNS round robin.'
81
+ config_param :dns_round_robin, :bool, default: false # heartbeat_type 'udp' is not available for this
82
+
83
+ desc 'Ignore DNS resolution and errors at startup time.'
84
+ config_param :ignore_network_errors_at_startup, :bool, default: false
85
+
86
+ desc 'Verify that a connection can be made with one of out_forward nodes at the time of startup.'
87
+ config_param :verify_connection_at_startup, :bool, default: false
88
+
89
+ desc 'Compress buffered data.'
90
+ config_param :compress, :enum, list: [:text, :gzip, :zstd], default: :text
91
+
92
+ desc 'The default version of TLS transport.'
93
+ config_param :tls_version, :enum, list: Fluent::TLS::SUPPORTED_VERSIONS, default: Fluent::TLS::DEFAULT_VERSION
94
+ desc 'The cipher configuration of TLS transport.'
95
+ config_param :tls_ciphers, :string, default: Fluent::TLS::CIPHERS_DEFAULT
96
+ desc 'Skip all verification of certificates or not.'
97
+ config_param :tls_insecure_mode, :bool, default: false
98
+ desc 'Allow self signed certificates or not.'
99
+ config_param :tls_allow_self_signed_cert, :bool, default: false
100
+ desc 'Verify hostname of servers and certificates or not in TLS transport.'
101
+ config_param :tls_verify_hostname, :bool, default: true
102
+ desc 'The additional CA certificate path for TLS.'
103
+ config_param :tls_ca_cert_path, :array, value_type: :string, default: nil
104
+ desc 'The additional certificate path for TLS.'
105
+ config_param :tls_cert_path, :array, value_type: :string, default: nil
106
+ desc 'The client certificate path for TLS.'
107
+ config_param :tls_client_cert_path, :string, default: nil
108
+ desc 'The client private key path for TLS.'
109
+ config_param :tls_client_private_key_path, :string, default: nil
110
+ desc 'The client private key passphrase for TLS.'
111
+ config_param :tls_client_private_key_passphrase, :string, default: nil, secret: true
112
+ desc 'The certificate thumbprint for searching from Windows system certstore.'
113
+ config_param :tls_cert_thumbprint, :string, default: nil, secret: true
114
+ desc 'The certificate logical store name on Windows system certstore.'
115
+ config_param :tls_cert_logical_store_name, :string, default: nil
116
+ desc 'Enable to use certificate enterprise store on Windows system certstore.'
117
+ config_param :tls_cert_use_enterprise_store, :bool, default: true
118
+ desc "Enable keepalive connection."
119
+ config_param :keepalive, :bool, default: false
120
+ desc "Expired time of keepalive. Default value is nil, which means to keep connection as long as possible"
121
+ config_param :keepalive_timeout, :time, default: nil
122
+ desc 'Check the remote connection is still available by sending a keepalive packet if this value is true.'
123
+ config_param :send_keepalive_packet, :bool, default: false
124
+
125
+ config_section :security, required: false, multi: false do
126
+ desc 'The hostname'
127
+ config_param :self_hostname, :string
128
+ desc 'Shared key for authentication'
129
+ config_param :shared_key, :string, secret: true
130
+ end
131
+
132
+ config_section :server, param_name: :servers do
133
+ desc "The IP address or host name of the server."
134
+ config_param :host, :string
135
+ desc "The name of the server. Used for logging and certificate verification in TLS transport (when host is address)."
136
+ config_param :name, :string, default: nil
137
+ desc "The port number of the host."
138
+ config_param :port, :integer, default: LISTEN_PORT
139
+ desc "The shared key per server."
140
+ config_param :shared_key, :string, default: nil, secret: true
141
+ desc "The username for authentication."
142
+ config_param :username, :string, default: ''
143
+ desc "The password for authentication."
144
+ config_param :password, :string, default: '', secret: true
145
+ desc "Marks a node as the standby node for an Active-Standby model between Fluentd nodes."
146
+ config_param :standby, :bool, default: false
147
+ desc "The load balancing weight."
148
+ config_param :weight, :integer, default: 60
149
+ end
150
+
151
+ attr_reader :nodes
152
+
153
+ config_param :port, :integer, default: LISTEN_PORT, obsoleted: "User <server> section instead."
154
+ config_param :host, :string, default: nil, obsoleted: "Use <server> section instead."
155
+
156
+ config_section :buffer do
157
+ config_set_default :chunk_keys, ["tag"]
158
+ end
159
+
160
+ attr_reader :read_interval, :recover_sample_size
161
+
162
+ def initialize
163
+ super
164
+
165
+ @nodes = [] #=> [Node]
166
+ @loop = nil
167
+ @thread = nil
168
+
169
+ @usock = nil
170
+ @keep_alive_watcher_interval = 5 # TODO
171
+ @suspend_flush = false
172
+ @healthy_nodes_count_metrics = nil
173
+ @registered_nodes_count_metrics = nil
174
+ end
175
+
176
+ def configure(conf)
177
+ compat_parameters_convert(conf, :buffer, default_chunk_key: 'tag')
178
+
179
+ super
180
+
181
+ unless @chunk_key_tag
182
+ raise Fluent::ConfigError, "buffer chunk key must include 'tag' for forward output"
183
+ end
184
+
185
+ @read_interval = @read_interval_msec / 1000.0
186
+ @recover_sample_size = @recover_wait / @heartbeat_interval
187
+
188
+ if @heartbeat_type == :tcp
189
+ log.warn "'heartbeat_type tcp' is deprecated. use 'transport' instead."
190
+ @heartbeat_type = :transport
191
+ end
192
+
193
+ if @dns_round_robin && @heartbeat_type == :udp
194
+ raise Fluent::ConfigError, "forward output heartbeat type must be 'transport' or 'none' to use dns_round_robin option"
195
+ end
196
+
197
+ if @transport == :tls
198
+ # socket helper adds CA cert or signed certificate to same cert store internally so unify it in this place.
199
+ if @tls_cert_path && !@tls_cert_path.empty?
200
+ @tls_ca_cert_path = @tls_cert_path
201
+ end
202
+ if @tls_ca_cert_path && !@tls_ca_cert_path.empty?
203
+ @tls_ca_cert_path.each do |path|
204
+ raise Fluent::ConfigError, "specified cert path does not exist:#{path}" unless File.exist?(path)
205
+ raise Fluent::ConfigError, "specified cert path is not readable:#{path}" unless File.readable?(path)
206
+ end
207
+ end
208
+
209
+ if @tls_insecure_mode
210
+ log.warn "TLS transport is configured in insecure way"
211
+ @tls_verify_hostname = false
212
+ @tls_allow_self_signed_cert = true
213
+ end
214
+
215
+ if Fluent.windows?
216
+ if (@tls_cert_path || @tls_ca_cert_path) && @tls_cert_logical_store_name
217
+ raise Fluent::ConfigError, "specified both cert path and tls_cert_logical_store_name is not permitted"
218
+ end
219
+ else
220
+ raise Fluent::ConfigError, "This parameter is for only Windows" if @tls_cert_logical_store_name
221
+ raise Fluent::ConfigError, "This parameter is for only Windows" if @tls_cert_thumbprint
222
+ end
223
+ end
224
+
225
+ @ack_handler = @require_ack_response ? AckHandler.new(timeout: @ack_response_timeout, log: @log, read_length: @read_length) : nil
226
+ socket_cache = @keepalive ? SocketCache.new(@keepalive_timeout, @log) : nil
227
+ @connection_manager = ConnectionManager.new(
228
+ log: @log,
229
+ secure: !!@security,
230
+ connection_factory: method(:create_transfer_socket),
231
+ socket_cache: socket_cache,
232
+ )
233
+
234
+ service_discovery_configure(
235
+ :out_forward_service_discovery_watcher,
236
+ static_default_service_directive: 'server',
237
+ load_balancer: LoadBalancer.new(log),
238
+ custom_build_method: method(:build_node),
239
+ )
240
+
241
+ service_discovery_services.each do |server|
242
+ # it's only for test
243
+ @nodes << server
244
+ unless @heartbeat_type == :none
245
+ begin
246
+ server.validate_host_resolution!
247
+ rescue => e
248
+ raise unless @ignore_network_errors_at_startup
249
+ log.warn "failed to resolve node name when configured", server: (server.name || server.host), error: e
250
+ server.disable!
251
+ end
252
+ end
253
+ end
254
+
255
+ unless @as_secondary
256
+ if @buffer.compress == :text
257
+ @buffer.compress = @compress
258
+ else
259
+ if @compress == :text
260
+ log.info "buffer is compressed. If you also want to save the bandwidth of a network, Add `compress` configuration in <match>"
261
+ elsif @compress != @buffer.compress
262
+ raise Fluent::ConfigError, "You cannot specify different compression formats for Buffer (Buffer: #{@buffer.compress}, Self: #{@compress})"
263
+ end
264
+ end
265
+ end
266
+
267
+ if service_discovery_services.empty?
268
+ raise Fluent::ConfigError, "forward output plugin requires at least one node is required. Add <server> or <service_discovery>"
269
+ end
270
+
271
+ if !@keepalive && @keepalive_timeout
272
+ log.warn('The value of keepalive_timeout is ignored. if you want to use keepalive, please add `keepalive true` to your conf.')
273
+ end
274
+
275
+ if @send_keepalive_packet && !@keepalive
276
+ raise Fluent::ConfigError, "'send_keepalive_packet' is enabled but 'keepalive' is not. Enable 'keepalive' to use TCP keepalive."
277
+ end
278
+
279
+ raise Fluent::ConfigError, "ack_response_timeout must be a positive integer" if @ack_response_timeout < 1
280
+
281
+ if @compress == :zstd
282
+ log.warn "zstd compression feature is an experimental new feature supported since v1.19.0." +
283
+ " Please make sure that the destination server also supports this feature before using it." +
284
+ " in_forward plugin for Fluentd supports it since v1.19.0."
285
+ end
286
+
287
+ @healthy_nodes_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "healthy_nodes_count", help_text: "Number of count healthy nodes", prefer_gauge: true)
288
+ @registered_nodes_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "registered_nodes_count", help_text: "Number of count registered nodes", prefer_gauge: true)
289
+ end
290
+
291
+ def multi_workers_ready?
292
+ true
293
+ end
294
+
295
+ def prefer_delayed_commit
296
+ @require_ack_response
297
+ end
298
+
299
+ def overwrite_delayed_commit_timeout
300
+ # Output#start sets @delayed_commit_timeout by @buffer_config.delayed_commit_timeout
301
+ # But it should be overwritten by ack_response_timeout to rollback chunks after timeout
302
+ if @delayed_commit_timeout != @ack_response_timeout
303
+ log.info "delayed_commit_timeout is overwritten by ack_response_timeout"
304
+ @delayed_commit_timeout = @ack_response_timeout + 2 # minimum ack_reader IO.select interval is 1s
305
+ end
306
+ end
307
+
308
+ def start
309
+ super
310
+
311
+ unless @heartbeat_type == :none
312
+ if @heartbeat_type == :udp
313
+ @usock = socket_create_udp(service_discovery_services.first.host, service_discovery_services.first.port, nonblock: true)
314
+ server_create_udp(:out_forward_heartbeat_receiver, 0, socket: @usock, max_bytes: @read_length, &method(:on_udp_heartbeat_response_recv))
315
+ end
316
+ timer_execute(:out_forward_heartbeat_request, @heartbeat_interval, &method(:on_heartbeat_timer))
317
+ end
318
+
319
+ if @require_ack_response
320
+ overwrite_delayed_commit_timeout
321
+ thread_create(:out_forward_receiving_ack, &method(:ack_reader))
322
+ end
323
+
324
+ if @verify_connection_at_startup
325
+ service_discovery_services.each do |node|
326
+ begin
327
+ node.verify_connection
328
+ rescue StandardError => e
329
+ log.fatal "forward's connection setting error: #{e.message}"
330
+ raise Fluent::UnrecoverableError, e.message
331
+ end
332
+ end
333
+ end
334
+
335
+ if @keepalive
336
+ timer_execute(:out_forward_keep_alived_socket_watcher, @keep_alive_watcher_interval, &method(:on_purge_obsolete_socks))
337
+ end
338
+ end
339
+
340
+ def close
341
+ if @usock
342
+ # close socket and ignore errors: this socket will not be used anyway.
343
+ @usock.close rescue nil
344
+ end
345
+
346
+ super
347
+ end
348
+
349
+ def stop
350
+ super
351
+
352
+ if @keepalive
353
+ @connection_manager.stop
354
+ end
355
+ end
356
+
357
+ def before_shutdown
358
+ super
359
+ @suspend_flush = true
360
+ end
361
+
362
+ def after_shutdown
363
+ last_ack if @require_ack_response
364
+ super
365
+ end
366
+
367
+ def try_flush
368
+ return if @require_ack_response && @suspend_flush
369
+ super
370
+ end
371
+
372
+ def last_ack
373
+ overwrite_delayed_commit_timeout
374
+ ack_check(ack_select_interval)
375
+ end
376
+
377
+ def write(chunk)
378
+ return if chunk.empty?
379
+ tag = chunk.metadata.tag
380
+
381
+ service_discovery_select_service { |node| node.send_data(tag, chunk) }
382
+ end
383
+
384
+ def try_write(chunk)
385
+ log.trace "writing a chunk to destination", chunk_id: dump_unique_id_hex(chunk.unique_id)
386
+ if chunk.empty?
387
+ commit_write(chunk.unique_id)
388
+ return
389
+ end
390
+ tag = chunk.metadata.tag
391
+ service_discovery_select_service { |node| node.send_data(tag, chunk) }
392
+ last_ack if @require_ack_response && @suspend_flush
393
+ end
394
+
395
+ def create_transfer_socket(host, port, hostname, &block)
396
+ case @transport
397
+ when :tls
398
+ socket_create_tls(
399
+ host, port,
400
+ version: @tls_version,
401
+ ciphers: @tls_ciphers,
402
+ insecure: @tls_insecure_mode,
403
+ verify_fqdn: @tls_verify_hostname,
404
+ fqdn: hostname,
405
+ allow_self_signed_cert: @tls_allow_self_signed_cert,
406
+ cert_paths: @tls_ca_cert_path,
407
+ cert_path: @tls_client_cert_path,
408
+ private_key_path: @tls_client_private_key_path,
409
+ private_key_passphrase: @tls_client_private_key_passphrase,
410
+ cert_thumbprint: @tls_cert_thumbprint,
411
+ cert_logical_store_name: @tls_cert_logical_store_name,
412
+ cert_use_enterprise_store: @tls_cert_use_enterprise_store,
413
+
414
+ # Enabling SO_LINGER causes tcp port exhaustion on Windows.
415
+ # This is because dynamic ports are only 16384 (from 49152 to 65535) and
416
+ # expiring SO_LINGER enabled ports should wait 4 minutes
417
+ # where set by TcpTimeDelay. Its default value is 4 minutes.
418
+ # So, we should disable SO_LINGER on Windows to prevent flood of waiting ports.
419
+ linger_timeout: Fluent.windows? ? nil : @send_timeout,
420
+ send_timeout: @send_timeout,
421
+ recv_timeout: @ack_response_timeout,
422
+ connect_timeout: @connect_timeout,
423
+ send_keepalive_packet: @send_keepalive_packet,
424
+ &block
425
+ )
426
+ when :tcp
427
+ socket_create_tcp(
428
+ host, port,
429
+ linger_timeout: @send_timeout,
430
+ send_timeout: @send_timeout,
431
+ recv_timeout: @ack_response_timeout,
432
+ connect_timeout: @connect_timeout,
433
+ send_keepalive_packet: @send_keepalive_packet,
434
+ &block
435
+ )
436
+ else
437
+ raise "BUG: unknown transport protocol #{@transport}"
438
+ end
439
+ end
440
+
441
+ def statistics
442
+ stats = super
443
+ services = service_discovery_services
444
+ @healthy_nodes_count_metrics.set(0)
445
+ @registered_nodes_count_metrics.set(services.size)
446
+ services.each do |s|
447
+ if s.available?
448
+ @healthy_nodes_count_metrics.inc
449
+ end
450
+ end
451
+
452
+ stats = {
453
+ 'output' => stats["output"].merge({
454
+ 'healthy_nodes_count' => @healthy_nodes_count_metrics.get,
455
+ 'registered_nodes_count' => @registered_nodes_count_metrics.get,
456
+ })
457
+ }
458
+ stats
459
+ end
460
+
461
+ # MessagePack FixArray length is 3
462
+ FORWARD_HEADER = [0x93].pack('C').freeze
463
+ def forward_header
464
+ FORWARD_HEADER
465
+ end
466
+
467
+ private
468
+
469
+ def build_node(server)
470
+ name = server.name || "#{server.host}:#{server.port}"
471
+ log.info "adding forwarding server '#{name}'", host: server.host, port: server.port, weight: server.weight, plugin_id: plugin_id
472
+
473
+ failure = FailureDetector.new(@heartbeat_interval, @hard_timeout, Time.now.to_i.to_f)
474
+ if @heartbeat_type == :none
475
+ NoneHeartbeatNode.new(self, server, failure: failure, connection_manager: @connection_manager, ack_handler: @ack_handler)
476
+ else
477
+ Node.new(self, server, failure: failure, connection_manager: @connection_manager, ack_handler: @ack_handler)
478
+ end
479
+ end
480
+
481
+ def on_heartbeat_timer
482
+ need_rebuild = false
483
+ service_discovery_services.each do |n|
484
+ begin
485
+ log.trace "sending heartbeat", host: n.host, port: n.port, heartbeat_type: @heartbeat_type
486
+ n.usock = @usock if @usock
487
+ need_rebuild = n.send_heartbeat || need_rebuild
488
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::EINTR, Errno::ECONNREFUSED, Errno::ETIMEDOUT => e
489
+ log.debug "failed to send heartbeat packet", host: n.host, port: n.port, heartbeat_type: @heartbeat_type, error: e
490
+ rescue => e
491
+ log.debug "unexpected error happen during heartbeat", host: n.host, port: n.port, heartbeat_type: @heartbeat_type, error: e
492
+ end
493
+
494
+ need_rebuild = n.tick || need_rebuild
495
+ end
496
+
497
+ if need_rebuild
498
+ service_discovery_rebalance
499
+ end
500
+ end
501
+
502
+ def on_udp_heartbeat_response_recv(data, sock)
503
+ sockaddr = Socket.pack_sockaddr_in(sock.remote_port, sock.remote_host)
504
+ if node = service_discovery_services.find { |n| n.sockaddr == sockaddr }
505
+ # log.trace "heartbeat arrived", name: node.name, host: node.host, port: node.port
506
+ if node.heartbeat
507
+ service_discovery_rebalance
508
+ end
509
+ else
510
+ log.warn("Unknown heartbeat response received from #{sock.remote_host}:#{sock.remote_port}. It may service out")
511
+ end
512
+ end
513
+
514
+ def on_purge_obsolete_socks
515
+ @connection_manager.purge_obsolete_socks
516
+ end
517
+
518
+ def ack_select_interval
519
+ if @delayed_commit_timeout > 3
520
+ 1
521
+ else
522
+ @delayed_commit_timeout / 3.0
523
+ end
524
+ end
525
+
526
+ def ack_reader
527
+ select_interval = ack_select_interval
528
+
529
+ while thread_current_running?
530
+ ack_check(select_interval)
531
+ end
532
+ end
533
+
534
+ def ack_check(select_interval)
535
+ @ack_handler.collect_response(select_interval) do |chunk_id, node, sock, result|
536
+ case result
537
+ when AckHandler::Result::SUCCESS
538
+ @connection_manager.close(sock)
539
+ commit_write(chunk_id)
540
+ when AckHandler::Result::FAILED
541
+ # The ack timed out or the peer closed the connection. A keepalive
542
+ # socket may still have an in-flight ack for this chunk, so drop it
543
+ # instead of returning it to the reuse pool; otherwise a late ack
544
+ # could later be read against a chunk sent on the reused socket (#4057).
545
+ @connection_manager.discard(sock)
546
+ node&.disable!
547
+ rollback_write(chunk_id, update_retry: false) if chunk_id
548
+ when AckHandler::Result::CHUNKID_UNMATCHED
549
+ # The ack read from this socket belongs to a different chunk than the
550
+ # one tracked for it: the keepalive connection's ack stream is out of
551
+ # sync (e.g. a stale ack left over from before an aggregator restart).
552
+ # Discard the socket so the following acks are not each offset by one,
553
+ # which would otherwise flood the log with mismatch warnings (#4057).
554
+ @connection_manager.discard(sock)
555
+ rollback_write(chunk_id, update_retry: false)
556
+ else
557
+ @connection_manager.close(sock)
558
+ log.warn("BUG: invalid status #{result} #{chunk_id}")
559
+
560
+ if chunk_id
561
+ rollback_write(chunk_id, update_retry: false)
562
+ end
563
+ end
564
+ end
565
+ end
566
+
567
+ class Node
568
+ extend Forwardable
569
+ def_delegators :@server, :discovery_id, :host, :port, :name, :weight, :standby
570
+
571
+ # @param connection_manager [Fluent::Plugin::ForwardOutput::ConnectionManager]
572
+ # @param ack_handler [Fluent::Plugin::ForwardOutput::AckHandler]
573
+ def initialize(sender, server, failure:, connection_manager:, ack_handler:)
574
+ @sender = sender
575
+ @log = sender.log
576
+ @compress = sender.compress
577
+ @server = server
578
+
579
+ @name = server.name
580
+ @host = server.host
581
+ @port = server.port
582
+ @weight = server.weight
583
+ @standby = server.standby
584
+ @failure = failure
585
+ @available = true
586
+
587
+ # @hostname is used for certificate verification & TLS SNI
588
+ host_is_hostname = !(IPAddr.new(@host) rescue false)
589
+ @hostname = case
590
+ when host_is_hostname then @host
591
+ when @name then @name
592
+ else nil
593
+ end
594
+
595
+ @usock = nil
596
+
597
+ @handshake = HandshakeProtocol.new(
598
+ log: @log,
599
+ hostname: sender.security&.self_hostname,
600
+ shared_key: server.shared_key || sender.security&.shared_key || '',
601
+ password: server.password || '',
602
+ username: server.username || '',
603
+ )
604
+
605
+ @resolved_host = nil
606
+ @resolved_time = 0
607
+ @resolved_once = false
608
+
609
+ @connection_manager = connection_manager
610
+ @ack_handler = ack_handler
611
+ end
612
+
613
+ attr_accessor :usock
614
+
615
+ attr_reader :state
616
+ attr_reader :sockaddr # used by on_udp_heartbeat_response_recv
617
+ attr_reader :failure # for test
618
+
619
+ def validate_host_resolution!
620
+ resolved_host
621
+ end
622
+
623
+ def available?
624
+ @available
625
+ end
626
+
627
+ def disable!
628
+ @available = false
629
+ end
630
+
631
+ def standby?
632
+ @standby
633
+ end
634
+
635
+ def verify_connection
636
+ connect do |sock, ri|
637
+ ensure_established_connection(sock, ri)
638
+ end
639
+ end
640
+
641
+ def establish_connection(sock, ri)
642
+ start_time = Fluent::Clock.now
643
+ timeout = @sender.hard_timeout
644
+
645
+ while ri.state != :established
646
+ # Check for timeout to prevent infinite loop
647
+ if Fluent::Clock.now - start_time > timeout
648
+ @log.warn "handshake timeout after #{timeout}s", host: @host, port: @port
649
+ disable!
650
+ break
651
+ end
652
+
653
+ begin
654
+ # TODO: On Ruby 2.2 or earlier, read_nonblock doesn't work expectedly.
655
+ # We need rewrite around here using new socket/server plugin helper.
656
+ buf = sock.read_nonblock(@sender.read_length)
657
+ if buf.empty?
658
+ sleep @sender.read_interval
659
+ next
660
+ end
661
+ Fluent::MessagePackFactory.msgpack_unpacker.feed_each(buf) do |data|
662
+ if @handshake.invoke(sock, ri, data) == :established
663
+ @log.debug "connection established", host: @host, port: @port
664
+ end
665
+ end
666
+ rescue IO::WaitReadable
667
+ # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN, it is extended by IO::WaitReadable.
668
+ # So IO::WaitReadable can be used to rescue the exceptions for retrying read_nonblock.
669
+ # https//docs.ruby-lang.org/en/2.3.0/IO.html#method-i-read_nonblock
670
+ sleep @sender.read_interval unless ri.state == :established
671
+ rescue SystemCallError => e
672
+ @log.warn "disconnected by error", host: @host, port: @port, error: e
673
+ disable!
674
+ break
675
+ rescue EOFError
676
+ @log.warn "disconnected", host: @host, port: @port
677
+ disable!
678
+ break
679
+ rescue HeloError => e
680
+ @log.warn "received invalid helo message from #{@name}"
681
+ disable!
682
+ break
683
+ rescue PingpongError => e
684
+ @log.warn "connection refused to #{@name || @host}: #{e.message}"
685
+ disable!
686
+ break
687
+ end
688
+ end
689
+ end
690
+
691
+ def send_data_actual(sock, tag, chunk)
692
+ option = { 'size' => chunk.size, 'compressed' => @compress }
693
+ option['chunk'] = Base64.encode64(chunk.unique_id) if @ack_handler
694
+
695
+ # https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#packedforward-mode
696
+ # out_forward always uses str32 type for entries.
697
+ # str16 can store only 64kbytes, and it should be much smaller than buffer chunk size.
698
+
699
+ tag = tag.dup.force_encoding(Encoding::UTF_8)
700
+
701
+ sock.write @sender.forward_header # array, size=3
702
+ sock.write tag.to_msgpack # 1. tag: String (str)
703
+ chunk.open(compressed: @compress) do |chunk_io|
704
+ entries = [0xdb, chunk_io.size].pack('CN')
705
+ sock.write entries.force_encoding(Encoding::UTF_8) # 2. entries: String (str32)
706
+ IO.copy_stream(chunk_io, sock) # writeRawBody(packed_es)
707
+ end
708
+ sock.write option.to_msgpack # 3. option: Hash(map)
709
+
710
+ # TODO: use bin32 for non-utf8 content(entries) when old msgpack-ruby (0.5.x or earlier) not supported
711
+ end
712
+
713
+ def send_data(tag, chunk)
714
+ ack = @ack_handler && @ack_handler.create_ack(chunk.unique_id, self)
715
+ connect(nil, ack: ack) do |sock, ri|
716
+ ensure_established_connection(sock, ri)
717
+ send_data_actual(sock, tag, chunk)
718
+ end
719
+
720
+ heartbeat(false)
721
+ nil
722
+ end
723
+
724
+ # FORWARD_TCP_HEARTBEAT_DATA = FORWARD_HEADER + ''.to_msgpack + [].to_msgpack
725
+ #
726
+ # @return [Boolean] return true if it needs to rebuild nodes
727
+ def send_heartbeat
728
+ begin
729
+ dest_addr = resolved_host
730
+ @resolved_once = true
731
+ rescue ::SocketError => e
732
+ if !@resolved_once && @sender.ignore_network_errors_at_startup
733
+ @log.warn "failed to resolve node name in heartbeating", server: @name || @host, error: e
734
+ return false
735
+ end
736
+ raise
737
+ end
738
+
739
+ case @sender.heartbeat_type
740
+ when :transport
741
+ connect(dest_addr) do |sock, ri|
742
+ ensure_established_connection(sock, ri)
743
+
744
+ ## don't send any data to not cause a compatibility problem
745
+ # sock.write FORWARD_TCP_HEARTBEAT_DATA
746
+
747
+ # successful tcp connection establishment is considered as valid heartbeat.
748
+ # When heartbeat is succeeded after detached, return true. It rebuilds weight array.
749
+ heartbeat(true)
750
+ end
751
+ when :udp
752
+ @usock.send "\0", 0, Socket.pack_sockaddr_in(@port, dest_addr)
753
+ # response is going to receive at on_udp_heartbeat_response_recv
754
+ false
755
+ when :none # :none doesn't use this class
756
+ raise "BUG: heartbeat_type none must not use Node"
757
+ else
758
+ raise "BUG: unknown heartbeat_type '#{@sender.heartbeat_type}'"
759
+ end
760
+ end
761
+
762
+ def resolved_host
763
+ case @sender.expire_dns_cache
764
+ when 0
765
+ # cache is disabled
766
+ resolve_dns!
767
+
768
+ when nil
769
+ # persistent cache
770
+ @resolved_host ||= resolve_dns!
771
+
772
+ else
773
+ now = Fluent::EventTime.now
774
+ rh = @resolved_host
775
+ if !rh || now - @resolved_time >= @sender.expire_dns_cache
776
+ rh = @resolved_host = resolve_dns!
777
+ @resolved_time = now
778
+ end
779
+ rh
780
+ end
781
+ end
782
+
783
+ def resolve_dns!
784
+ addrinfo_list = Socket.getaddrinfo(@host, @port, nil, Socket::SOCK_STREAM)
785
+ addrinfo = @sender.dns_round_robin ? addrinfo_list.sample : addrinfo_list.first
786
+ @sockaddr = Socket.pack_sockaddr_in(addrinfo[1], addrinfo[3]) # used by on_udp_heartbeat_response_recv
787
+ addrinfo[3]
788
+ end
789
+ private :resolve_dns!
790
+
791
+ def tick
792
+ now = Time.now.to_f
793
+ unless available?
794
+ if @failure.hard_timeout?(now)
795
+ @failure.clear
796
+ end
797
+ return nil
798
+ end
799
+
800
+ if @failure.hard_timeout?(now)
801
+ @log.warn "detached forwarding server '#{@name}'", host: @host, port: @port, hard_timeout: true
802
+ disable!
803
+ @resolved_host = nil # expire cached host
804
+ @failure.clear
805
+ return true
806
+ end
807
+
808
+ if @sender.phi_failure_detector
809
+ phi = @failure.phi(now)
810
+ if phi > @sender.phi_threshold
811
+ @log.warn "detached forwarding server '#{@name}'", host: @host, port: @port, phi: phi, phi_threshold: @sender.phi_threshold
812
+ disable!
813
+ @resolved_host = nil # expire cached host
814
+ @failure.clear
815
+ return true
816
+ end
817
+ end
818
+ false
819
+ end
820
+
821
+ def heartbeat(detect=true)
822
+ now = Time.now.to_f
823
+ @failure.add(now)
824
+ if detect && !available? && @failure.sample_size > @sender.recover_sample_size
825
+ @available = true
826
+ @log.warn "recovered forwarding server '#{@name}'", host: @host, port: @port
827
+ true
828
+ else
829
+ nil
830
+ end
831
+ end
832
+
833
+ private
834
+
835
+ def ensure_established_connection(sock, request_info)
836
+ if request_info.state != :established
837
+ establish_connection(sock, request_info)
838
+
839
+ if request_info.state != :established
840
+ raise ConnectionClosedError, "failed to establish connection with node #{@name}"
841
+ end
842
+ end
843
+ end
844
+
845
+ def connect(host = nil, ack: false, &block)
846
+ @connection_manager.connect(host: host || resolved_host, port: port, hostname: @hostname, ack: ack, &block)
847
+ end
848
+ end
849
+
850
+ # Override Node to disable heartbeat
851
+ class NoneHeartbeatNode < Node
852
+ def available?
853
+ true
854
+ end
855
+
856
+ def tick
857
+ false
858
+ end
859
+
860
+ def heartbeat(detect=true)
861
+ true
862
+ end
863
+ end
864
+ end
865
+ end