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,319 @@
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
+ require 'fluent/plugin/output'
17
+ require 'fluent/env'
18
+ require 'fluent/config/error'
19
+
20
+ require 'json'
21
+
22
+ module Fluent::Plugin
23
+ class ExecFilterOutput < Output
24
+ Fluent::Plugin.register_output('exec_filter', self)
25
+
26
+ helpers :compat_parameters, :inject, :formatter, :parser, :extract, :child_process, :event_emitter
27
+
28
+ desc 'The command (program) to execute.'
29
+ config_param :command, :string
30
+
31
+ config_param :remove_prefix, :string, default: nil, deprecated: "use @label instead for event routing"
32
+ config_param :add_prefix, :string, default: nil, deprecated: "use @label instead for event routing"
33
+
34
+ config_section :inject do
35
+ config_set_default :time_type, :unixtime
36
+ end
37
+
38
+ config_section :format do
39
+ config_set_default :@type, 'tsv'
40
+ config_set_default :localtime, true
41
+ end
42
+
43
+ config_section :parse do
44
+ config_set_default :@type, 'tsv'
45
+ config_set_default :time_key, nil
46
+ config_set_default :time_format, nil
47
+ config_set_default :localtime, true
48
+ config_set_default :estimate_current_event, false
49
+ end
50
+
51
+ config_section :extract do
52
+ config_set_default :time_type, :float
53
+ end
54
+
55
+ config_section :buffer do
56
+ config_set_default :flush_mode, :interval
57
+ config_set_default :flush_interval, 1
58
+ end
59
+
60
+ config_param :tag, :string, default: nil
61
+
62
+ config_param :tag_key, :string, default: nil, deprecated: "use 'tag_key' in <inject>/<extract> instead"
63
+ config_param :time_key, :string, default: nil, deprecated: "use 'time_key' in <inject>/<extract> instead"
64
+ config_param :time_format, :string, default: nil, deprecated: "use 'time_format' in <inject>/<extract> instead"
65
+
66
+ desc 'The default block size to read if parser requires partial read.'
67
+ config_param :read_block_size, :size, default: 10240 # 10k
68
+
69
+ desc 'The number of spawned process for command.'
70
+ config_param :num_children, :integer, default: 1
71
+
72
+ desc 'Respawn command when command exit. ["none", "inf" or positive integer for times to respawn (default: none)]'
73
+ # nil, 'none' or 0: no respawn, 'inf' or -1: infinite times, positive integer: try to respawn specified times only
74
+ config_param :child_respawn, :string, default: nil
75
+
76
+ # 0: output logs for all of messages to emit
77
+ config_param :suppress_error_log_interval, :time, default: 0
78
+
79
+ attr_reader :formatter, :parser # for tests
80
+
81
+ KEYS_FOR_IN_AND_OUT = {
82
+ 'tag_key' => ['in_tag_key', 'out_tag_key'],
83
+ 'time_key' => ['in_time_key', 'out_time_key'],
84
+ 'time_format' => ['in_time_format', 'out_time_format'],
85
+ }
86
+ COMPAT_INJECT_PARAMS = {
87
+ 'in_tag_key' => 'tag_key',
88
+ 'in_time_key' => 'time_key',
89
+ 'in_time_format' => 'time_format',
90
+ }
91
+ COMPAT_FORMAT_PARAMS = {
92
+ 'in_format' => '@type',
93
+ 'in_keys' => 'keys',
94
+ }
95
+ COMPAT_PARSE_PARAMS = {
96
+ 'out_format' => '@type',
97
+ 'out_keys' => 'keys',
98
+ 'out_stream_buffer_size' => 'stream_buffer_size',
99
+ }
100
+ COMPAT_EXTRACT_PARAMS = {
101
+ 'out_tag_key' => 'tag_key',
102
+ 'out_time_key' => 'time_key',
103
+ 'out_time_format' => 'time_format',
104
+ }
105
+
106
+ def exec_filter_compat_parameters_copy_to_subsection!(conf, subsection_name, params)
107
+ return unless conf.elements(subsection_name).empty?
108
+ return unless params.keys.any?{|k| conf.has_key?(k) }
109
+ hash = {}
110
+ params.each_pair do |compat, current|
111
+ hash[current] = conf[compat] if conf.has_key?(compat)
112
+ end
113
+ conf.elements << Fluent::Config::Element.new(subsection_name, '', hash, [])
114
+ end
115
+
116
+ def exec_filter_compat_parameters_convert!(conf)
117
+ KEYS_FOR_IN_AND_OUT.each_pair do |inout, keys|
118
+ if conf.has_key?(inout)
119
+ keys.each do |k|
120
+ conf[k] = conf[inout]
121
+ end
122
+ end
123
+ end
124
+ exec_filter_compat_parameters_copy_to_subsection!(conf, 'inject', COMPAT_INJECT_PARAMS)
125
+ exec_filter_compat_parameters_copy_to_subsection!(conf, 'format', COMPAT_FORMAT_PARAMS)
126
+ exec_filter_compat_parameters_copy_to_subsection!(conf, 'parse', COMPAT_PARSE_PARAMS)
127
+ exec_filter_compat_parameters_copy_to_subsection!(conf, 'extract', COMPAT_EXTRACT_PARAMS)
128
+ end
129
+
130
+ def configure(conf)
131
+ exec_filter_compat_parameters_convert!(conf)
132
+ compat_parameters_convert(conf, :buffer)
133
+
134
+ if inject_section = conf.elements('inject').first
135
+ if inject_section.has_key?('time_format')
136
+ inject_section['time_type'] ||= 'string'
137
+ end
138
+ end
139
+ if extract_section = conf.elements('extract').first
140
+ if extract_section.has_key?('time_format')
141
+ extract_section['time_type'] ||= 'string'
142
+ end
143
+ end
144
+
145
+ super
146
+
147
+ if !@tag && (!@extract_config || !@extract_config.tag_key)
148
+ raise Fluent::ConfigError, "'tag' or '<extract> tag_key </extract>' option is required on exec_filter output"
149
+ end
150
+
151
+ @formatter = formatter_create
152
+ @parser = parser_create
153
+
154
+ if @remove_prefix
155
+ @removed_prefix_string = @remove_prefix + '.'
156
+ @removed_length = @removed_prefix_string.length
157
+ end
158
+ if @add_prefix
159
+ @added_prefix_string = @add_prefix + '.'
160
+ end
161
+
162
+ @respawns = if @child_respawn.nil? || (@child_respawn == 'none') || (@child_respawn == '0')
163
+ 0
164
+ elsif (@child_respawn == 'inf') || (@child_respawn == '-1')
165
+ -1
166
+ elsif /^\d+$/.match?(@child_respawn)
167
+ @child_respawn.to_i
168
+ else
169
+ raise ConfigError, "child_respawn option argument invalid: none(or 0), inf(or -1) or positive number"
170
+ end
171
+
172
+ @suppress_error_log_interval ||= 0
173
+ @next_log_time = Time.now.to_i
174
+ end
175
+
176
+ def multi_workers_ready?
177
+ true
178
+ end
179
+
180
+ ExecutedProcess = Struct.new(:mutex, :pid, :respawns, :readio, :writeio)
181
+
182
+ def start
183
+ super
184
+
185
+ @children_mutex = Mutex.new
186
+ @children = []
187
+ @rr = 0
188
+
189
+ exit_callback = ->(status){
190
+ c = @children.find{|child| child.pid == status.pid }
191
+ if c
192
+ unless self.stopped?
193
+ log.warn "child process exits with error code", code: status.to_i, status: status.exitstatus, signal: status.termsig
194
+ end
195
+ c.mutex.synchronize do
196
+ c.writeio&.close rescue nil
197
+ c.readio&.close rescue nil
198
+ c.pid = c.readio = c.writeio = nil
199
+ end
200
+ end
201
+ }
202
+ child_process_callback = ->(index, readio, writeio){
203
+ pid = child_process_id
204
+ c = @children[index]
205
+ writeio.sync = true
206
+ c.mutex.synchronize do
207
+ c.pid = pid
208
+ c.respawns = @respawns
209
+ c.readio = readio
210
+ c.writeio = writeio
211
+ end
212
+
213
+ run(readio)
214
+ }
215
+ execute_child_process = ->(index){
216
+ child_process_execute("out_exec_filter_child#{index}".to_sym, @command, on_exit_callback: exit_callback) do |readio, writeio|
217
+ child_process_callback.call(index, readio, writeio)
218
+ end
219
+ }
220
+
221
+ @children_mutex.synchronize do
222
+ @num_children.times do |i|
223
+ @children << ExecutedProcess.new(Mutex.new, nil, 0, nil, nil)
224
+ execute_child_process.call(i)
225
+ end
226
+ end
227
+
228
+ if @respawns != 0
229
+ thread_create(:out_exec_filter_respawn_monitor) do
230
+ while thread_current_running?
231
+ @children.each_with_index do |c, i|
232
+ if c.mutex && c.mutex.synchronize{ c.pid.nil? && c.respawns != 0 }
233
+ respawns = c.mutex.synchronize do
234
+ c.respawns -= 1 if c.respawns > 0
235
+ c.respawns
236
+ end
237
+ log.info "respawning child process", num: i, respawn_counter: respawns
238
+ execute_child_process.call(i)
239
+ end
240
+ end
241
+ sleep 0.2
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ def terminate
248
+ @children = []
249
+ super
250
+ end
251
+
252
+ def tag_remove_prefix(tag)
253
+ if @remove_prefix
254
+ if ((tag[0, @removed_length] == @removed_prefix_string) && (tag.length > @removed_length)) || (tag == @removed_prefix_string)
255
+ tag = tag[@removed_length..-1] || ''
256
+ end
257
+ end
258
+ tag
259
+ end
260
+
261
+ NEWLINE = "\n"
262
+
263
+ def format(tag, time, record)
264
+ tag = tag_remove_prefix(tag)
265
+ record = inject_values_to_record(tag, time, record)
266
+ if @formatter.formatter_type == :text_per_line
267
+ @formatter.format(tag, time, record).chomp + NEWLINE
268
+ else
269
+ @formatter.format(tag, time, record)
270
+ end
271
+ end
272
+
273
+ def write(chunk)
274
+ try_times = 0
275
+ while true
276
+ r = @rr = (@rr + 1) % @children.length
277
+ if @children[r].pid && writeio = @children[r].writeio
278
+ chunk.write_to(writeio)
279
+ break
280
+ end
281
+ try_times += 1
282
+ raise "no healthy child processes exist" if try_times >= @children.length
283
+ end
284
+ end
285
+
286
+ def run(io)
287
+ io.set_encoding(Encoding::ASCII_8BIT)
288
+ case
289
+ when @parser.implement?(:parse_io)
290
+ @parser.parse_io(io, &method(:on_record))
291
+ when @parser.implement?(:parse_partial_data)
292
+ until io.eof?
293
+ @parser.parse_partial_data(io.readpartial(@read_block_size), &method(:on_record))
294
+ end
295
+ when @parser.parser_type == :text_per_line
296
+ io.each_line do |line|
297
+ @parser.parse(line.chomp, &method(:on_record))
298
+ end
299
+ else
300
+ @parser.parse(io.read, &method(:on_record))
301
+ end
302
+ end
303
+
304
+ def on_record(time, record)
305
+ tag = extract_tag_from_record(record)
306
+ tag = @added_prefix_string + tag if tag && @add_prefix
307
+ tag ||= @tag
308
+ time ||= extract_time_from_record(record) || Fluent::EventTime.now
309
+ router.emit(tag, time, record)
310
+ rescue => e
311
+ if @suppress_error_log_interval == 0 || Time.now.to_i > @next_log_time
312
+ log.error "exec_filter failed to emit", record: JSON.generate(record), error: e
313
+ log.error_backtrace e.backtrace
314
+ @next_log_time = Time.now.to_i + @suppress_error_log_interval
315
+ end
316
+ router.emit_error_event(tag, time, record, e) if tag && time && record
317
+ end
318
+ end
319
+ end
@@ -0,0 +1,371 @@
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 'zlib'
19
+ require 'time'
20
+ require 'pathname'
21
+
22
+ require 'fluent/plugin/output'
23
+ require 'fluent/config/error'
24
+ # TODO remove ...
25
+ require 'fluent/plugin/file_util'
26
+
27
+ module Fluent::Plugin
28
+ class FileOutput < Output
29
+ Fluent::Plugin.register_output('file', self)
30
+
31
+ helpers :formatter, :inject, :compat_parameters
32
+
33
+ SUPPORTED_COMPRESS = [:text, :gz, :gzip, :zstd]
34
+ SUPPORTED_COMPRESS_MAP = {
35
+ text: nil,
36
+ gz: :gzip,
37
+ gzip: :gzip,
38
+ zstd: :zstd,
39
+ }
40
+
41
+ DEFAULT_TIMEKEY = 60 * 60 * 24
42
+
43
+ desc "The Path of the file."
44
+ config_param :path, :string
45
+
46
+ desc "Specify to add file suffix for bare file path or not."
47
+ config_param :add_path_suffix, :bool, default: true
48
+ desc "The file suffix added to bare file path."
49
+ config_param :path_suffix, :string, default: '.log'
50
+ desc "The flushed chunk is appended to existence file or not."
51
+ config_param :append, :bool, default: false
52
+ desc "Compress flushed file."
53
+ config_param :compress, :enum, list: SUPPORTED_COMPRESS, default: :text
54
+ desc "Execute compression again even when buffer chunk is already compressed."
55
+ config_param :recompress, :bool, default: false
56
+ desc "Create symlink to temporary buffered file when buffer_type is file (disabled on Windows)."
57
+ config_param :symlink_path, :string, default: nil
58
+ desc "Use relative path for symlink target (default: false)"
59
+ config_param :symlink_path_use_relative, :bool, default: false
60
+
61
+ config_section :format do
62
+ config_set_default :@type, 'out_file'
63
+ end
64
+
65
+ config_section :buffer do
66
+ config_set_default :@type, 'file'
67
+ config_set_default :chunk_keys, ['time']
68
+ config_set_default :timekey, DEFAULT_TIMEKEY
69
+ end
70
+
71
+ attr_reader :dir_perm
72
+ attr_accessor :last_written_path # for tests
73
+
74
+ module SymlinkBufferMixin
75
+ def metadata(timekey: nil, tag: nil, variables: nil)
76
+ metadata = super
77
+
78
+ if newer_timekey?(metadata.timekey)
79
+ synchronize { @latest_timekey = metadata.timekey if newer_timekey?(metadata.timekey) }
80
+ end
81
+
82
+ metadata
83
+ end
84
+
85
+ def output_plugin_for_symlink=(output_plugin)
86
+ @_output_plugin_for_symlink = output_plugin
87
+ end
88
+
89
+ def symlink_path=(path)
90
+ @_symlink_path = path
91
+ end
92
+
93
+ def generate_chunk(metadata)
94
+ chunk = super
95
+ # "symlink" feature is to link from symlink_path to the latest file chunk. Records with latest
96
+ # timekey will be appended into that file chunk. On the other side, resumed file chunks might NOT
97
+ # have timekey, especially in the cases that resumed file chunks are generated by Fluentd v0.12.
98
+ # These chunks will be enqueued immediately, and will be flushed soon.
99
+ # Split chunks (seq > 0) are generated outside the buffer lock, so ln_sf would race between threads.
100
+ if chunk.metadata.timekey && chunk.metadata.seq == 0 && chunk.metadata.timekey == @latest_timekey
101
+ sym_path = @_output_plugin_for_symlink.extract_placeholders(@_symlink_path, chunk)
102
+ FileUtils.mkdir_p(File.dirname(sym_path), mode: @_output_plugin_for_symlink.dir_perm)
103
+ if @_output_plugin_for_symlink.symlink_path_use_relative
104
+ relative_path = Pathname.new(chunk.path).relative_path_from(Pathname.new(File.dirname(sym_path)))
105
+ FileUtils.ln_sf(relative_path, sym_path)
106
+ else
107
+ FileUtils.ln_sf(chunk.path, sym_path)
108
+ end
109
+ end
110
+ chunk
111
+ end
112
+
113
+ private
114
+
115
+ def newer_timekey?(timekey)
116
+ timekey && (@latest_timekey.nil? || timekey > @latest_timekey)
117
+ end
118
+ end
119
+
120
+ def configure(conf)
121
+ compat_parameters_convert(conf, :formatter, :buffer, :inject, default_chunk_key: "time")
122
+
123
+ configured_time_slice_format = conf['time_slice_format']
124
+
125
+ if conf.elements(name: 'buffer').empty?
126
+ # no <buffer> section, default time chunk key and timekey (1d) will be used.
127
+ log.warn "default timekey interval (1d) will be used because of missing <buffer> section. To change the output frequency, please modify the timekey value"
128
+
129
+ conf.add_element('buffer', 'time')
130
+ else
131
+ unless conf.elements(name: 'buffer').first.has_key?('timekey')
132
+ if conf.elements(name: 'buffer').first.arg != "[]"
133
+ # with <buffer> section (except <buffer []>), and no timekey
134
+ log.warn "default timekey interval (1d) will be used. To change the output frequency, please modify the timekey value"
135
+ end
136
+ end
137
+ end
138
+ buffer_conf = conf.elements(name: 'buffer').first
139
+ # Fluent::PluginId#configure is not called yet, so we can't use #plugin_root_dir here.
140
+ if !buffer_conf.has_key?('path') && !(conf['@id'] && system_config.root_dir)
141
+ # v0.14 file buffer handles path as directory if '*' is missing
142
+ # 'dummy_path' is not to raise configuration error for 'path' in file buffer plugin,
143
+ # but raise it in this plugin.
144
+ buffer_conf['path'] = conf['path'] || '/tmp/dummy_path'
145
+ end
146
+
147
+ if conf.has_key?('utc') || conf.has_key?('localtime')
148
+ param_name = conf.has_key?('utc') ? 'utc' : 'localtime'
149
+ log.warn "'#{param_name}' is deprecated for output plugin. This parameter is used for formatter plugin in compatibility layer. If you want to use same feature, use timekey_use_utc parameter in <buffer> directive instead"
150
+ end
151
+
152
+ super
153
+
154
+ @compress_method = SUPPORTED_COMPRESS_MAP[@compress]
155
+
156
+ if @path.include?('*') && !@buffer_config.timekey
157
+ raise Fluent::ConfigError, "path including '*' must be used with buffer chunk key 'time'"
158
+ end
159
+
160
+ path_suffix = @add_path_suffix ? @path_suffix : ''
161
+ path_timekey = if @chunk_key_time
162
+ @as_secondary ? @primary_instance.buffer_config.timekey : @buffer_config.timekey
163
+ else
164
+ nil
165
+ end
166
+ @path_template = generate_path_template(@path, path_timekey, @append, @compress_method, path_suffix: path_suffix, time_slice_format: configured_time_slice_format)
167
+
168
+ if @as_secondary
169
+ # When this plugin is configured as secondary & primary plugin has tag key, but this plugin may not have it.
170
+ # Increment placeholder can make another output file per chunk tag/keys even if original path doesn't include it.
171
+ placeholder_validators(:path, @path_template).select{|v| v.type == :time }.each do |v|
172
+ v.validate!
173
+ end
174
+ else
175
+ placeholder_validate!(:path, @path_template)
176
+
177
+ max_tag_index = get_placeholders_tag(@path_template).max || 1
178
+ max_tag_index = 1 if max_tag_index < 1
179
+ dummy_tag = (['a'] * max_tag_index).join('.')
180
+ dummy_record_keys = get_placeholders_keys(@path_template) || ['message']
181
+ dummy_record = Hash[dummy_record_keys.zip(['data'] * dummy_record_keys.size)]
182
+
183
+ test_chunk1 = chunk_for_test(dummy_tag, Fluent::EventTime.now, dummy_record)
184
+ test_path = extract_placeholders(@path_template, test_chunk1)
185
+ unless ::Fluent::FileUtil.writable_p?(test_path)
186
+ raise Fluent::ConfigError, "out_file: `#{test_path}` is not writable"
187
+ end
188
+ end
189
+
190
+ @formatter = formatter_create
191
+
192
+ if @symlink_path && @buffer.respond_to?(:path)
193
+ if @as_secondary
194
+ raise Fluent::ConfigError, "symlink_path option is unavailable in <secondary>: consider to use secondary_file plugin"
195
+ end
196
+ if Fluent.windows?
197
+ log.warn "symlink_path is unavailable on Windows platform. disabled."
198
+ @symlink_path = nil
199
+ else
200
+ placeholder_validators(:symlink_path, @symlink_path).reject{ |v| v.type == :time }.each do |v|
201
+ begin
202
+ v.validate!
203
+ rescue Fluent::ConfigError => e
204
+ log.warn "#{e}. This means multiple chunks are competing for a single symlink_path, so some logs may not be taken from the symlink."
205
+ end
206
+ end
207
+
208
+ @buffer.extend SymlinkBufferMixin
209
+ @buffer.symlink_path = @symlink_path
210
+ @buffer.output_plugin_for_symlink = self
211
+ end
212
+
213
+ if @compress != :text && @buffer.compress != :text && @buffer.compress != @compress_method
214
+ raise Fluent::ConfigError, "You cannot specify different compression formats for Buffer (Buffer: #{@buffer.compress}, Self: #{@compress})"
215
+ end
216
+ end
217
+
218
+ @dir_perm = system_config.dir_permission || Fluent::DEFAULT_DIR_PERMISSION
219
+ @file_perm = system_config.file_permission || Fluent::DEFAULT_FILE_PERMISSION
220
+ @need_lock = system_config.workers > 1
221
+ end
222
+
223
+ def multi_workers_ready?
224
+ true
225
+ end
226
+
227
+ def format(tag, time, record)
228
+ r = inject_values_to_record(tag, time, record)
229
+ @formatter.format(tag, time, r)
230
+ end
231
+
232
+ def write(chunk)
233
+ path = extract_placeholders(@path_template, chunk)
234
+ FileUtils.mkdir_p File.dirname(path), mode: @dir_perm
235
+
236
+ writer = case
237
+ when @compress_method.nil?
238
+ method(:write_without_compression)
239
+ when @compress_method != :text
240
+ if @buffer.compress == :text || @recompress
241
+ method(:write_with_compression).curry.call(@compress_method)
242
+ else
243
+ method(:write_from_compressed_chunk).curry.call(@compress_method)
244
+ end
245
+ else
246
+ raise "BUG: unknown compression method #{@compress_method}"
247
+ end
248
+
249
+ if @append
250
+ if @need_lock
251
+ acquire_worker_lock(path) do
252
+ writer.call(path, chunk)
253
+ end
254
+ else
255
+ writer.call(path, chunk)
256
+ end
257
+ else
258
+ find_filepath_available(path, with_lock: @need_lock) do |actual_path|
259
+ writer.call(actual_path, chunk)
260
+ path = actual_path
261
+ end
262
+ end
263
+
264
+ @last_written_path = path
265
+ end
266
+
267
+ def write_without_compression(path, chunk)
268
+ File.open(path, "ab", @file_perm) do |f|
269
+ chunk.write_to(f)
270
+ end
271
+ end
272
+
273
+ def write_with_compression(type, path, chunk)
274
+ File.open(path, "ab", @file_perm) do |f|
275
+ gz = nil
276
+ if type == :gzip
277
+ gz = Zlib::GzipWriter.new(f)
278
+ elsif type == :zstd
279
+ gz = Zstd::StreamWriter.new(f)
280
+ end
281
+ chunk.write_to(gz, compressed: :text)
282
+ gz.close
283
+ end
284
+ end
285
+
286
+ def write_from_compressed_chunk(type, path, chunk)
287
+ File.open(path, "ab", @file_perm) do |f|
288
+ chunk.write_to(f, compressed: type)
289
+ end
290
+ end
291
+
292
+ def timekey_to_timeformat(timekey)
293
+ case timekey
294
+ when nil then ''
295
+ when 0...60 then '%Y%m%d%H%M%S' # 60 exclusive
296
+ when 60...3600 then '%Y%m%d%H%M'
297
+ when 3600...86400 then '%Y%m%d%H'
298
+ else '%Y%m%d'
299
+ end
300
+ end
301
+
302
+ def compression_suffix(compress)
303
+ case compress
304
+ when :gzip then '.gz'
305
+ when :zstd then '.zstd'
306
+ when nil then ''
307
+ else
308
+ raise ArgumentError, "unknown compression type #{compress}"
309
+ end
310
+ end
311
+
312
+ # /path/to/dir/file.* -> /path/to/dir/file.%Y%m%d
313
+ # /path/to/dir/file.*.data -> /path/to/dir/file.%Y%m%d.data
314
+ # /path/to/dir/file -> /path/to/dir/file.%Y%m%d.log
315
+ # %Y%m%d -> %Y%m%d_** (non append)
316
+ # + .gz (gzipped)
317
+ ## TODO: remove time_slice_format when end of support of compat_parameters
318
+ def generate_path_template(original, timekey, append, compress, path_suffix: '', time_slice_format: nil)
319
+ comp_suffix = compression_suffix(compress)
320
+ index_placeholder = append ? '' : '_**'
321
+ if original.index('*')
322
+ raise "BUG: configuration error must be raised for path including '*' without timekey" unless timekey
323
+ time_placeholders_part = time_slice_format || timekey_to_timeformat(timekey)
324
+ original.gsub('*', time_placeholders_part + index_placeholder) + comp_suffix
325
+ else
326
+ if timekey
327
+ if time_slice_format
328
+ "#{original}.#{time_slice_format}#{index_placeholder}#{path_suffix}#{comp_suffix}"
329
+ else
330
+ time_placeholders = timekey_to_timeformat(timekey)
331
+ if time_placeholders.scan(/../).any?{|ph| original.include?(ph) }
332
+ raise Fluent::ConfigError, "insufficient timestamp placeholders in path" if time_placeholders.scan(/../).any?{|ph| !original.include?(ph) }
333
+ "#{original}#{index_placeholder}#{path_suffix}#{comp_suffix}"
334
+ else
335
+ "#{original}.#{time_placeholders}#{index_placeholder}#{path_suffix}#{comp_suffix}"
336
+ end
337
+ end
338
+ else
339
+ "#{original}#{index_placeholder}#{path_suffix}#{comp_suffix}"
340
+ end
341
+ end
342
+ end
343
+
344
+ def find_filepath_available(path_with_placeholder, with_lock: false) # for non-append
345
+ raise "BUG: index placeholder not found in path: #{path_with_placeholder}" unless path_with_placeholder.index('_**')
346
+ i = 0
347
+ dir_path = locked = nil
348
+ while true
349
+ path = path_with_placeholder.sub('_**', "_#{i}")
350
+ i += 1
351
+ next if File.exist?(path)
352
+
353
+ if with_lock
354
+ dir_path = path + '.lock'
355
+ locked = Dir.mkdir(dir_path) rescue false
356
+ next unless locked
357
+ # ensure that other worker doesn't create a file (and release lock)
358
+ # between previous File.exist? and Dir.mkdir
359
+ next if File.exist?(path)
360
+ end
361
+
362
+ break
363
+ end
364
+ yield path
365
+ ensure
366
+ if dir_path && locked && Dir.exist?(dir_path)
367
+ Dir.rmdir(dir_path) rescue nil
368
+ end
369
+ end
370
+ end
371
+ end