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.
- checksums.yaml +7 -0
- data/.rubocop.yml +116 -0
- data/ADOPTERS.md +5 -0
- data/AGENTS.md +46 -0
- data/AUTHORS +2 -0
- data/CHANGELOG.md +3324 -0
- data/CONTRIBUTING.md +45 -0
- data/GOVERNANCE.md +55 -0
- data/GithubWorkflow.md +78 -0
- data/LICENSE +202 -0
- data/MAINTAINERS.md +19 -0
- data/README.md +73 -0
- data/Rakefile +89 -0
- data/SECURITY.md +47 -0
- data/bin/fluent-binlog-reader +7 -0
- data/bin/fluent-ca-generate +6 -0
- data/bin/fluent-cap-ctl +7 -0
- data/bin/fluent-cat +5 -0
- data/bin/fluent-ctl +7 -0
- data/bin/fluent-debug +5 -0
- data/bin/fluent-gem +9 -0
- data/bin/fluent-plugin-config-format +5 -0
- data/bin/fluent-plugin-generate +5 -0
- data/bin/fluentd +15 -0
- data/code-of-conduct.md +3 -0
- data/docs/SECURITY_AUDIT.pdf +0 -0
- data/example/copy_roundrobin.conf +39 -0
- data/example/counter.conf +18 -0
- data/example/filter_stdout.conf +22 -0
- data/example/in_forward.conf +14 -0
- data/example/in_forward_client.conf +37 -0
- data/example/in_forward_shared_key.conf +15 -0
- data/example/in_forward_tls.conf +14 -0
- data/example/in_forward_users.conf +24 -0
- data/example/in_forward_workers.conf +21 -0
- data/example/in_http.conf +16 -0
- data/example/in_out_forward.conf +17 -0
- data/example/in_sample_blocks.conf +17 -0
- data/example/in_sample_with_compression.conf +23 -0
- data/example/in_syslog.conf +15 -0
- data/example/in_tail.conf +14 -0
- data/example/in_tcp.conf +13 -0
- data/example/in_udp.conf +13 -0
- data/example/logevents.conf +25 -0
- data/example/multi_filters.conf +61 -0
- data/example/out_copy.conf +20 -0
- data/example/out_exec_filter.conf +42 -0
- data/example/out_file.conf +13 -0
- data/example/out_forward.conf +35 -0
- data/example/out_forward_buf_file.conf +23 -0
- data/example/out_forward_client.conf +109 -0
- data/example/out_forward_heartbeat_none.conf +16 -0
- data/example/out_forward_sd.conf +17 -0
- data/example/out_forward_shared_key.conf +36 -0
- data/example/out_forward_tls.conf +18 -0
- data/example/out_forward_users.conf +65 -0
- data/example/out_null.conf +36 -0
- data/example/sd.yaml +8 -0
- data/example/secondary_file.conf +42 -0
- data/example/suppress_config_dump.conf +7 -0
- data/example/v0_12_filter.conf +78 -0
- data/example/v1_literal_example.conf +36 -0
- data/example/worker_section.conf +36 -0
- data/fluent.conf +139 -0
- data/lib/fluent/agent.rb +168 -0
- data/lib/fluent/capability.rb +87 -0
- data/lib/fluent/clock.rb +66 -0
- data/lib/fluent/command/binlog_reader.rb +244 -0
- data/lib/fluent/command/bundler_injection.rb +45 -0
- data/lib/fluent/command/ca_generate.rb +184 -0
- data/lib/fluent/command/cap_ctl.rb +174 -0
- data/lib/fluent/command/cat.rb +365 -0
- data/lib/fluent/command/ctl.rb +180 -0
- data/lib/fluent/command/debug.rb +103 -0
- data/lib/fluent/command/fluentd.rb +385 -0
- data/lib/fluent/command/plugin_config_formatter.rb +308 -0
- data/lib/fluent/command/plugin_generator.rb +365 -0
- data/lib/fluent/compat/call_super_mixin.rb +76 -0
- data/lib/fluent/compat/detach_process_mixin.rb +33 -0
- data/lib/fluent/compat/exec_util.rb +144 -0
- data/lib/fluent/compat/file_util.rb +54 -0
- data/lib/fluent/compat/filter.rb +68 -0
- data/lib/fluent/compat/formatter.rb +117 -0
- data/lib/fluent/compat/formatter_utils.rb +85 -0
- data/lib/fluent/compat/handle_tag_and_time_mixin.rb +62 -0
- data/lib/fluent/compat/handle_tag_name_mixin.rb +53 -0
- data/lib/fluent/compat/input.rb +49 -0
- data/lib/fluent/compat/output.rb +721 -0
- data/lib/fluent/compat/output_chain.rb +60 -0
- data/lib/fluent/compat/parser.rb +310 -0
- data/lib/fluent/compat/parser_utils.rb +40 -0
- data/lib/fluent/compat/propagate_default.rb +62 -0
- data/lib/fluent/compat/record_filter_mixin.rb +34 -0
- data/lib/fluent/compat/set_tag_key_mixin.rb +50 -0
- data/lib/fluent/compat/set_time_key_mixin.rb +69 -0
- data/lib/fluent/compat/socket_util.rb +165 -0
- data/lib/fluent/compat/string_util.rb +34 -0
- data/lib/fluent/compat/structured_format_mixin.rb +26 -0
- data/lib/fluent/compat/type_converter.rb +90 -0
- data/lib/fluent/config/basic_parser.rb +122 -0
- data/lib/fluent/config/configure_proxy.rb +424 -0
- data/lib/fluent/config/dsl.rb +152 -0
- data/lib/fluent/config/element.rb +265 -0
- data/lib/fluent/config/error.rb +44 -0
- data/lib/fluent/config/literal_parser.rb +305 -0
- data/lib/fluent/config/parser.rb +119 -0
- data/lib/fluent/config/section.rb +272 -0
- data/lib/fluent/config/types.rb +257 -0
- data/lib/fluent/config/v1_parser.rb +200 -0
- data/lib/fluent/config/yaml_parser/fluent_value.rb +47 -0
- data/lib/fluent/config/yaml_parser/loader.rb +124 -0
- data/lib/fluent/config/yaml_parser/parser.rb +179 -0
- data/lib/fluent/config/yaml_parser/section_builder.rb +107 -0
- data/lib/fluent/config/yaml_parser.rb +56 -0
- data/lib/fluent/config.rb +89 -0
- data/lib/fluent/configurable.rb +202 -0
- data/lib/fluent/counter/base_socket.rb +44 -0
- data/lib/fluent/counter/client.rb +297 -0
- data/lib/fluent/counter/error.rb +86 -0
- data/lib/fluent/counter/mutex_hash.rb +163 -0
- data/lib/fluent/counter/server.rb +273 -0
- data/lib/fluent/counter/store.rb +205 -0
- data/lib/fluent/counter/validator.rb +145 -0
- data/lib/fluent/counter.rb +23 -0
- data/lib/fluent/daemon.rb +14 -0
- data/lib/fluent/daemonizer.rb +88 -0
- data/lib/fluent/engine.rb +269 -0
- data/lib/fluent/env.rb +45 -0
- data/lib/fluent/error.rb +37 -0
- data/lib/fluent/event.rb +369 -0
- data/lib/fluent/event_router.rb +315 -0
- data/lib/fluent/ext_monitor_require.rb +28 -0
- data/lib/fluent/file_wrapper.rb +137 -0
- data/lib/fluent/filter.rb +21 -0
- data/lib/fluent/fluent_log_event_router.rb +139 -0
- data/lib/fluent/formatter.rb +23 -0
- data/lib/fluent/input.rb +21 -0
- data/lib/fluent/label.rb +46 -0
- data/lib/fluent/load.rb +33 -0
- data/lib/fluent/log/console_adapter.rb +66 -0
- data/lib/fluent/log.rb +775 -0
- data/lib/fluent/match.rb +187 -0
- data/lib/fluent/mixin.rb +31 -0
- data/lib/fluent/msgpack_factory.rb +111 -0
- data/lib/fluent/oj_options.rb +61 -0
- data/lib/fluent/output.rb +29 -0
- data/lib/fluent/output_chain.rb +23 -0
- data/lib/fluent/parser.rb +23 -0
- data/lib/fluent/plugin/bare_output.rb +88 -0
- data/lib/fluent/plugin/base.rb +219 -0
- data/lib/fluent/plugin/buf_file.rb +256 -0
- data/lib/fluent/plugin/buf_file_single.rb +272 -0
- data/lib/fluent/plugin/buf_memory.rb +34 -0
- data/lib/fluent/plugin/buffer/chunk.rb +313 -0
- data/lib/fluent/plugin/buffer/file_chunk.rb +432 -0
- data/lib/fluent/plugin/buffer/file_single_chunk.rb +325 -0
- data/lib/fluent/plugin/buffer/memory_chunk.rb +91 -0
- data/lib/fluent/plugin/buffer.rb +1063 -0
- data/lib/fluent/plugin/compressable.rb +87 -0
- data/lib/fluent/plugin/exec_util.rb +22 -0
- data/lib/fluent/plugin/extractor.rb +132 -0
- data/lib/fluent/plugin/file_util.rb +22 -0
- data/lib/fluent/plugin/filter.rb +119 -0
- data/lib/fluent/plugin/filter_grep.rb +189 -0
- data/lib/fluent/plugin/filter_parser.rb +124 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +325 -0
- data/lib/fluent/plugin/filter_stdout.rb +53 -0
- data/lib/fluent/plugin/formatter.rb +75 -0
- data/lib/fluent/plugin/formatter_csv.rb +92 -0
- data/lib/fluent/plugin/formatter_hash.rb +35 -0
- data/lib/fluent/plugin/formatter_json.rb +62 -0
- data/lib/fluent/plugin/formatter_ltsv.rb +44 -0
- data/lib/fluent/plugin/formatter_msgpack.rb +33 -0
- data/lib/fluent/plugin/formatter_out_file.rb +55 -0
- data/lib/fluent/plugin/formatter_single_value.rb +36 -0
- data/lib/fluent/plugin/formatter_stdout.rb +76 -0
- data/lib/fluent/plugin/formatter_tsv.rb +40 -0
- data/lib/fluent/plugin/in_debug_agent.rb +71 -0
- data/lib/fluent/plugin/in_dummy.rb +18 -0
- data/lib/fluent/plugin/in_exec.rb +124 -0
- data/lib/fluent/plugin/in_forward.rb +489 -0
- data/lib/fluent/plugin/in_gc_stat.rb +72 -0
- data/lib/fluent/plugin/in_http.rb +737 -0
- data/lib/fluent/plugin/in_monitor_agent.rb +406 -0
- data/lib/fluent/plugin/in_object_space.rb +93 -0
- data/lib/fluent/plugin/in_sample.rb +148 -0
- data/lib/fluent/plugin/in_syslog.rb +346 -0
- data/lib/fluent/plugin/in_tail/compatibility.rb +111 -0
- data/lib/fluent/plugin/in_tail/dir_watcher.rb +713 -0
- data/lib/fluent/plugin/in_tail/group_watch.rb +204 -0
- data/lib/fluent/plugin/in_tail/io_handler.rb +391 -0
- data/lib/fluent/plugin/in_tail/line_feeder.rb +230 -0
- data/lib/fluent/plugin/in_tail/position_file.rb +269 -0
- data/lib/fluent/plugin/in_tail/stat_watcher.rb +52 -0
- data/lib/fluent/plugin/in_tail/tail_watcher.rb +276 -0
- data/lib/fluent/plugin/in_tail/worker_pool.rb +298 -0
- data/lib/fluent/plugin/in_tail.rb +917 -0
- data/lib/fluent/plugin/in_tcp.rb +230 -0
- data/lib/fluent/plugin/in_udp.rb +101 -0
- data/lib/fluent/plugin/in_unix.rb +197 -0
- data/lib/fluent/plugin/input.rb +71 -0
- data/lib/fluent/plugin/metrics.rb +119 -0
- data/lib/fluent/plugin/metrics_local.rb +96 -0
- data/lib/fluent/plugin/multi_output.rb +179 -0
- data/lib/fluent/plugin/out_buffer.rb +40 -0
- data/lib/fluent/plugin/out_copy.rb +120 -0
- data/lib/fluent/plugin/out_exec.rb +105 -0
- data/lib/fluent/plugin/out_exec_filter.rb +319 -0
- data/lib/fluent/plugin/out_file.rb +371 -0
- data/lib/fluent/plugin/out_forward/ack_handler.rb +176 -0
- data/lib/fluent/plugin/out_forward/connection_manager.rb +131 -0
- data/lib/fluent/plugin/out_forward/error.rb +28 -0
- data/lib/fluent/plugin/out_forward/failure_detector.rb +84 -0
- data/lib/fluent/plugin/out_forward/handshake_protocol.rb +125 -0
- data/lib/fluent/plugin/out_forward/load_balancer.rb +114 -0
- data/lib/fluent/plugin/out_forward/socket_cache.rb +177 -0
- data/lib/fluent/plugin/out_forward.rb +865 -0
- data/lib/fluent/plugin/out_http.rb +419 -0
- data/lib/fluent/plugin/out_null.rb +74 -0
- data/lib/fluent/plugin/out_relabel.rb +32 -0
- data/lib/fluent/plugin/out_roundrobin.rb +84 -0
- data/lib/fluent/plugin/out_secondary_file.rb +148 -0
- data/lib/fluent/plugin/out_stdout.rb +81 -0
- data/lib/fluent/plugin/out_stream.rb +130 -0
- data/lib/fluent/plugin/output.rb +1688 -0
- data/lib/fluent/plugin/owned_by_mixin.rb +41 -0
- data/lib/fluent/plugin/parser.rb +274 -0
- data/lib/fluent/plugin/parser_apache.rb +28 -0
- data/lib/fluent/plugin/parser_apache2.rb +88 -0
- data/lib/fluent/plugin/parser_apache_error.rb +26 -0
- data/lib/fluent/plugin/parser_csv.rb +124 -0
- data/lib/fluent/plugin/parser_json.rb +118 -0
- data/lib/fluent/plugin/parser_ltsv.rb +49 -0
- data/lib/fluent/plugin/parser_msgpack.rb +72 -0
- data/lib/fluent/plugin/parser_multiline.rb +152 -0
- data/lib/fluent/plugin/parser_nginx.rb +28 -0
- data/lib/fluent/plugin/parser_none.rb +36 -0
- data/lib/fluent/plugin/parser_regexp.rb +68 -0
- data/lib/fluent/plugin/parser_syslog.rb +543 -0
- data/lib/fluent/plugin/parser_tsv.rb +47 -0
- data/lib/fluent/plugin/sd_file.rb +157 -0
- data/lib/fluent/plugin/sd_srv.rb +135 -0
- data/lib/fluent/plugin/sd_static.rb +58 -0
- data/lib/fluent/plugin/service_discovery.rb +65 -0
- data/lib/fluent/plugin/socket_util.rb +22 -0
- data/lib/fluent/plugin/storage.rb +84 -0
- data/lib/fluent/plugin/storage_local.rb +166 -0
- data/lib/fluent/plugin/string_util.rb +22 -0
- data/lib/fluent/plugin.rb +206 -0
- data/lib/fluent/plugin_helper/cert_option.rb +199 -0
- data/lib/fluent/plugin_helper/child_process.rb +369 -0
- data/lib/fluent/plugin_helper/compat_parameters.rb +343 -0
- data/lib/fluent/plugin_helper/counter.rb +51 -0
- data/lib/fluent/plugin_helper/event_emitter.rb +112 -0
- data/lib/fluent/plugin_helper/event_loop.rb +170 -0
- data/lib/fluent/plugin_helper/extract.rb +104 -0
- data/lib/fluent/plugin_helper/formatter.rb +147 -0
- data/lib/fluent/plugin_helper/http_server/app.rb +81 -0
- data/lib/fluent/plugin_helper/http_server/methods.rb +35 -0
- data/lib/fluent/plugin_helper/http_server/request.rb +53 -0
- data/lib/fluent/plugin_helper/http_server/router.rb +54 -0
- data/lib/fluent/plugin_helper/http_server/server.rb +116 -0
- data/lib/fluent/plugin_helper/http_server/ssl_context_builder.rb +41 -0
- data/lib/fluent/plugin_helper/http_server.rb +129 -0
- data/lib/fluent/plugin_helper/inject.rb +154 -0
- data/lib/fluent/plugin_helper/metrics.rb +136 -0
- data/lib/fluent/plugin_helper/parser.rb +147 -0
- data/lib/fluent/plugin_helper/record_accessor.rb +207 -0
- data/lib/fluent/plugin_helper/retry_state.rb +219 -0
- data/lib/fluent/plugin_helper/server.rb +840 -0
- data/lib/fluent/plugin_helper/service_discovery/manager.rb +146 -0
- data/lib/fluent/plugin_helper/service_discovery/round_robin_balancer.rb +43 -0
- data/lib/fluent/plugin_helper/service_discovery.rb +125 -0
- data/lib/fluent/plugin_helper/socket.rb +288 -0
- data/lib/fluent/plugin_helper/socket_option.rb +98 -0
- data/lib/fluent/plugin_helper/storage.rb +349 -0
- data/lib/fluent/plugin_helper/thread.rb +180 -0
- data/lib/fluent/plugin_helper/timer.rb +92 -0
- data/lib/fluent/plugin_helper.rb +75 -0
- data/lib/fluent/plugin_id.rb +93 -0
- data/lib/fluent/process.rb +22 -0
- data/lib/fluent/registry.rb +117 -0
- data/lib/fluent/root_agent.rb +468 -0
- data/lib/fluent/rpc.rb +95 -0
- data/lib/fluent/source_only_buffer_agent.rb +102 -0
- data/lib/fluent/static_config_analysis.rb +195 -0
- data/lib/fluent/supervisor.rb +1347 -0
- data/lib/fluent/system_config.rb +213 -0
- data/lib/fluent/test/base.rb +83 -0
- data/lib/fluent/test/driver/base.rb +231 -0
- data/lib/fluent/test/driver/base_owned.rb +83 -0
- data/lib/fluent/test/driver/base_owner.rb +135 -0
- data/lib/fluent/test/driver/event_feeder.rb +98 -0
- data/lib/fluent/test/driver/filter.rb +61 -0
- data/lib/fluent/test/driver/formatter.rb +30 -0
- data/lib/fluent/test/driver/input.rb +31 -0
- data/lib/fluent/test/driver/multi_output.rb +53 -0
- data/lib/fluent/test/driver/output.rb +102 -0
- data/lib/fluent/test/driver/parser.rb +30 -0
- data/lib/fluent/test/driver/storage.rb +30 -0
- data/lib/fluent/test/driver/test_event_router.rb +45 -0
- data/lib/fluent/test/filter_test.rb +77 -0
- data/lib/fluent/test/formatter_test.rb +65 -0
- data/lib/fluent/test/helpers.rb +138 -0
- data/lib/fluent/test/input_test.rb +174 -0
- data/lib/fluent/test/log.rb +79 -0
- data/lib/fluent/test/output_test.rb +156 -0
- data/lib/fluent/test/parser_test.rb +70 -0
- data/lib/fluent/test/startup_shutdown.rb +44 -0
- data/lib/fluent/test.rb +61 -0
- data/lib/fluent/time.rb +513 -0
- data/lib/fluent/timezone.rb +171 -0
- data/lib/fluent/tls.rb +105 -0
- data/lib/fluent/unique_id.rb +39 -0
- data/lib/fluent/variable_store.rb +40 -0
- data/lib/fluent/version.rb +21 -0
- data/lib/fluent/win32api.rb +38 -0
- data/lib/fluent/winsvc.rb +130 -0
- data/templates/new_gem/.gitignore +8 -0
- data/templates/new_gem/Gemfile +3 -0
- data/templates/new_gem/README.md.erb +43 -0
- data/templates/new_gem/Rakefile +13 -0
- data/templates/new_gem/fluent-plugin.gemspec.erb +28 -0
- data/templates/new_gem/lib/fluent/plugin/filter.rb.erb +14 -0
- data/templates/new_gem/lib/fluent/plugin/formatter.rb.erb +14 -0
- data/templates/new_gem/lib/fluent/plugin/input.rb.erb +11 -0
- data/templates/new_gem/lib/fluent/plugin/output.rb.erb +11 -0
- data/templates/new_gem/lib/fluent/plugin/parser.rb.erb +15 -0
- data/templates/new_gem/lib/fluent/plugin/storage.rb.erb +40 -0
- data/templates/new_gem/test/helper.rb.erb +7 -0
- data/templates/new_gem/test/plugin/test_filter.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_formatter.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_input.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_output.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_parser.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_storage.rb.erb +18 -0
- data/templates/plugin_config_formatter/param.md-compact.erb +25 -0
- data/templates/plugin_config_formatter/param.md-table.erb +10 -0
- data/templates/plugin_config_formatter/param.md.erb +34 -0
- data/templates/plugin_config_formatter/section.md.erb +12 -0
- 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
|