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,1347 @@
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 'fileutils'
18
+ require 'open3'
19
+ require 'pathname'
20
+ require 'find'
21
+ require 'set'
22
+
23
+ require 'fluent/config'
24
+ require 'fluent/counter'
25
+ require 'fluent/env'
26
+ require 'fluent/engine'
27
+ require 'fluent/error'
28
+ require 'fluent/log'
29
+ require 'fluent/plugin'
30
+ require 'fluent/rpc'
31
+ require 'fluent/system_config'
32
+ require 'fluent/msgpack_factory'
33
+ require 'fluent/variable_store'
34
+ require 'serverengine'
35
+
36
+ if Fluent.windows?
37
+ require 'win32/ipc'
38
+ require 'win32/event'
39
+ end
40
+
41
+ module Fluent
42
+ module ServerModule
43
+ def before_run
44
+ @fluentd_conf = config[:fluentd_conf]
45
+ @rpc_endpoint = nil
46
+ @rpc_server = nil
47
+ @counter = nil
48
+ @socket_manager_server = nil
49
+ @starting_new_supervisor_with_zero_downtime = false
50
+ @new_supervisor_pid = nil
51
+ start_in_parallel = ENV.key?("FLUENT_RUNNING_IN_PARALLEL_WITH_OLD")
52
+ @zero_downtime_restart_mutex = Mutex.new
53
+
54
+ @fluentd_lock_dir = Dir.mktmpdir("fluentd-lock-")
55
+ ENV['FLUENTD_LOCK_DIR'] = @fluentd_lock_dir
56
+
57
+ if config[:rpc_endpoint] and not start_in_parallel
58
+ @rpc_endpoint = config[:rpc_endpoint]
59
+ @enable_get_dump = config[:enable_get_dump]
60
+ run_rpc_server
61
+ end
62
+
63
+ if Fluent.windows?
64
+ install_windows_event_handler
65
+ else
66
+ install_supervisor_signal_handlers
67
+ end
68
+
69
+ if counter = config[:counter_server] and not start_in_parallel
70
+ run_counter_server(counter)
71
+ end
72
+
73
+ if config[:disable_shared_socket]
74
+ $log.info "shared socket for multiple workers is disabled"
75
+ elsif start_in_parallel
76
+ begin
77
+ raise "[BUG] SERVERENGINE_SOCKETMANAGER_PATH env var must exist when starting in parallel" unless ENV.key?('SERVERENGINE_SOCKETMANAGER_PATH')
78
+ @socket_manager_server = ServerEngine::SocketManager::Server.share_sockets_with_another_server(ENV['SERVERENGINE_SOCKETMANAGER_PATH'])
79
+ $log.info "zero-downtime-restart: took over the shared sockets", path: ENV['SERVERENGINE_SOCKETMANAGER_PATH']
80
+ rescue => e
81
+ $log.error "zero-downtime-restart: cancel sequence because failed to take over the shared sockets", error: e
82
+ raise
83
+ end
84
+ else
85
+ @socket_manager_server = ServerEngine::SocketManager::Server.open
86
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = @socket_manager_server.path.to_s
87
+ end
88
+
89
+ stop_parallel_old_supervisor_after_delay if start_in_parallel
90
+ end
91
+
92
+ def after_run
93
+ stop_windows_event_thread if Fluent.windows?
94
+ stop_rpc_server if @rpc_endpoint
95
+ stop_counter_server if @counter
96
+ cleanup_lock_dir
97
+ Fluent::Supervisor.cleanup_socketmanager_path unless @starting_new_supervisor_with_zero_downtime
98
+ ensure
99
+ notify_new_supervisor_that_old_one_has_stopped if @starting_new_supervisor_with_zero_downtime
100
+ end
101
+
102
+ def cleanup_lock_dir
103
+ begin
104
+ Dir.each_child(@fluentd_lock_dir) do |name|
105
+ FileUtils.rm_f(File.join(@fluentd_lock_dir, name)) if File.fnmatch?("fluentd-*.lock", name)
106
+ end
107
+ rescue Errno::ENOENT
108
+ # Directory is already missing. Fall through and let rmdir below
109
+ # fail in the same way as the current implementation.
110
+ end
111
+ FileUtils.rmdir(@fluentd_lock_dir)
112
+ end
113
+
114
+ def run_rpc_server
115
+ @rpc_server = RPC::Server.new(@rpc_endpoint, $log)
116
+
117
+ # built-in RPC for signals
118
+ @rpc_server.mount_proc('/api/processes.interruptWorkers') { |req, res|
119
+ $log.debug "fluentd RPC got /api/processes.interruptWorkers request"
120
+ Process.kill :INT, Process.pid
121
+ nil
122
+ }
123
+ @rpc_server.mount_proc('/api/processes.killWorkers') { |req, res|
124
+ $log.debug "fluentd RPC got /api/processes.killWorkers request"
125
+ Process.kill :TERM, Process.pid
126
+ nil
127
+ }
128
+ @rpc_server.mount_proc('/api/processes.flushBuffersAndKillWorkers') { |req, res|
129
+ $log.debug "fluentd RPC got /api/processes.flushBuffersAndKillWorkers request"
130
+ if Fluent.windows?
131
+ supervisor_sigusr1_handler
132
+ stop(true)
133
+ else
134
+ Process.kill :USR1, Process.pid
135
+ Process.kill :TERM, Process.pid
136
+ end
137
+ nil
138
+ }
139
+ unless Fluent.windows?
140
+ @rpc_server.mount_proc('/api/processes.zeroDowntimeRestart') { |req, res|
141
+ $log.debug "fluentd RPC got /api/processes.zeroDowntimeRestart request"
142
+ Process.kill :USR2, Process.pid
143
+ nil
144
+ }
145
+ end
146
+ @rpc_server.mount_proc('/api/plugins.flushBuffers') { |req, res|
147
+ $log.debug "fluentd RPC got /api/plugins.flushBuffers request"
148
+ if Fluent.windows?
149
+ supervisor_sigusr1_handler
150
+ else
151
+ Process.kill :USR1, Process.pid
152
+ end
153
+ nil
154
+ }
155
+ @rpc_server.mount_proc('/api/config.reload') { |req, res|
156
+ $log.debug "fluentd RPC got /api/config.reload request"
157
+ if Fluent.windows?
158
+ # restart worker with auto restarting by killing
159
+ kill_worker
160
+ else
161
+ Process.kill :HUP, Process.pid
162
+ end
163
+ nil
164
+ }
165
+ @rpc_server.mount_proc('/api/config.dump') { |req, res|
166
+ $log.debug "fluentd RPC got /api/config.dump request"
167
+ $log.info "dump in-memory config"
168
+ supervisor_dump_config_handler
169
+ nil
170
+ }
171
+
172
+ @rpc_server.mount_proc('/api/config.gracefulReload') { |req, res|
173
+ $log.debug "fluentd RPC got /api/config.gracefulReload request"
174
+ graceful_reload
175
+ nil
176
+ }
177
+
178
+ if @enable_get_dump
179
+ @rpc_server.mount_proc('/api/config.getDump') { |req, res|
180
+ $log.debug "fluentd RPC got /api/config.getDump request"
181
+ $log.info "get dump in-memory config via HTTP"
182
+ res.body = supervisor_get_dump_config_handler
183
+ [nil, nil, res]
184
+ }
185
+ end
186
+
187
+ @rpc_server.start
188
+ end
189
+
190
+ def stop_rpc_server
191
+ @rpc_server&.shutdown
192
+ end
193
+
194
+ def run_counter_server(counter_conf)
195
+ @counter = Fluent::Counter::Server.new(
196
+ counter_conf.scope,
197
+ {host: counter_conf.bind, port: counter_conf.port, log: $log, path: counter_conf.backup_path}
198
+ )
199
+ @counter.start
200
+ end
201
+
202
+ def stop_counter_server
203
+ @counter.stop
204
+ end
205
+
206
+ def stop_parallel_old_supervisor_after_delay
207
+ Thread.new do
208
+ # Delay to wait the new workers to start up.
209
+ # Even if it takes a long time to start the new workers and stop the old Fluentd first,
210
+ # it is no problem because the socket buffer works, as long as the capacity is not exceeded.
211
+ sleep 10
212
+ old_pid = ENV["FLUENT_RUNNING_IN_PARALLEL_WITH_OLD"]&.to_i
213
+ if old_pid
214
+ $log.info "zero-downtime-restart: stop the old supervisor"
215
+ Process.kill :TERM, old_pid
216
+ end
217
+ rescue => e
218
+ $log.warn "zero-downtime-restart: failed to stop the old supervisor." +
219
+ " If the old one does not exist, please send SIGWINCH to this new process to start to work fully." +
220
+ " If it exists, something went wrong. Please kill the old one manually.",
221
+ error: e
222
+ end
223
+ end
224
+
225
+ def notify_new_supervisor_that_old_one_has_stopped
226
+ if config[:pid_path]
227
+ new_pid = File.read(config[:pid_path]).to_i
228
+ else
229
+ raise "[BUG] new_supervisor_pid is not saved" unless @new_supervisor_pid
230
+ new_pid = @new_supervisor_pid
231
+ end
232
+
233
+ $log.info "zero-downtime-restart: notify the new supervisor (pid: #{new_pid}) that old one has stopped"
234
+ Process.kill :WINCH, new_pid
235
+ rescue => e
236
+ $log.error(
237
+ "zero-downtime-restart: failed to notify the new supervisor." +
238
+ " Please send SIGWINCH to the new supervisor process manually" +
239
+ " if it does not start to work fully.",
240
+ error: e
241
+ )
242
+ end
243
+
244
+ def install_supervisor_signal_handlers
245
+ return if Fluent.windows?
246
+
247
+ trap :HUP do
248
+ $log.debug "fluentd supervisor process get SIGHUP"
249
+ supervisor_sighup_handler
250
+ end
251
+
252
+ trap :USR1 do
253
+ $log.debug "fluentd supervisor process get SIGUSR1"
254
+ supervisor_sigusr1_handler
255
+ end
256
+
257
+ trap :USR2 do
258
+ $log.debug 'fluentd supervisor process got SIGUSR2'
259
+ if Fluent.windows?
260
+ graceful_reload
261
+ else
262
+ zero_downtime_restart
263
+ end
264
+ end
265
+
266
+ trap :WINCH do
267
+ $log.debug 'fluentd supervisor process got SIGWINCH'
268
+ cancel_source_only
269
+ end
270
+ end
271
+
272
+ if Fluent.windows?
273
+ # Override some methods of ServerEngine::MultiSpawnWorker
274
+ # Since Fluentd's Supervisor doesn't use ServerEngine's HUP, USR1 and USR2
275
+ # handlers (see install_supervisor_signal_handlers), they should be
276
+ # disabled also on Windows, just send commands to workers instead.
277
+ def restart(graceful)
278
+ @monitors.each do |m|
279
+ m.send_command(graceful ? "GRACEFUL_RESTART\n" : "IMMEDIATE_RESTART\n")
280
+ end
281
+ end
282
+
283
+ def reload
284
+ @monitors.each do |m|
285
+ m.send_command("RELOAD\n")
286
+ end
287
+ end
288
+ end
289
+
290
+ def install_windows_event_handler
291
+ return unless Fluent.windows?
292
+
293
+ @pid_signame = "fluentd_#{Process.pid}"
294
+ @signame = config[:signame]
295
+
296
+ Thread.new do
297
+ ipc = Win32::Ipc.new(nil)
298
+ events = [
299
+ {win32_event: Win32::Event.new("#{@pid_signame}_STOP_EVENT_THREAD"), action: :stop_event_thread},
300
+ {win32_event: Win32::Event.new("#{@pid_signame}"), action: :stop},
301
+ {win32_event: Win32::Event.new("#{@pid_signame}_HUP"), action: :hup},
302
+ {win32_event: Win32::Event.new("#{@pid_signame}_USR1"), action: :usr1},
303
+ {win32_event: Win32::Event.new("#{@pid_signame}_USR2"), action: :usr2},
304
+ {win32_event: Win32::Event.new("#{@pid_signame}_CONT"), action: :cont},
305
+ ]
306
+ if @signame
307
+ signame_events = [
308
+ {win32_event: Win32::Event.new("#{@signame}"), action: :stop},
309
+ {win32_event: Win32::Event.new("#{@signame}_HUP"), action: :hup},
310
+ {win32_event: Win32::Event.new("#{@signame}_USR1"), action: :usr1},
311
+ {win32_event: Win32::Event.new("#{@signame}_USR2"), action: :usr2},
312
+ {win32_event: Win32::Event.new("#{@signame}_CONT"), action: :cont},
313
+ ]
314
+ events.concat(signame_events)
315
+ end
316
+ begin
317
+ loop do
318
+ infinite = 0xFFFFFFFF
319
+ ipc_idx = ipc.wait_any(events.map {|e| e[:win32_event]}, infinite)
320
+ event_idx = ipc_idx - 1
321
+
322
+ if event_idx >= 0 && event_idx < events.length
323
+ $log.debug("Got Win32 event \"#{events[event_idx][:win32_event].name}\"")
324
+ else
325
+ $log.warn("Unexpected return value of Win32::Ipc#wait_any: #{ipc_idx}")
326
+ end
327
+ case events[event_idx][:action]
328
+ when :stop
329
+ stop(true)
330
+ when :hup
331
+ supervisor_sighup_handler
332
+ when :usr1
333
+ supervisor_sigusr1_handler
334
+ when :usr2
335
+ graceful_reload
336
+ when :cont
337
+ supervisor_dump_handler_for_windows
338
+ when :stop_event_thread
339
+ break
340
+ end
341
+ end
342
+ ensure
343
+ events.each { |event| event[:win32_event].close }
344
+ end
345
+ end
346
+ end
347
+
348
+ def stop_windows_event_thread
349
+ if Fluent.windows?
350
+ ev = Win32::Event.open("#{@pid_signame}_STOP_EVENT_THREAD")
351
+ ev.set
352
+ ev.close
353
+ end
354
+ end
355
+
356
+ def supervisor_sighup_handler
357
+ kill_worker
358
+ end
359
+
360
+ def supervisor_sigusr1_handler
361
+ reopen_log
362
+ send_signal_to_workers(:USR1)
363
+ end
364
+
365
+ def graceful_reload
366
+ conf = nil
367
+ t = Thread.new do
368
+ $log.info 'Reloading new config'
369
+
370
+ # Validate that loading config is valid at first
371
+ conf = Fluent::Config.build(
372
+ config_path: config[:config_path],
373
+ encoding: config[:conf_encoding],
374
+ additional_config: config[:inline_config],
375
+ use_v1_config: config[:use_v1_config],
376
+ type: config[:config_file_type],
377
+ )
378
+
379
+ Fluent::VariableStore.try_to_reset do
380
+ Fluent::Engine.reload_config(conf, supervisor: true)
381
+ end
382
+ end
383
+
384
+ t.report_on_exception = false # Error is handled by myself
385
+ t.join
386
+
387
+ reopen_log
388
+ send_signal_to_workers(:USR2)
389
+ @fluentd_conf = conf.to_s
390
+ rescue => e
391
+ $log.error "Failed to reload config file: #{e}"
392
+ end
393
+
394
+ def zero_downtime_restart
395
+ Thread.new do
396
+ @zero_downtime_restart_mutex.synchronize do
397
+ $log.info "start zero-downtime-restart sequence"
398
+
399
+ if @starting_new_supervisor_with_zero_downtime
400
+ $log.warn "zero-downtime-restart: canceled because it is already starting"
401
+ Thread.exit
402
+ end
403
+ if ENV.key?("FLUENT_RUNNING_IN_PARALLEL_WITH_OLD")
404
+ $log.warn "zero-downtime-restart: canceled because the previous sequence is still running"
405
+ Thread.exit
406
+ end
407
+
408
+ @starting_new_supervisor_with_zero_downtime = true
409
+ commands = [ServerEngine.ruby_bin_path, $0] + ARGV
410
+ env_to_add = {
411
+ "SERVERENGINE_SOCKETMANAGER_INTERNAL_TOKEN" => ServerEngine::SocketManager::INTERNAL_TOKEN,
412
+ "FLUENT_RUNNING_IN_PARALLEL_WITH_OLD" => "#{Process.pid}",
413
+ }
414
+ pid = Process.spawn(env_to_add, commands.join(" "))
415
+ @new_supervisor_pid = pid unless config[:daemonize]
416
+
417
+ if config[:daemonize]
418
+ Thread.new(pid) do |pid|
419
+ _, status = Process.wait2(pid)
420
+ # check if `ServerEngine::Daemon#daemonize_with_double_fork` succeeded or not
421
+ unless status.success?
422
+ @starting_new_supervisor_with_zero_downtime = false
423
+ $log.error "zero-downtime-restart: failed because new supervisor exits unexpectedly"
424
+ end
425
+ end
426
+ else
427
+ Thread.new(pid) do |pid|
428
+ _, status = Process.wait2(pid)
429
+ @starting_new_supervisor_with_zero_downtime = false
430
+ $log.error "zero-downtime-restart: failed because new supervisor exits unexpectedly", status: status
431
+ end
432
+ end
433
+ end
434
+ rescue => e
435
+ $log.error "zero-downtime-restart: failed", error: e
436
+ @starting_new_supervisor_with_zero_downtime = false
437
+ end
438
+ end
439
+
440
+ def cancel_source_only
441
+ if ENV.key?("FLUENT_RUNNING_IN_PARALLEL_WITH_OLD")
442
+ if config[:rpc_endpoint]
443
+ begin
444
+ @rpc_endpoint = config[:rpc_endpoint]
445
+ @enable_get_dump = config[:enable_get_dump]
446
+ run_rpc_server
447
+ rescue => e
448
+ $log.error "failed to start RPC server", error: e
449
+ end
450
+ end
451
+
452
+ if counter = config[:counter_server]
453
+ begin
454
+ run_counter_server(counter)
455
+ rescue => e
456
+ $log.error "failed to start counter server", error: e
457
+ end
458
+ end
459
+
460
+ $log.info "zero-downtime-restart: done all sequences, now new processes start to work fully"
461
+ ENV.delete("FLUENT_RUNNING_IN_PARALLEL_WITH_OLD")
462
+ end
463
+
464
+ send_signal_to_workers(:WINCH)
465
+ end
466
+
467
+ def supervisor_dump_handler_for_windows
468
+ # As for UNIX-like, SIGCONT signal to each process makes the process output its dump-file,
469
+ # and it is implemented before the implementation of the function for Windows.
470
+ # It is possible to trap SIGCONT and handle it here also on UNIX-like,
471
+ # but for backward compatibility, this handler is currently for a Windows-only.
472
+ raise "[BUG] This function is for Windows ONLY." unless Fluent.windows?
473
+
474
+ Thread.new do
475
+ begin
476
+ FluentSigdump.dump_windows
477
+ rescue => e
478
+ $log.error "failed to dump: #{e}"
479
+ end
480
+ end
481
+
482
+ send_signal_to_workers(:CONT)
483
+ rescue => e
484
+ $log.error "failed to dump: #{e}"
485
+ end
486
+
487
+ def kill_worker
488
+ if config[:worker_pid]
489
+ pids = config[:worker_pid].clone
490
+ config[:worker_pid].clear
491
+ pids.each_value do |pid|
492
+ if Fluent.windows?
493
+ Process.kill :KILL, pid
494
+ else
495
+ Process.kill :TERM, pid
496
+ end
497
+ end
498
+ end
499
+ end
500
+
501
+ def supervisor_dump_config_handler
502
+ $log.info @fluentd_conf
503
+ end
504
+
505
+ def supervisor_get_dump_config_handler
506
+ { conf: @fluentd_conf }
507
+ end
508
+
509
+ def dump
510
+ super unless @stop
511
+ end
512
+
513
+ private
514
+
515
+ def reopen_log
516
+ if $log
517
+ # Creating new thread due to mutex can't lock
518
+ # in main thread during trap context
519
+ Thread.new do
520
+ $log.reopen!
521
+ end
522
+ end
523
+ end
524
+
525
+ def send_signal_to_workers(signal)
526
+ return unless config[:worker_pid]
527
+
528
+ if Fluent.windows?
529
+ send_command_to_workers(signal)
530
+ else
531
+ config[:worker_pid].each_value do |pid|
532
+ # don't rescue Errno::ESRCH here (invalid status)
533
+ Process.kill(signal, pid)
534
+ end
535
+ end
536
+ end
537
+
538
+ def send_command_to_workers(signal)
539
+ # Use SeverEngine's CommandSender on Windows
540
+ case signal
541
+ when :HUP
542
+ restart(false)
543
+ when :USR1
544
+ restart(true)
545
+ when :USR2
546
+ reload
547
+ when :CONT
548
+ dump_all_windows_workers
549
+ end
550
+ end
551
+
552
+ def dump_all_windows_workers
553
+ @monitors.each do |m|
554
+ m.send_command("DUMP\n")
555
+ end
556
+ end
557
+ end
558
+
559
+ module WorkerModule
560
+ def spawn(process_manager)
561
+ main_cmd = config[:main_cmd]
562
+ env = {
563
+ 'SERVERENGINE_WORKER_ID' => @worker_id.to_i.to_s,
564
+ 'FLUENT_INSTANCE_ID' => Fluent::INSTANCE_ID,
565
+ }
566
+ @pm = process_manager.spawn(env, *main_cmd)
567
+ end
568
+
569
+ def after_start
570
+ (config[:worker_pid] ||= {})[@worker_id] = @pm.pid
571
+ end
572
+
573
+ def dump
574
+ super unless @stop
575
+ end
576
+ end
577
+
578
+ class Supervisor
579
+ def self.serverengine_config(params = {})
580
+ # ServerEngine's "daemonize" option is boolean, and path of pid file is brought by "pid_path"
581
+ pid_path = params['daemonize']
582
+ daemonize = !!params['daemonize']
583
+
584
+ se_config = {
585
+ worker_type: 'spawn',
586
+ workers: params['workers'],
587
+ log_stdin: false,
588
+ log_stdout: false,
589
+ log_stderr: false,
590
+ enable_heartbeat: true,
591
+ auto_heartbeat: false,
592
+ unrecoverable_exit_codes: [2],
593
+ stop_immediately_at_unrecoverable_exit: true,
594
+ root_dir: params['root_dir'],
595
+ logger: $log,
596
+ log: $log&.out,
597
+ log_level: params['log_level'],
598
+ chuser: params['chuser'],
599
+ chgroup: params['chgroup'],
600
+ chumask: params['chumask'].is_a?(Integer) ? params['chumask'] : params['chumask']&.to_i(8),
601
+ daemonize: daemonize,
602
+ rpc_endpoint: params['rpc_endpoint'],
603
+ counter_server: params['counter_server'],
604
+ enable_get_dump: params['enable_get_dump'],
605
+ windows_daemon_cmdline: [ServerEngine.ruby_bin_path,
606
+ File.join(File.dirname(__FILE__), 'daemon.rb'),
607
+ ServerModule.name,
608
+ WorkerModule.name,
609
+ JSON.dump(params)],
610
+ command_sender: Fluent.windows? ? "pipe" : "signal",
611
+ config_path: params['fluentd_conf_path'],
612
+ fluentd_conf: params['fluentd_conf'],
613
+ conf_encoding: params['conf_encoding'],
614
+ inline_config: params['inline_config'],
615
+ use_v1_config: params['use_v1_config'],
616
+ config_file_type: params['config_file_type']&.to_sym,
617
+ main_cmd: params['main_cmd'],
618
+ signame: params['signame'],
619
+ disable_shared_socket: params['disable_shared_socket'],
620
+ restart_worker_interval: params['restart_worker_interval'],
621
+ }
622
+ se_config[:pid_path] = pid_path if daemonize
623
+
624
+ se_config
625
+ end
626
+
627
+ def self.default_options
628
+ {
629
+ config_path: Fluent::DEFAULT_CONFIG_PATH,
630
+ plugin_dirs: [Fluent::DEFAULT_PLUGIN_DIR],
631
+ log_level: Fluent::Log::LEVEL_INFO,
632
+ log_path: nil,
633
+ daemonize: nil,
634
+ libs: [],
635
+ setup_path: nil,
636
+ chuser: nil,
637
+ chgroup: nil,
638
+ chumask: "0",
639
+ root_dir: nil,
640
+ suppress_interval: 0,
641
+ suppress_repeated_stacktrace: true,
642
+ ignore_repeated_log_interval: nil,
643
+ without_source: nil,
644
+ with_source_only: nil,
645
+ enable_input_metrics: true,
646
+ enable_size_metrics: nil,
647
+ use_v1_config: true,
648
+ strict_config_value: nil,
649
+ supervise: true,
650
+ standalone_worker: false,
651
+ signame: nil,
652
+ conf_encoding: 'utf-8',
653
+ disable_shared_socket: nil,
654
+ config_file_type: :guess,
655
+ }
656
+ end
657
+
658
+ def self.cleanup_socketmanager_path
659
+ return if Fluent.windows?
660
+ return unless ENV.key?('SERVERENGINE_SOCKETMANAGER_PATH')
661
+
662
+ FileUtils.rm_f(ENV['SERVERENGINE_SOCKETMANAGER_PATH'])
663
+ end
664
+
665
+ def initialize(cl_opt)
666
+ @cl_opt = cl_opt
667
+ opt = self.class.default_options.merge(cl_opt)
668
+
669
+ @config_file_type = opt[:config_file_type]
670
+ @daemonize = opt[:daemonize]
671
+ @standalone_worker= opt[:standalone_worker]
672
+ @config_path = opt[:config_path]
673
+ @inline_config = opt[:inline_config]
674
+ @use_v1_config = opt[:use_v1_config]
675
+ @conf_encoding = opt[:conf_encoding]
676
+ @show_plugin_config = opt[:show_plugin_config]
677
+ @libs = opt[:libs]
678
+ @plugin_dirs = opt[:plugin_dirs]
679
+ @chgroup = opt[:chgroup]
680
+ @chuser = opt[:chuser]
681
+ @chumask = opt[:chumask]
682
+ @signame = opt[:signame]
683
+
684
+ # TODO: `@log_path`, `@log_rotate_age` and `@log_rotate_size` should be removed
685
+ # since it should be merged with SystemConfig in `build_system_config()`.
686
+ # We should always use `system_config.log.path`, `system_config.log.rotate_age`
687
+ # and `system_config.log.rotate_size`.
688
+ # However, currently, there is a bug that `system_config.log` parameters
689
+ # are not in `Fluent::SystemConfig::SYSTEM_CONFIG_PARAMETERS`, and these
690
+ # parameters are not merged in `build_system_config()`.
691
+ # Until we fix the bug of `Fluent::SystemConfig`, we need to use these instance variables.
692
+ @log_path = opt[:log_path]
693
+ @log_rotate_age = opt[:log_rotate_age]
694
+ @log_rotate_size = opt[:log_rotate_size]
695
+
696
+ @finished = false
697
+ end
698
+
699
+ def run_supervisor(dry_run: false)
700
+ if dry_run
701
+ $log.info "starting fluentd-#{Fluent::VERSION} as dry run mode", ruby: RUBY_VERSION
702
+ end
703
+
704
+ if @system_config.workers < 1
705
+ raise Fluent::ConfigError, "invalid number of workers (must be > 0):#{@system_config.workers}"
706
+ end
707
+
708
+ if Fluent.windows? && @system_config.with_source_only
709
+ raise Fluent::ConfigError, "with-source-only is not supported on Windows"
710
+ end
711
+
712
+ root_dir = @system_config.root_dir
713
+ if root_dir
714
+ if File.exist?(root_dir)
715
+ unless Dir.exist?(root_dir)
716
+ raise Fluent::InvalidRootDirectory, "non directory entry exists:#{root_dir}"
717
+ end
718
+ else
719
+ begin
720
+ FileUtils.mkdir_p(root_dir, mode: @system_config.dir_permission || Fluent::DEFAULT_DIR_PERMISSION)
721
+ rescue => e
722
+ raise Fluent::InvalidRootDirectory, "failed to create root directory:#{root_dir}, #{e.inspect}"
723
+ end
724
+ end
725
+ end
726
+
727
+ begin
728
+ ServerEngine::Privilege.change(@chuser, @chgroup)
729
+ MessagePackFactory.init(enable_time_support: @system_config.enable_msgpack_time_support)
730
+ Fluent::Engine.init(@system_config, supervisor_mode: true, start_in_parallel: ENV.key?("FLUENT_RUNNING_IN_PARALLEL_WITH_OLD"))
731
+ Fluent::Engine.run_configure(@conf, dry_run: dry_run)
732
+ rescue Fluent::ConfigError => e
733
+ $log.error 'config error', file: @config_path, error: e
734
+ $log.debug_backtrace
735
+ exit!(1)
736
+ rescue ScriptError => e # LoadError, NotImplementedError, SyntaxError
737
+ if e.respond_to?(:path)
738
+ $log.error e.message, path: e.path, error: e
739
+ else
740
+ $log.error e.message, error: e
741
+ end
742
+ $log.debug_backtrace
743
+ exit!(1)
744
+ rescue => e
745
+ $log.error "unexpected error", error: e
746
+ $log.debug_backtrace
747
+ exit!(1)
748
+ end
749
+
750
+ if dry_run
751
+ $log.info 'finished dry run mode'
752
+ exit 0
753
+ else
754
+ supervise
755
+ end
756
+ end
757
+
758
+ def options
759
+ {
760
+ 'config_path' => @config_path,
761
+ 'pid_file' => @daemonize,
762
+ 'plugin_dirs' => @plugin_dirs,
763
+ 'log_path' => @log_path,
764
+ 'root_dir' => @system_config.root_dir,
765
+ }
766
+ end
767
+
768
+ def run_worker
769
+ Process.setproctitle("worker:#{@system_config.process_name}") if @process_name
770
+
771
+ if @standalone_worker && @system_config.workers != 1
772
+ raise Fluent::ConfigError, "invalid number of workers (must be 1 or unspecified) with --no-supervisor: #{@system_config.workers}"
773
+ end
774
+
775
+ if Fluent.windows? && @system_config.with_source_only
776
+ raise Fluent::ConfigError, "with-source-only is not supported on Windows"
777
+ end
778
+
779
+ install_main_process_signal_handlers
780
+
781
+ # This is the only log message for @standalone_worker
782
+ $log.info "starting fluentd-#{Fluent::VERSION} without supervision", pid: Process.pid, ruby: RUBY_VERSION if @standalone_worker
783
+
784
+ main_process do
785
+ create_socket_manager if @standalone_worker
786
+ if @standalone_worker
787
+ ServerEngine::Privilege.change(@chuser, @chgroup)
788
+ File.umask(@chumask.to_i(8))
789
+ end
790
+ MessagePackFactory.init(enable_time_support: @system_config.enable_msgpack_time_support)
791
+ Fluent::Engine.init(@system_config, start_in_parallel: ENV.key?("FLUENT_RUNNING_IN_PARALLEL_WITH_OLD"))
792
+ Fluent::Engine.run_configure(@conf)
793
+ enable_ruby_jit if @system_config.enable_jit
794
+ Fluent::Engine.run
795
+ self.class.cleanup_socketmanager_path if @standalone_worker
796
+ exit 0
797
+ end
798
+ end
799
+
800
+ def configure(supervisor: false)
801
+ setup_global_logger(supervisor: supervisor)
802
+
803
+ if @show_plugin_config
804
+ show_plugin_config
805
+ end
806
+
807
+ if @inline_config == '-'
808
+ $log.warn('the value "-" for `inline_config` is deprecated. See https://github.com/fluent/fluentd/issues/2711')
809
+ @inline_config = STDIN.read
810
+ end
811
+ parsed_files = Set.new
812
+ @conf = Fluent::Config.build(
813
+ config_path: @config_path,
814
+ encoding: @conf_encoding,
815
+ additional_config: @inline_config,
816
+ use_v1_config: @use_v1_config,
817
+ type: @config_file_type,
818
+ on_file_parsed: ->(path) { parsed_files << path },
819
+ )
820
+ @system_config = build_system_config(@conf)
821
+
822
+ # `<system> umask` sets the process umask, just like the `--umask` command
823
+ # line option. The command line option takes precedence when both are given.
824
+ if @system_config.umask && !@cl_opt.key?(:chumask)
825
+ @chumask = @system_config.umask
826
+ end
827
+
828
+ $log.info :supervisor, 'parsing config file is succeeded', path: @config_path
829
+
830
+ build_additional_configurations(parsed_files) do |additional_conf|
831
+ @conf += additional_conf
832
+ end
833
+
834
+ if Fluent.windows?
835
+ @conf.elements.each do |element|
836
+ next unless element.name == 'source'
837
+ if element['@type'] == 'tail' && element['pos_file']
838
+ $log.warn("Recommend adding #{File.dirname(element['pos_file'])} to the exclusion path of your antivirus software on Windows")
839
+ else
840
+ storage = element.elements.find { |v| v.name == 'storage' and v['@type'] == 'local' }
841
+ if storage
842
+ $log.warn("Recommend adding #{File.dirname(storage['path'])} to the exclusion path of your antivirus software on Windows")
843
+ end
844
+ end
845
+ end
846
+ end
847
+
848
+ @libs.each do |lib|
849
+ require lib
850
+ end
851
+
852
+ @plugin_dirs.each do |dir|
853
+ if Dir.exist?(dir)
854
+ dir = File.expand_path(dir)
855
+ Fluent::Plugin.add_plugin_dir(dir)
856
+ end
857
+ end
858
+
859
+ if supervisor
860
+ # plugins / configuration dumps
861
+ Gem::Specification.find_all.select { |x| x.name =~ /^fluent(d|-(plugin|mixin)-.*)$/ }.each do |spec|
862
+ $log.info("gem '#{spec.name}' version '#{spec.version}'")
863
+ end
864
+ end
865
+ end
866
+
867
+ private
868
+
869
+ def setup_global_logger(supervisor: false)
870
+ if supervisor
871
+ worker_id = 0
872
+ process_type = :supervisor
873
+ else
874
+ worker_id = ENV['SERVERENGINE_WORKER_ID'].to_i
875
+ process_type = case
876
+ when @standalone_worker then :standalone
877
+ when worker_id == 0 then :worker0
878
+ else :workers
879
+ end
880
+ end
881
+
882
+ # Parse configuration immediately to initialize logger in early stage.
883
+ # Since we can't confirm the log messages in this parsing process,
884
+ # we must parse the config again after initializing logger.
885
+ conf = Fluent::Config.build(
886
+ config_path: @config_path,
887
+ encoding: @conf_encoding,
888
+ additional_config: @inline_config,
889
+ use_v1_config: @use_v1_config,
890
+ type: @config_file_type,
891
+ on_file_parsed: nil,
892
+ )
893
+ system_config = build_system_config(conf)
894
+
895
+ # TODO: we should remove this logic. This merging process should be done
896
+ # in `build_system_config()`.
897
+ @log_path ||= system_config.log.path
898
+ @log_rotate_age ||= system_config.log.rotate_age
899
+ @log_rotate_size ||= system_config.log.rotate_size
900
+
901
+ rotate = @log_rotate_age || @log_rotate_size
902
+ actual_log_path = @log_path
903
+
904
+ # We need to prepare a unique path for each worker since Windows locks files.
905
+ if Fluent.windows? && rotate && @log_path && @log_path != "-"
906
+ actual_log_path = Fluent::Log.per_process_path(@log_path, process_type, worker_id)
907
+ end
908
+
909
+ if actual_log_path && actual_log_path != "-"
910
+ FileUtils.mkdir_p(File.dirname(actual_log_path)) unless File.exist?(actual_log_path)
911
+ if rotate
912
+ logdev = Fluent::LogDeviceIO.new(
913
+ actual_log_path,
914
+ shift_age: @log_rotate_age,
915
+ shift_size: @log_rotate_size,
916
+ )
917
+ else
918
+ logdev = File.open(actual_log_path, "a")
919
+ end
920
+
921
+ if @chuser || @chgroup
922
+ chuid = @chuser ? ServerEngine::Privilege.get_etc_passwd(@chuser).uid : nil
923
+ chgid = @chgroup ? ServerEngine::Privilege.get_etc_group(@chgroup).gid : nil
924
+ File.chown(chuid, chgid, actual_log_path)
925
+ end
926
+
927
+ if system_config.dir_permission
928
+ File.chmod(system_config.dir_permission || Fluent::DEFAULT_DIR_PERMISSION, File.dirname(actual_log_path))
929
+ end
930
+ else
931
+ logdev = STDOUT
932
+ end
933
+
934
+ $log = Fluent::Log.new(
935
+ # log_level: subtract 1 to match serverengine daemon logger side logging severity.
936
+ ServerEngine::DaemonLogger.new(logdev, log_level: system_config.log_level - 1),
937
+ path: actual_log_path,
938
+ process_type: process_type,
939
+ worker_id: worker_id,
940
+ format: system_config.log.format,
941
+ time_format: system_config.log.time_format,
942
+ suppress_repeated_stacktrace: system_config.suppress_repeated_stacktrace,
943
+ ignore_repeated_log_interval: system_config.ignore_repeated_log_interval,
944
+ ignore_same_log_interval: system_config.ignore_same_log_interval,
945
+ )
946
+ $log.force_stacktrace_level(system_config.log.forced_stacktrace_level) if system_config.force_stacktrace_level?
947
+ $log.enable_color(false) if actual_log_path
948
+ $log.enable_debug if system_config.log_level <= Fluent::Log::LEVEL_DEBUG
949
+
950
+ $log.info "init #{process_type} logger",
951
+ path: actual_log_path,
952
+ rotate_age: @log_rotate_age,
953
+ rotate_size: @log_rotate_size
954
+ end
955
+
956
+ def create_socket_manager
957
+ server = ServerEngine::SocketManager::Server.open
958
+ ENV['SERVERENGINE_SOCKETMANAGER_PATH'] = server.path.to_s
959
+ end
960
+
961
+ def show_plugin_config
962
+ name, type = @show_plugin_config.split(":") # input:tail
963
+ $log.info "show_plugin_config option is deprecated. Use fluent-plugin-config-format --format=txt #{name} #{type}"
964
+ exit 0
965
+ end
966
+
967
+ def supervise
968
+ Process.setproctitle("supervisor:#{@system_config.process_name}") if @system_config.process_name
969
+ $log.info "starting fluentd-#{Fluent::VERSION}", pid: Process.pid, ruby: RUBY_VERSION
970
+
971
+ fluentd_spawn_cmd = build_spawn_command
972
+ $log.info "spawn command to main: ", cmdline: fluentd_spawn_cmd
973
+
974
+ params = {
975
+ 'main_cmd' => fluentd_spawn_cmd,
976
+ 'daemonize' => @daemonize,
977
+ 'inline_config' => @inline_config,
978
+ 'chuser' => @chuser,
979
+ 'chgroup' => @chgroup,
980
+ 'chumask' => @chumask,
981
+ 'fluentd_conf_path' => @config_path,
982
+ 'fluentd_conf' => @conf.to_s,
983
+ 'use_v1_config' => @use_v1_config,
984
+ 'config_file_type' => @config_file_type,
985
+ 'conf_encoding' => @conf_encoding,
986
+ 'signame' => @signame,
987
+
988
+ 'workers' => @system_config.workers,
989
+ 'root_dir' => @system_config.root_dir,
990
+ 'log_level' => @system_config.log_level,
991
+ 'rpc_endpoint' => @system_config.rpc_endpoint,
992
+ 'enable_get_dump' => @system_config.enable_get_dump,
993
+ 'counter_server' => @system_config.counter_server,
994
+ 'disable_shared_socket' => @system_config.disable_shared_socket,
995
+ 'restart_worker_interval' => @system_config.restart_worker_interval,
996
+ }
997
+
998
+ se = ServerEngine.create(ServerModule, WorkerModule) {
999
+ # Note: This is called only at the initialization of ServerEngine, since
1000
+ # Fluentd overwrites all related SIGNAL(HUP,USR1,USR2) and have own reloading feature.
1001
+ Fluent::Supervisor.serverengine_config(params)
1002
+ }
1003
+
1004
+ se.run
1005
+ end
1006
+
1007
+ def install_main_process_signal_handlers
1008
+ # Fluentd worker process (worker of ServerEngine) don't use code in serverengine to set signal handlers,
1009
+ # because it does almost nothing.
1010
+ # This method is the only method to set signal handlers in Fluentd worker process.
1011
+
1012
+ # When user use Ctrl + C not SIGINT, SIGINT is sent to all process in same process group.
1013
+ # ServerEngine server process will send SIGTERM to child(spawned) processes by that SIGINT, so
1014
+ # worker process SHOULD NOT do anything with SIGINT, SHOULD just ignore.
1015
+ trap :INT do
1016
+ $log.debug "fluentd main process get SIGINT"
1017
+
1018
+ # When Fluentd is launched without supervisor, worker should handle ctrl-c by itself
1019
+ if @standalone_worker
1020
+ @finished = true
1021
+ $log.debug "getting start to shutdown main process"
1022
+ Fluent::Engine.stop
1023
+ end
1024
+ end
1025
+
1026
+ trap :TERM do
1027
+ $log.debug "fluentd main process get SIGTERM"
1028
+ unless @finished
1029
+ @finished = true
1030
+ $log.debug "getting start to shutdown main process"
1031
+ Fluent::Engine.stop
1032
+ end
1033
+ end
1034
+
1035
+ if Fluent.windows?
1036
+ install_main_process_command_handlers
1037
+ else
1038
+ trap :USR1 do
1039
+ flush_buffer
1040
+ end
1041
+
1042
+ trap :USR2 do
1043
+ # Leave the old GracefulReload feature, just in case.
1044
+ # We can send SIGUSR2 to the worker process to use this old GracefulReload feature.
1045
+ # (Note: Normally, we can send SIGUSR2 to the supervisor process to use
1046
+ # zero-downtime-restart feature as GracefulReload on non-Windows.)
1047
+ reload_config
1048
+ end
1049
+
1050
+ trap :CONT do
1051
+ dump_non_windows
1052
+ end
1053
+
1054
+ trap :WINCH do
1055
+ cancel_source_only
1056
+ end
1057
+ end
1058
+ end
1059
+
1060
+ def install_main_process_command_handlers
1061
+ command_pipe = $stdin.dup
1062
+ $stdin.reopen(File::NULL, "rb")
1063
+ command_pipe.binmode
1064
+ command_pipe.sync = true
1065
+
1066
+ Thread.new do
1067
+ loop do
1068
+ cmd = command_pipe.gets
1069
+ break unless cmd
1070
+
1071
+ case cmd.chomp!
1072
+ when "GRACEFUL_STOP", "IMMEDIATE_STOP"
1073
+ $log.debug "fluentd main process get #{cmd} command"
1074
+ @finished = true
1075
+ $log.debug "getting start to shutdown main process"
1076
+ Fluent::Engine.stop
1077
+ break
1078
+ when "GRACEFUL_RESTART"
1079
+ $log.debug "fluentd main process get #{cmd} command"
1080
+ flush_buffer
1081
+ when "RELOAD"
1082
+ $log.debug "fluentd main process get #{cmd} command"
1083
+ reload_config
1084
+ when "DUMP"
1085
+ $log.debug "fluentd main process get #{cmd} command"
1086
+ dump_windows
1087
+ else
1088
+ $log.warn "fluentd main process get unknown command [#{cmd}]"
1089
+ end
1090
+ end
1091
+ end
1092
+ end
1093
+
1094
+ def flush_buffer
1095
+ # Creating new thread due to mutex can't lock
1096
+ # in main thread during trap context
1097
+ Thread.new do
1098
+ begin
1099
+ $log.debug "fluentd main process get SIGUSR1"
1100
+ $log.info "force flushing buffered events"
1101
+ $log.reopen!
1102
+ Fluent::Engine.flush!
1103
+ $log.debug "flushing thread: flushed"
1104
+ rescue Exception => e
1105
+ $log.warn "flushing thread error: #{e}"
1106
+ end
1107
+ end
1108
+ end
1109
+
1110
+ def cancel_source_only
1111
+ Thread.new do
1112
+ begin
1113
+ $log.debug "fluentd main process get SIGWINCH"
1114
+ $log.info "try to cancel with-source-only mode"
1115
+ Fluent::Engine.cancel_source_only!
1116
+ rescue Exception => e
1117
+ $log.warn "failed to cancel source only", error: e
1118
+ end
1119
+ end
1120
+ end
1121
+
1122
+ def reload_config
1123
+ Thread.new do
1124
+ $log.debug('worker got SIGUSR2')
1125
+
1126
+ begin
1127
+ parsed_files = Set.new
1128
+ conf = Fluent::Config.build(
1129
+ config_path: @config_path,
1130
+ encoding: @conf_encoding,
1131
+ additional_config: @inline_config,
1132
+ use_v1_config: @use_v1_config,
1133
+ type: @config_file_type,
1134
+ on_file_parsed: ->(path) { parsed_files << path },
1135
+ )
1136
+
1137
+ build_additional_configurations(parsed_files) do |additional_conf|
1138
+ conf += additional_conf
1139
+ end
1140
+
1141
+ Fluent::VariableStore.try_to_reset do
1142
+ Fluent::Engine.reload_config(conf)
1143
+ end
1144
+ rescue => e
1145
+ # it is guaranteed that config file is valid by supervisor side. but it's not atomic because of using signals to commnicate between worker and super
1146
+ # So need this rescue code
1147
+ $log.error("failed to reload config: #{e}")
1148
+ next
1149
+ end
1150
+
1151
+ @conf = conf
1152
+ end
1153
+ end
1154
+
1155
+ def dump_non_windows
1156
+ begin
1157
+ Sigdump.dump unless @finished
1158
+ rescue => e
1159
+ $log.error("failed to dump: #{e}")
1160
+ end
1161
+ end
1162
+
1163
+ def dump_windows
1164
+ Thread.new do
1165
+ begin
1166
+ FluentSigdump.dump_windows
1167
+ rescue => e
1168
+ $log.error("failed to dump: #{e}")
1169
+ end
1170
+ end
1171
+ end
1172
+
1173
+ def logging_with_console_output
1174
+ yield $log
1175
+ unless $log.stdout?
1176
+ logger = ServerEngine::DaemonLogger.new(STDOUT)
1177
+ log = Fluent::Log.new(logger)
1178
+ log.level = @system_config.log_level
1179
+ console = log.enable_debug
1180
+ yield console
1181
+ end
1182
+ end
1183
+
1184
+ def main_process(&block)
1185
+ if @system_config.process_name
1186
+ if @system_config.workers > 1
1187
+ Process.setproctitle("worker:#{@system_config.process_name}#{ENV['SERVERENGINE_WORKER_ID']}")
1188
+ else
1189
+ Process.setproctitle("worker:#{@system_config.process_name}")
1190
+ end
1191
+ end
1192
+
1193
+ unrecoverable_error = false
1194
+
1195
+ begin
1196
+ block.call
1197
+ rescue Fluent::ConfigError => e
1198
+ logging_with_console_output do |log|
1199
+ log.error "config error", file: @config_path, error: e
1200
+ log.debug_backtrace
1201
+ end
1202
+ unrecoverable_error = true
1203
+ rescue Fluent::UnrecoverableError => e
1204
+ logging_with_console_output do |log|
1205
+ log.error e.message, error: e
1206
+ log.error_backtrace
1207
+ end
1208
+ unrecoverable_error = true
1209
+ rescue ScriptError => e # LoadError, NotImplementedError, SyntaxError
1210
+ logging_with_console_output do |log|
1211
+ if e.respond_to?(:path)
1212
+ log.error e.message, path: e.path, error: e
1213
+ else
1214
+ log.error e.message, error: e
1215
+ end
1216
+ log.error_backtrace
1217
+ end
1218
+ unrecoverable_error = true
1219
+ rescue => e
1220
+ logging_with_console_output do |log|
1221
+ log.error "unexpected error", error: e
1222
+ log.error_backtrace
1223
+ end
1224
+ end
1225
+
1226
+ exit!(unrecoverable_error ? 2 : 1)
1227
+ end
1228
+
1229
+ def enable_ruby_jit
1230
+ unless defined?(RubyVM::YJIT) && RubyVM::YJIT.respond_to?(:enable)
1231
+ $log.info "Ruby JIT is not available on this Ruby"
1232
+ return
1233
+ end
1234
+
1235
+ if RubyVM::YJIT.enable
1236
+ $log.info "enabled Ruby JIT"
1237
+ else
1238
+ $log.warn "failed to enable Ruby JIT"
1239
+ end
1240
+ end
1241
+
1242
+ def build_system_config(conf)
1243
+ system_config = SystemConfig.create(conf, @cl_opt[:strict_config_value])
1244
+ # Prefer the options explicitly specified in the command line
1245
+ #
1246
+ # TODO: There is a bug that `system_config.log.rotate_age/rotate_size` are
1247
+ # not merged with the command line options since they are not in
1248
+ # `SYSTEM_CONFIG_PARAMETERS`.
1249
+ # We have to fix this bug.
1250
+ opt = {}
1251
+ Fluent::SystemConfig::SYSTEM_CONFIG_PARAMETERS.each do |param|
1252
+ if @cl_opt.key?(param) && !@cl_opt[param].nil?
1253
+ opt[param] = @cl_opt[param]
1254
+ end
1255
+ end
1256
+ system_config.overwrite_variables(**opt)
1257
+ system_config
1258
+ end
1259
+
1260
+ def build_additional_configurations(parsed_files)
1261
+ if @system_config.config_include_dir&.empty?
1262
+ $log.info :supervisor, 'configuration include directory is disabled'
1263
+ return
1264
+ end
1265
+ begin
1266
+ supported_suffixes = [".conf", ".yaml", ".yml"]
1267
+ Find.find(@system_config.config_include_dir) do |path|
1268
+ next if File.directory?(path)
1269
+ next unless supported_suffixes.include?(File.extname(path))
1270
+ # NOTE: both types of normal config (.conf) and YAML will be loaded.
1271
+ # Thus, it does not care whether @config_path is .conf or .yml.
1272
+ if parsed_files.include?(path)
1273
+ $log.info :supervisor, 'skip auto loading, it was already loaded', path: path
1274
+ next
1275
+ end
1276
+
1277
+ $log.info :supervisor, 'loading additional configuration file', path: path
1278
+ yield Fluent::Config.build(config_path: path,
1279
+ encoding: @conf_encoding,
1280
+ use_v1_config: @use_v1_config,
1281
+ type: :guess,
1282
+ on_file_parsed: nil)
1283
+ end
1284
+ rescue Errno::ENOENT
1285
+ $log.info :supervisor, 'inaccessible include directory was specified', path: @system_config.config_include_dir
1286
+ end
1287
+ end
1288
+
1289
+ RUBY_ENCODING_OPTIONS_REGEX = %r{\A(-E|--encoding=|--internal-encoding=|--external-encoding=)}.freeze
1290
+
1291
+ def build_spawn_command
1292
+ if ENV['TEST_RUBY_PATH']
1293
+ fluentd_spawn_cmd = [ENV['TEST_RUBY_PATH']]
1294
+ else
1295
+ fluentd_spawn_cmd = [ServerEngine.ruby_bin_path]
1296
+ end
1297
+
1298
+ rubyopt = ENV['RUBYOPT']
1299
+ if rubyopt
1300
+ encodes, others = rubyopt.split(' ').partition { |e| e.match?(RUBY_ENCODING_OPTIONS_REGEX) }
1301
+ fluentd_spawn_cmd.concat(others)
1302
+
1303
+ adopted_encodes = encodes.empty? ? ['-Eascii-8bit:ascii-8bit'] : encodes
1304
+ fluentd_spawn_cmd.concat(adopted_encodes)
1305
+ else
1306
+ fluentd_spawn_cmd << '-Eascii-8bit:ascii-8bit'
1307
+ end
1308
+
1309
+ # Adding `-h` so that it can avoid ruby's command blocking
1310
+ # e.g. `ruby -Eascii-8bit:ascii-8bit` will block. but `ruby -Eascii-8bit:ascii-8bit -h` won't.
1311
+ _, e, s = Open3.capture3(*fluentd_spawn_cmd, "-h")
1312
+ if s.exitstatus != 0
1313
+ $log.error('Invalid option is passed to RUBYOPT', command: fluentd_spawn_cmd, error: e)
1314
+ exit s.exitstatus
1315
+ end
1316
+
1317
+ fluentd_spawn_cmd << $0
1318
+ fluentd_spawn_cmd += $fluentdargv
1319
+ fluentd_spawn_cmd << '--under-supervisor'
1320
+
1321
+ fluentd_spawn_cmd
1322
+ end
1323
+ end
1324
+
1325
+ module FluentSigdump
1326
+ def self.dump_windows
1327
+ raise "[BUG] WindowsSigdump::dump is for Windows ONLY." unless Fluent.windows?
1328
+
1329
+ # Sigdump outputs under `/tmp` dir without `SIGDUMP_PATH` specified,
1330
+ # but `/tmp` dir may not exist on Windows by default.
1331
+ # So use the systemroot-temp-dir instead.
1332
+ dump_filepath = ENV['SIGDUMP_PATH'].nil? || ENV['SIGDUMP_PATH'].empty? \
1333
+ ? "#{ENV['windir']}/Temp/fluentd-sigdump-#{Process.pid}.log"
1334
+ : get_path_with_pid(ENV['SIGDUMP_PATH'])
1335
+
1336
+ require 'sigdump'
1337
+ Sigdump.dump(dump_filepath)
1338
+
1339
+ $log.info "dump to #{dump_filepath}."
1340
+ end
1341
+
1342
+ def self.get_path_with_pid(raw_path)
1343
+ path = Pathname.new(raw_path)
1344
+ path.sub_ext("-#{Process.pid}#{path.extname}").to_s
1345
+ end
1346
+ end
1347
+ end