fluentd 1.13.3 → 1.16.5
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 +4 -4
- data/.github/ISSUE_TEMPLATE/{bug_report.yaml → bug_report.yml} +2 -0
- data/.github/ISSUE_TEMPLATE/config.yml +2 -2
- data/.github/ISSUE_TEMPLATE/{feature_request.yaml → feature_request.yml} +1 -0
- data/.github/workflows/stale-actions.yml +11 -9
- data/.github/workflows/test.yml +32 -0
- data/CHANGELOG.md +490 -10
- data/CONTRIBUTING.md +2 -2
- data/MAINTAINERS.md +7 -5
- data/README.md +3 -23
- data/Rakefile +1 -1
- data/SECURITY.md +14 -0
- data/fluentd.gemspec +7 -8
- data/lib/fluent/command/cat.rb +13 -3
- data/lib/fluent/command/ctl.rb +6 -3
- data/lib/fluent/command/fluentd.rb +73 -65
- data/lib/fluent/command/plugin_config_formatter.rb +1 -1
- data/lib/fluent/compat/output.rb +9 -6
- data/lib/fluent/config/dsl.rb +1 -1
- data/lib/fluent/config/error.rb +12 -0
- data/lib/fluent/config/literal_parser.rb +2 -2
- data/lib/fluent/config/parser.rb +1 -1
- data/lib/fluent/config/v1_parser.rb +3 -3
- data/lib/fluent/config/yaml_parser/fluent_value.rb +47 -0
- data/lib/fluent/config/yaml_parser/loader.rb +108 -0
- data/lib/fluent/config/yaml_parser/parser.rb +166 -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 +14 -1
- data/lib/fluent/counter/server.rb +1 -1
- data/lib/fluent/counter/validator.rb +3 -3
- data/lib/fluent/daemon.rb +2 -4
- data/lib/fluent/engine.rb +1 -1
- data/lib/fluent/env.rb +4 -0
- data/lib/fluent/error.rb +3 -0
- data/lib/fluent/event.rb +8 -4
- data/lib/fluent/event_router.rb +47 -2
- data/lib/fluent/file_wrapper.rb +137 -0
- data/lib/fluent/log/console_adapter.rb +66 -0
- data/lib/fluent/log.rb +44 -5
- data/lib/fluent/match.rb +1 -1
- data/lib/fluent/msgpack_factory.rb +6 -1
- data/lib/fluent/oj_options.rb +1 -2
- data/lib/fluent/plugin/bare_output.rb +49 -8
- data/lib/fluent/plugin/base.rb +26 -9
- data/lib/fluent/plugin/buf_file.rb +34 -5
- data/lib/fluent/plugin/buf_file_single.rb +32 -3
- data/lib/fluent/plugin/buffer/file_chunk.rb +1 -1
- data/lib/fluent/plugin/buffer.rb +216 -70
- data/lib/fluent/plugin/filter.rb +35 -1
- data/lib/fluent/plugin/filter_record_transformer.rb +1 -1
- data/lib/fluent/plugin/in_forward.rb +2 -2
- data/lib/fluent/plugin/in_http.rb +39 -10
- data/lib/fluent/plugin/in_monitor_agent.rb +4 -2
- data/lib/fluent/plugin/in_sample.rb +1 -1
- data/lib/fluent/plugin/in_syslog.rb +13 -1
- data/lib/fluent/plugin/in_tail/group_watch.rb +204 -0
- data/lib/fluent/plugin/in_tail/position_file.rb +33 -33
- data/lib/fluent/plugin/in_tail.rb +216 -84
- data/lib/fluent/plugin/in_tcp.rb +47 -2
- data/lib/fluent/plugin/input.rb +39 -1
- data/lib/fluent/plugin/metrics.rb +119 -0
- data/lib/fluent/plugin/metrics_local.rb +96 -0
- data/lib/fluent/plugin/multi_output.rb +43 -6
- data/lib/fluent/plugin/out_copy.rb +1 -1
- data/lib/fluent/plugin/out_exec_filter.rb +2 -2
- data/lib/fluent/plugin/out_file.rb +20 -2
- data/lib/fluent/plugin/out_forward/ack_handler.rb +19 -4
- data/lib/fluent/plugin/out_forward/socket_cache.rb +2 -0
- data/lib/fluent/plugin/out_forward.rb +17 -9
- data/lib/fluent/plugin/out_secondary_file.rb +39 -22
- data/lib/fluent/plugin/output.rb +167 -78
- data/lib/fluent/plugin/parser.rb +3 -4
- data/lib/fluent/plugin/parser_apache2.rb +1 -1
- data/lib/fluent/plugin/parser_json.rb +1 -1
- data/lib/fluent/plugin/parser_syslog.rb +1 -1
- data/lib/fluent/plugin/storage_local.rb +3 -5
- data/lib/fluent/plugin.rb +10 -1
- data/lib/fluent/plugin_helper/child_process.rb +3 -0
- data/lib/fluent/plugin_helper/event_emitter.rb +8 -1
- data/lib/fluent/plugin_helper/event_loop.rb +2 -2
- data/lib/fluent/plugin_helper/http_server/server.rb +2 -1
- data/lib/fluent/plugin_helper/metrics.rb +129 -0
- data/lib/fluent/plugin_helper/record_accessor.rb +1 -1
- data/lib/fluent/plugin_helper/retry_state.rb +14 -4
- data/lib/fluent/plugin_helper/server.rb +35 -6
- data/lib/fluent/plugin_helper/service_discovery.rb +2 -2
- data/lib/fluent/plugin_helper/socket.rb +13 -2
- data/lib/fluent/plugin_helper/thread.rb +3 -3
- data/lib/fluent/plugin_helper.rb +1 -0
- data/lib/fluent/plugin_id.rb +3 -2
- data/lib/fluent/registry.rb +2 -1
- data/lib/fluent/root_agent.rb +6 -0
- data/lib/fluent/rpc.rb +4 -3
- data/lib/fluent/supervisor.rb +283 -259
- data/lib/fluent/system_config.rb +13 -3
- data/lib/fluent/test/driver/base.rb +11 -5
- data/lib/fluent/test/driver/filter.rb +4 -0
- data/lib/fluent/test/startup_shutdown.rb +6 -8
- data/lib/fluent/time.rb +21 -20
- data/lib/fluent/version.rb +1 -1
- data/lib/fluent/win32api.rb +38 -0
- data/lib/fluent/winsvc.rb +5 -8
- data/templates/new_gem/test/helper.rb.erb +0 -1
- data/test/command/test_cat.rb +31 -2
- data/test/command/test_ctl.rb +1 -2
- data/test/command/test_fluentd.rb +209 -24
- data/test/command/test_plugin_config_formatter.rb +0 -1
- data/test/compat/test_parser.rb +6 -6
- data/test/config/test_system_config.rb +13 -11
- data/test/config/test_types.rb +1 -1
- data/test/log/test_console_adapter.rb +110 -0
- data/test/plugin/in_tail/test_io_handler.rb +26 -8
- data/test/plugin/in_tail/test_position_file.rb +48 -59
- data/test/plugin/out_forward/test_ack_handler.rb +39 -0
- data/test/plugin/out_forward/test_socket_cache.rb +26 -1
- data/test/plugin/test_bare_output.rb +14 -1
- data/test/plugin/test_base.rb +133 -1
- data/test/plugin/test_buf_file.rb +62 -23
- data/test/plugin/test_buf_file_single.rb +65 -0
- data/test/plugin/test_buffer.rb +267 -3
- data/test/plugin/test_buffer_chunk.rb +11 -0
- data/test/plugin/test_filter.rb +12 -1
- data/test/plugin/test_filter_parser.rb +1 -1
- data/test/plugin/test_filter_stdout.rb +2 -2
- data/test/plugin/test_in_forward.rb +9 -11
- data/test/plugin/test_in_http.rb +65 -3
- data/test/plugin/test_in_monitor_agent.rb +216 -11
- data/test/plugin/test_in_object_space.rb +9 -3
- data/test/plugin/test_in_syslog.rb +35 -0
- data/test/plugin/test_in_tail.rb +1393 -385
- data/test/plugin/test_in_tcp.rb +87 -2
- data/test/plugin/test_in_udp.rb +28 -0
- data/test/plugin/test_in_unix.rb +2 -2
- data/test/plugin/test_input.rb +12 -1
- data/test/plugin/test_metrics.rb +294 -0
- data/test/plugin/test_metrics_local.rb +96 -0
- data/test/plugin/test_multi_output.rb +25 -1
- data/test/plugin/test_out_exec.rb +6 -4
- data/test/plugin/test_out_exec_filter.rb +6 -2
- data/test/plugin/test_out_file.rb +34 -17
- data/test/plugin/test_out_forward.rb +78 -77
- data/test/plugin/test_out_http.rb +1 -0
- data/test/plugin/test_out_stdout.rb +2 -2
- data/test/plugin/test_output.rb +297 -12
- data/test/plugin/test_output_as_buffered.rb +44 -44
- data/test/plugin/test_output_as_buffered_compress.rb +32 -18
- data/test/plugin/test_output_as_buffered_retries.rb +54 -7
- data/test/plugin/test_output_as_buffered_secondary.rb +4 -4
- data/test/plugin/test_parser_regexp.rb +1 -6
- data/test/plugin/test_parser_syslog.rb +1 -1
- data/test/plugin_helper/test_cert_option.rb +1 -1
- data/test/plugin_helper/test_child_process.rb +38 -16
- data/test/plugin_helper/test_event_emitter.rb +29 -0
- data/test/plugin_helper/test_http_server_helper.rb +1 -1
- data/test/plugin_helper/test_metrics.rb +137 -0
- data/test/plugin_helper/test_retry_state.rb +602 -38
- data/test/plugin_helper/test_server.rb +78 -6
- data/test/plugin_helper/test_timer.rb +2 -2
- data/test/test_config.rb +191 -24
- data/test/test_event_router.rb +17 -0
- data/test/test_file_wrapper.rb +53 -0
- data/test/test_formatter.rb +24 -21
- data/test/test_log.rb +122 -40
- data/test/test_msgpack_factory.rb +32 -0
- data/test/test_plugin_classes.rb +102 -0
- data/test/test_root_agent.rb +30 -1
- data/test/test_supervisor.rb +477 -257
- data/test/test_time_parser.rb +22 -0
- metadata +55 -34
- data/.drone.yml +0 -35
- data/.github/workflows/issue-auto-closer.yml +0 -12
- data/.github/workflows/linux-test.yaml +0 -36
- data/.github/workflows/macos-test.yaml +0 -30
- data/.github/workflows/windows-test.yaml +0 -46
- data/.gitlab-ci.yml +0 -103
- data/lib/fluent/plugin/file_wrapper.rb +0 -187
- data/test/plugin/test_file_wrapper.rb +0 -126
- data/test/test_logger_initializer.rb +0 -46
|
@@ -64,31 +64,29 @@ module Fluent::Plugin
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def multi_workers_ready?
|
|
67
|
-
### TODO: add hack to synchronize for multi workers
|
|
68
67
|
true
|
|
69
68
|
end
|
|
70
69
|
|
|
71
70
|
def write(chunk)
|
|
72
71
|
path_without_suffix = extract_placeholders(@path_without_suffix, chunk)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
72
|
+
generate_path(path_without_suffix) do |path|
|
|
73
|
+
FileUtils.mkdir_p File.dirname(path), mode: @dir_perm
|
|
74
|
+
|
|
75
|
+
case @compress
|
|
76
|
+
when :text
|
|
77
|
+
File.open(path, "ab", @file_perm) {|f|
|
|
78
|
+
f.flock(File::LOCK_EX)
|
|
79
|
+
chunk.write_to(f)
|
|
80
|
+
}
|
|
81
|
+
when :gzip
|
|
82
|
+
File.open(path, "ab", @file_perm) {|f|
|
|
83
|
+
f.flock(File::LOCK_EX)
|
|
84
|
+
gz = Zlib::GzipWriter.new(f)
|
|
85
|
+
chunk.write_to(gz)
|
|
86
|
+
gz.close
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
89
|
end
|
|
90
|
-
|
|
91
|
-
path
|
|
92
90
|
end
|
|
93
91
|
|
|
94
92
|
private
|
|
@@ -117,15 +115,34 @@ module Fluent::Plugin
|
|
|
117
115
|
|
|
118
116
|
def generate_path(path_without_suffix)
|
|
119
117
|
if @append
|
|
120
|
-
"#{path_without_suffix}#{@suffix}"
|
|
121
|
-
|
|
118
|
+
path = "#{path_without_suffix}#{@suffix}"
|
|
119
|
+
synchronize_path(path) do
|
|
120
|
+
yield path
|
|
121
|
+
end
|
|
122
|
+
return path
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
begin
|
|
122
126
|
i = 0
|
|
123
127
|
loop do
|
|
124
128
|
path = "#{path_without_suffix}.#{i}#{@suffix}"
|
|
125
|
-
|
|
129
|
+
break unless File.exist?(path)
|
|
126
130
|
i += 1
|
|
127
131
|
end
|
|
132
|
+
synchronize_path(path) do
|
|
133
|
+
# If multiple processes or threads select the same path and another
|
|
134
|
+
# one entered this locking block first, the file should already
|
|
135
|
+
# exist and this one should retry to find new path.
|
|
136
|
+
raise FileAlreadyExist if File.exist?(path)
|
|
137
|
+
yield path
|
|
138
|
+
end
|
|
139
|
+
rescue FileAlreadyExist
|
|
140
|
+
retry
|
|
128
141
|
end
|
|
142
|
+
path
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
class FileAlreadyExist < StandardError
|
|
129
146
|
end
|
|
130
147
|
end
|
|
131
148
|
end
|
data/lib/fluent/plugin/output.rb
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
|
|
17
|
+
require 'fluent/env'
|
|
17
18
|
require 'fluent/error'
|
|
18
19
|
require 'fluent/plugin/base'
|
|
19
20
|
require 'fluent/plugin/buffer'
|
|
@@ -37,7 +38,7 @@ module Fluent
|
|
|
37
38
|
include PluginHelper::Mixin
|
|
38
39
|
include UniqueId::Mixin
|
|
39
40
|
|
|
40
|
-
helpers_internal :thread, :retry_state
|
|
41
|
+
helpers_internal :thread, :retry_state, :metrics
|
|
41
42
|
|
|
42
43
|
CHUNK_KEY_PATTERN = /^[-_.@a-zA-Z0-9]+$/
|
|
43
44
|
CHUNK_KEY_PLACEHOLDER_PATTERN = /\$\{([-_.@$a-zA-Z0-9]+)\}/
|
|
@@ -98,7 +99,6 @@ module Fluent
|
|
|
98
99
|
config_param :retry_max_interval, :time, default: nil, desc: 'The maximum interval seconds for exponential backoff between retries while failing.'
|
|
99
100
|
|
|
100
101
|
config_param :retry_randomize, :bool, default: true, desc: 'If true, output plugin will retry after randomized interval not to do burst retries.'
|
|
101
|
-
config_param :disable_chunk_backup, :bool, default: false, desc: 'If true, chunks are thrown away when unrecoverable error happens'
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
config_section :secondary, param_name: :secondary_config, required: false, multi: false, final: true do
|
|
@@ -164,7 +164,6 @@ module Fluent
|
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
attr_reader :as_secondary, :delayed_commit, :delayed_commit_timeout, :timekey_zone
|
|
167
|
-
attr_reader :num_errors, :emit_count, :emit_records, :write_count, :rollback_count
|
|
168
167
|
|
|
169
168
|
# for tests
|
|
170
169
|
attr_reader :buffer, :retry, :secondary, :chunk_keys, :chunk_key_accessors, :chunk_key_time, :chunk_key_tag
|
|
@@ -172,22 +171,49 @@ module Fluent
|
|
|
172
171
|
# output_enqueue_thread_waiting: for test of output.rb itself
|
|
173
172
|
attr_accessor :retry_for_error_chunk # if true, error flush will be retried even if under_plugin_development is true
|
|
174
173
|
|
|
174
|
+
def num_errors
|
|
175
|
+
@num_errors_metrics.get
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def emit_count
|
|
179
|
+
@emit_count_metrics.get
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def emit_size
|
|
183
|
+
@emit_size_metrics.get
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def emit_records
|
|
187
|
+
@emit_records_metrics.get
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def write_count
|
|
191
|
+
@write_count_metrics.get
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def rollback_count
|
|
195
|
+
@rollback_count_metrics.get
|
|
196
|
+
end
|
|
197
|
+
|
|
175
198
|
def initialize
|
|
176
199
|
super
|
|
177
200
|
@counter_mutex = Mutex.new
|
|
201
|
+
@flush_thread_mutex = Mutex.new
|
|
178
202
|
@buffering = false
|
|
179
203
|
@delayed_commit = false
|
|
180
204
|
@as_secondary = false
|
|
181
205
|
@primary_instance = nil
|
|
182
206
|
|
|
183
207
|
# TODO: well organized counters
|
|
184
|
-
@
|
|
185
|
-
@
|
|
186
|
-
@
|
|
187
|
-
@
|
|
188
|
-
@
|
|
189
|
-
@
|
|
190
|
-
@
|
|
208
|
+
@num_errors_metrics = nil
|
|
209
|
+
@emit_count_metrics = nil
|
|
210
|
+
@emit_records_metrics = nil
|
|
211
|
+
@emit_size_metrics = nil
|
|
212
|
+
@write_count_metrics = nil
|
|
213
|
+
@rollback_count_metrics = nil
|
|
214
|
+
@flush_time_count_metrics = nil
|
|
215
|
+
@slow_flush_count_metrics = nil
|
|
216
|
+
@enable_size_metrics = false
|
|
191
217
|
|
|
192
218
|
# How to process events is decided here at once, but it will be decided in delayed way on #configure & #start
|
|
193
219
|
if implement?(:synchronous)
|
|
@@ -209,6 +235,7 @@ module Fluent
|
|
|
209
235
|
@dequeued_chunks_mutex = nil
|
|
210
236
|
@output_enqueue_thread = nil
|
|
211
237
|
@output_flush_threads = nil
|
|
238
|
+
@output_flush_thread_current_position = 0
|
|
212
239
|
|
|
213
240
|
@simple_chunking = nil
|
|
214
241
|
@chunk_keys = @chunk_key_accessors = @chunk_key_time = @chunk_key_tag = nil
|
|
@@ -246,6 +273,15 @@ module Fluent
|
|
|
246
273
|
|
|
247
274
|
super
|
|
248
275
|
|
|
276
|
+
@num_errors_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "num_errors", help_text: "Number of count num errors")
|
|
277
|
+
@emit_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "emit_count", help_text: "Number of count emits")
|
|
278
|
+
@emit_records_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "emit_records", help_text: "Number of emit records")
|
|
279
|
+
@emit_size_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "emit_size", help_text: "Total size of emit events")
|
|
280
|
+
@write_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "write_count", help_text: "Number of writing events")
|
|
281
|
+
@rollback_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "rollback_count", help_text: "Number of rollbacking operations")
|
|
282
|
+
@flush_time_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "flush_time_count", help_text: "Count of flush time")
|
|
283
|
+
@slow_flush_count_metrics = metrics_create(namespace: "fluentd", subsystem: "output", name: "slow_flush_count", help_text: "Count of slow flush occurred time(s)")
|
|
284
|
+
|
|
249
285
|
if has_buffer_section
|
|
250
286
|
unless implement?(:buffered) || implement?(:delayed_commit)
|
|
251
287
|
raise Fluent::ConfigError, "<buffer> section is configured, but plugin '#{self.class}' doesn't support buffering"
|
|
@@ -271,6 +307,8 @@ module Fluent
|
|
|
271
307
|
@buffering = true
|
|
272
308
|
end
|
|
273
309
|
end
|
|
310
|
+
# Enable to update record size metrics or not
|
|
311
|
+
@enable_size_metrics = !!system_config.enable_size_metrics
|
|
274
312
|
|
|
275
313
|
if @as_secondary
|
|
276
314
|
if !@buffering && !@buffering.nil?
|
|
@@ -340,6 +378,7 @@ module Fluent
|
|
|
340
378
|
buffer_conf = conf.elements(name: 'buffer').first || Fluent::Config::Element.new('buffer', '', {}, [])
|
|
341
379
|
@buffer = Plugin.new_buffer(buffer_type, parent: self)
|
|
342
380
|
@buffer.configure(buffer_conf)
|
|
381
|
+
keep_buffer_config_compat
|
|
343
382
|
@buffer.enable_update_timekeys if @chunk_key_time
|
|
344
383
|
|
|
345
384
|
@flush_at_shutdown = @buffer_config.flush_at_shutdown
|
|
@@ -387,7 +426,9 @@ module Fluent
|
|
|
387
426
|
end
|
|
388
427
|
@secondary.acts_as_secondary(self)
|
|
389
428
|
@secondary.configure(secondary_conf)
|
|
390
|
-
if (
|
|
429
|
+
if (@secondary.class.to_s != "Fluent::Plugin::SecondaryFileOutput") &&
|
|
430
|
+
(self.class != @secondary.class) &&
|
|
431
|
+
(@custom_format || @secondary.implement?(:custom_format))
|
|
391
432
|
log.warn "Use different plugin for secondary. Check the plugin works with primary like secondary_file", primary: self.class.to_s, secondary: @secondary.class.to_s
|
|
392
433
|
end
|
|
393
434
|
else
|
|
@@ -397,6 +438,12 @@ module Fluent
|
|
|
397
438
|
self
|
|
398
439
|
end
|
|
399
440
|
|
|
441
|
+
def keep_buffer_config_compat
|
|
442
|
+
# Need this to call `@buffer_config.disable_chunk_backup` just as before,
|
|
443
|
+
# since some plugins may use this option in this way.
|
|
444
|
+
@buffer_config[:disable_chunk_backup] = @buffer.disable_chunk_backup
|
|
445
|
+
end
|
|
446
|
+
|
|
400
447
|
def start
|
|
401
448
|
super
|
|
402
449
|
|
|
@@ -455,6 +502,7 @@ module Fluent
|
|
|
455
502
|
@dequeued_chunks = []
|
|
456
503
|
@dequeued_chunks_mutex = Mutex.new
|
|
457
504
|
|
|
505
|
+
@output_flush_thread_current_position = 0
|
|
458
506
|
@buffer_config.flush_thread_count.times do |i|
|
|
459
507
|
thread_title = "flush_thread_#{i}".to_sym
|
|
460
508
|
thread_state = FlushThreadState.new(nil, nil, Mutex.new, ConditionVariable.new)
|
|
@@ -466,7 +514,6 @@ module Fluent
|
|
|
466
514
|
@output_flush_threads << thread_state
|
|
467
515
|
end
|
|
468
516
|
end
|
|
469
|
-
@output_flush_thread_current_position = 0
|
|
470
517
|
|
|
471
518
|
if !@under_plugin_development && (@flush_mode == :interval || @chunk_key_time)
|
|
472
519
|
@output_enqueue_thread = thread_create(:enqueue_thread, &method(:enqueue_thread_run))
|
|
@@ -553,6 +600,42 @@ module Fluent
|
|
|
553
600
|
super
|
|
554
601
|
end
|
|
555
602
|
|
|
603
|
+
def actual_flush_thread_count
|
|
604
|
+
return 0 unless @buffering
|
|
605
|
+
return @buffer_config.flush_thread_count unless @as_secondary
|
|
606
|
+
@primary_instance.buffer_config.flush_thread_count
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
# Ensures `path` (filename or filepath) processable
|
|
610
|
+
# only by the current thread in the current process.
|
|
611
|
+
# For multiple workers, the lock is shared if `path` is the same value.
|
|
612
|
+
# For multiple threads, the lock is shared by all threads in the same process.
|
|
613
|
+
def synchronize_path(path)
|
|
614
|
+
synchronize_path_in_workers(path) do
|
|
615
|
+
synchronize_in_threads do
|
|
616
|
+
yield
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
def synchronize_path_in_workers(path)
|
|
622
|
+
need_worker_lock = system_config.workers > 1
|
|
623
|
+
if need_worker_lock
|
|
624
|
+
acquire_worker_lock(path) { yield }
|
|
625
|
+
else
|
|
626
|
+
yield
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
def synchronize_in_threads
|
|
631
|
+
need_thread_lock = actual_flush_thread_count > 1
|
|
632
|
+
if need_thread_lock
|
|
633
|
+
@flush_thread_mutex.synchronize { yield }
|
|
634
|
+
else
|
|
635
|
+
yield
|
|
636
|
+
end
|
|
637
|
+
end
|
|
638
|
+
|
|
556
639
|
def support_in_v12_style?(feature)
|
|
557
640
|
# for plugins written in v0.12 styles
|
|
558
641
|
case feature
|
|
@@ -741,7 +824,7 @@ module Fluent
|
|
|
741
824
|
if str.include?('${tag}')
|
|
742
825
|
rvalue = rvalue.gsub('${tag}', metadata.tag)
|
|
743
826
|
end
|
|
744
|
-
if str
|
|
827
|
+
if CHUNK_TAG_PLACEHOLDER_PATTERN.match?(str)
|
|
745
828
|
hash = {}
|
|
746
829
|
tag_parts = metadata.tag.split('.')
|
|
747
830
|
tag_parts.each_with_index do |part, i|
|
|
@@ -797,18 +880,19 @@ module Fluent
|
|
|
797
880
|
end
|
|
798
881
|
|
|
799
882
|
def emit_sync(tag, es)
|
|
800
|
-
@
|
|
883
|
+
@emit_count_metrics.inc
|
|
801
884
|
begin
|
|
802
885
|
process(tag, es)
|
|
803
|
-
@
|
|
886
|
+
@emit_records_metrics.add(es.size)
|
|
887
|
+
@emit_size_metrics.add(es.to_msgpack_stream.bytesize) if @enable_size_metrics
|
|
804
888
|
rescue
|
|
805
|
-
@
|
|
889
|
+
@num_errors_metrics.inc
|
|
806
890
|
raise
|
|
807
891
|
end
|
|
808
892
|
end
|
|
809
893
|
|
|
810
894
|
def emit_buffered(tag, es)
|
|
811
|
-
@
|
|
895
|
+
@emit_count_metrics.inc
|
|
812
896
|
begin
|
|
813
897
|
execute_chunking(tag, es, enqueue: (@flush_mode == :immediate))
|
|
814
898
|
if !@retry && @buffer.queued?(nil, optimistic: true)
|
|
@@ -816,7 +900,7 @@ module Fluent
|
|
|
816
900
|
end
|
|
817
901
|
rescue
|
|
818
902
|
# TODO: separate number of errors into emit errors and write/flush errors
|
|
819
|
-
@
|
|
903
|
+
@num_errors_metrics.inc
|
|
820
904
|
raise
|
|
821
905
|
end
|
|
822
906
|
end
|
|
@@ -966,7 +1050,8 @@ module Fluent
|
|
|
966
1050
|
write_guard do
|
|
967
1051
|
@buffer.write(meta_and_data, enqueue: enqueue)
|
|
968
1052
|
end
|
|
969
|
-
@
|
|
1053
|
+
@emit_records_metrics.add(es.size)
|
|
1054
|
+
@emit_size_metrics.add(es.to_msgpack_stream.bytesize) if @enable_size_metrics
|
|
970
1055
|
true
|
|
971
1056
|
end
|
|
972
1057
|
|
|
@@ -983,7 +1068,8 @@ module Fluent
|
|
|
983
1068
|
write_guard do
|
|
984
1069
|
@buffer.write(meta_and_data, format: format_proc, enqueue: enqueue)
|
|
985
1070
|
end
|
|
986
|
-
@
|
|
1071
|
+
@emit_records_metrics.add(es.size)
|
|
1072
|
+
@emit_size_metrics.add(es.to_msgpack_stream.bytesize) if @enable_size_metrics
|
|
987
1073
|
true
|
|
988
1074
|
end
|
|
989
1075
|
|
|
@@ -1008,7 +1094,8 @@ module Fluent
|
|
|
1008
1094
|
write_guard do
|
|
1009
1095
|
@buffer.write({meta => data}, format: format_proc, enqueue: enqueue)
|
|
1010
1096
|
end
|
|
1011
|
-
@
|
|
1097
|
+
@emit_records_metrics.add(es.size)
|
|
1098
|
+
@emit_size_metrics.add(es.to_msgpack_stream.bytesize) if @enable_size_metrics
|
|
1012
1099
|
true
|
|
1013
1100
|
end
|
|
1014
1101
|
|
|
@@ -1046,7 +1133,7 @@ module Fluent
|
|
|
1046
1133
|
# false if chunk was already flushed and couldn't be rollbacked unexpectedly
|
|
1047
1134
|
# in many cases, false can be just ignored
|
|
1048
1135
|
if @buffer.takeback_chunk(chunk_id)
|
|
1049
|
-
@
|
|
1136
|
+
@rollback_count_metrics.inc
|
|
1050
1137
|
if update_retry
|
|
1051
1138
|
primary = @as_secondary ? @primary_instance : self
|
|
1052
1139
|
primary.update_retry_state(chunk_id, @as_secondary)
|
|
@@ -1062,7 +1149,7 @@ module Fluent
|
|
|
1062
1149
|
while @dequeued_chunks.first && @dequeued_chunks.first.expired?
|
|
1063
1150
|
info = @dequeued_chunks.shift
|
|
1064
1151
|
if @buffer.takeback_chunk(info.chunk_id)
|
|
1065
|
-
@
|
|
1152
|
+
@rollback_count_metrics.inc
|
|
1066
1153
|
log.warn "failed to flush the buffer chunk, timeout to commit.", chunk_id: dump_unique_id_hex(info.chunk_id), flushed_at: info.time
|
|
1067
1154
|
primary = @as_secondary ? @primary_instance : self
|
|
1068
1155
|
primary.update_retry_state(info.chunk_id, @as_secondary)
|
|
@@ -1077,7 +1164,7 @@ module Fluent
|
|
|
1077
1164
|
until @dequeued_chunks.empty?
|
|
1078
1165
|
info = @dequeued_chunks.shift
|
|
1079
1166
|
if @buffer.takeback_chunk(info.chunk_id)
|
|
1080
|
-
@
|
|
1167
|
+
@rollback_count_metrics.inc
|
|
1081
1168
|
log.info "delayed commit for buffer chunks was cancelled in shutdown", chunk_id: dump_unique_id_hex(info.chunk_id)
|
|
1082
1169
|
primary = @as_secondary ? @primary_instance : self
|
|
1083
1170
|
primary.update_retry_state(info.chunk_id, @as_secondary)
|
|
@@ -1120,7 +1207,7 @@ module Fluent
|
|
|
1120
1207
|
|
|
1121
1208
|
if output.delayed_commit
|
|
1122
1209
|
log.trace "executing delayed write and commit", chunk: dump_unique_id_hex(chunk.unique_id)
|
|
1123
|
-
@
|
|
1210
|
+
@write_count_metrics.inc
|
|
1124
1211
|
@dequeued_chunks_mutex.synchronize do
|
|
1125
1212
|
# delayed_commit_timeout for secondary is configured in <buffer> of primary (<secondary> don't get <buffer>)
|
|
1126
1213
|
@dequeued_chunks << DequeuedChunkInfo.new(chunk.unique_id, Time.now, self.delayed_commit_timeout)
|
|
@@ -1132,7 +1219,7 @@ module Fluent
|
|
|
1132
1219
|
chunk_id = chunk.unique_id
|
|
1133
1220
|
dump_chunk_id = dump_unique_id_hex(chunk_id)
|
|
1134
1221
|
log.trace "adding write count", instance: self.object_id
|
|
1135
|
-
@
|
|
1222
|
+
@write_count_metrics.inc
|
|
1136
1223
|
log.trace "executing sync write", chunk: dump_chunk_id
|
|
1137
1224
|
|
|
1138
1225
|
output.write(chunk)
|
|
@@ -1188,7 +1275,7 @@ module Fluent
|
|
|
1188
1275
|
end
|
|
1189
1276
|
|
|
1190
1277
|
if @buffer.takeback_chunk(chunk.unique_id)
|
|
1191
|
-
@
|
|
1278
|
+
@rollback_count_metrics.inc
|
|
1192
1279
|
end
|
|
1193
1280
|
|
|
1194
1281
|
update_retry_state(chunk.unique_id, using_secondary, e)
|
|
@@ -1198,18 +1285,10 @@ module Fluent
|
|
|
1198
1285
|
end
|
|
1199
1286
|
|
|
1200
1287
|
def backup_chunk(chunk, using_secondary, delayed_commit)
|
|
1201
|
-
if @
|
|
1288
|
+
if @buffer.disable_chunk_backup
|
|
1202
1289
|
log.warn "disable_chunk_backup is true. #{dump_unique_id_hex(chunk.unique_id)} chunk is thrown away"
|
|
1203
1290
|
else
|
|
1204
|
-
|
|
1205
|
-
safe_plugin_id = plugin_id.gsub(/[ "\/\\:;|*<>?]/, '_')
|
|
1206
|
-
backup_base_dir = system_config.root_dir || DEFAULT_BACKUP_DIR
|
|
1207
|
-
backup_file = File.join(backup_base_dir, 'backup', "worker#{fluentd_worker_id}", safe_plugin_id, "#{unique_id}.log")
|
|
1208
|
-
backup_dir = File.dirname(backup_file)
|
|
1209
|
-
|
|
1210
|
-
log.warn "bad chunk is moved to #{backup_file}"
|
|
1211
|
-
FileUtils.mkdir_p(backup_dir, mode: system_config.dir_permission || 0755) unless Dir.exist?(backup_dir)
|
|
1212
|
-
File.open(backup_file, 'ab', system_config.file_permission || 0644) { |f|
|
|
1291
|
+
@buffer.backup(chunk.unique_id) { |f|
|
|
1213
1292
|
chunk.write_to(f)
|
|
1214
1293
|
}
|
|
1215
1294
|
end
|
|
@@ -1219,9 +1298,9 @@ module Fluent
|
|
|
1219
1298
|
def check_slow_flush(start)
|
|
1220
1299
|
elapsed_time = Fluent::Clock.now - start
|
|
1221
1300
|
elapsed_millsec = (elapsed_time * 1000).to_i
|
|
1222
|
-
@
|
|
1301
|
+
@flush_time_count_metrics.add(elapsed_millsec)
|
|
1223
1302
|
if elapsed_time > @slow_flush_log_threshold
|
|
1224
|
-
@
|
|
1303
|
+
@slow_flush_count_metrics.inc
|
|
1225
1304
|
log.warn "buffer flush took longer time than slow_flush_log_threshold:",
|
|
1226
1305
|
elapsed_time: elapsed_time, slow_flush_log_threshold: @slow_flush_log_threshold, plugin_id: self.plugin_id
|
|
1227
1306
|
end
|
|
@@ -1229,53 +1308,62 @@ module Fluent
|
|
|
1229
1308
|
|
|
1230
1309
|
def update_retry_state(chunk_id, using_secondary, error = nil)
|
|
1231
1310
|
@retry_mutex.synchronize do
|
|
1232
|
-
@
|
|
1311
|
+
@num_errors_metrics.inc
|
|
1233
1312
|
chunk_id_hex = dump_unique_id_hex(chunk_id)
|
|
1234
1313
|
|
|
1235
1314
|
unless @retry
|
|
1236
1315
|
@retry = retry_state(@buffer_config.retry_randomize)
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1316
|
+
|
|
1317
|
+
if @retry.limit?
|
|
1318
|
+
handle_limit_reached(error)
|
|
1319
|
+
elsif error
|
|
1320
|
+
log_retry_error(error, chunk_id_hex, using_secondary)
|
|
1240
1321
|
end
|
|
1322
|
+
|
|
1241
1323
|
return
|
|
1242
1324
|
end
|
|
1243
1325
|
|
|
1244
1326
|
# @retry exists
|
|
1245
1327
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
log.error msg, retry_times: @retry.steps, records: records, error: error
|
|
1251
|
-
log.error_backtrace error.backtrace
|
|
1252
|
-
end
|
|
1253
|
-
@buffer.clear_queue!
|
|
1254
|
-
log.debug "buffer queue cleared"
|
|
1255
|
-
@retry = nil
|
|
1328
|
+
# Ensure that the current time is greater than or equal to @retry.next_time to avoid the situation when
|
|
1329
|
+
# @retry.step is called almost as many times as the number of flush threads in a short time.
|
|
1330
|
+
if Time.now >= @retry.next_time
|
|
1331
|
+
@retry.step
|
|
1256
1332
|
else
|
|
1257
|
-
#
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
if error
|
|
1265
|
-
if using_secondary
|
|
1266
|
-
msg = "failed to flush the buffer with secondary output."
|
|
1267
|
-
log.warn msg, retry_time: @retry.steps, next_retry_seconds: @retry.next_time, chunk: chunk_id_hex, error: error
|
|
1268
|
-
log.warn_backtrace error.backtrace
|
|
1269
|
-
else
|
|
1270
|
-
msg = "failed to flush the buffer."
|
|
1271
|
-
log.warn msg, retry_time: @retry.steps, next_retry_seconds: @retry.next_time, chunk: chunk_id_hex, error: error
|
|
1272
|
-
log.warn_backtrace error.backtrace
|
|
1273
|
-
end
|
|
1274
|
-
end
|
|
1333
|
+
@retry.recalc_next_time # to prevent all flush threads from retrying at the same time
|
|
1334
|
+
end
|
|
1335
|
+
|
|
1336
|
+
if @retry.limit?
|
|
1337
|
+
handle_limit_reached(error)
|
|
1338
|
+
elsif error
|
|
1339
|
+
log_retry_error(error, chunk_id_hex, using_secondary)
|
|
1275
1340
|
end
|
|
1276
1341
|
end
|
|
1277
1342
|
end
|
|
1278
1343
|
|
|
1344
|
+
def log_retry_error(error, chunk_id_hex, using_secondary)
|
|
1345
|
+
return unless error
|
|
1346
|
+
if using_secondary
|
|
1347
|
+
msg = "failed to flush the buffer with secondary output."
|
|
1348
|
+
else
|
|
1349
|
+
msg = "failed to flush the buffer."
|
|
1350
|
+
end
|
|
1351
|
+
log.warn(msg, retry_times: @retry.steps, next_retry_time: @retry.next_time.round, chunk: chunk_id_hex, error: error)
|
|
1352
|
+
log.warn_backtrace(error.backtrace)
|
|
1353
|
+
end
|
|
1354
|
+
|
|
1355
|
+
def handle_limit_reached(error)
|
|
1356
|
+
if error
|
|
1357
|
+
records = @buffer.queued_records
|
|
1358
|
+
msg = "Hit limit for retries. dropping all chunks in the buffer queue."
|
|
1359
|
+
log.error msg, retry_times: @retry.steps, records: records, error: error
|
|
1360
|
+
log.error_backtrace error.backtrace
|
|
1361
|
+
end
|
|
1362
|
+
@buffer.clear_queue!
|
|
1363
|
+
log.debug "buffer queue cleared"
|
|
1364
|
+
@retry = nil
|
|
1365
|
+
end
|
|
1366
|
+
|
|
1279
1367
|
def retry_state(randomize)
|
|
1280
1368
|
if @secondary
|
|
1281
1369
|
retry_state_create(
|
|
@@ -1490,15 +1578,16 @@ module Fluent
|
|
|
1490
1578
|
|
|
1491
1579
|
def statistics
|
|
1492
1580
|
stats = {
|
|
1493
|
-
'emit_records' => @
|
|
1581
|
+
'emit_records' => @emit_records_metrics.get,
|
|
1582
|
+
'emit_size' => @emit_size_metrics.get,
|
|
1494
1583
|
# Respect original name
|
|
1495
1584
|
# https://github.com/fluent/fluentd/blob/45c7b75ba77763eaf87136864d4942c4e0c5bfcd/lib/fluent/plugin/in_monitor_agent.rb#L284
|
|
1496
|
-
'retry_count' => @
|
|
1497
|
-
'emit_count' => @
|
|
1498
|
-
'write_count' => @
|
|
1499
|
-
'rollback_count' => @
|
|
1500
|
-
'slow_flush_count' => @
|
|
1501
|
-
'flush_time_count' => @
|
|
1585
|
+
'retry_count' => @num_errors_metrics.get,
|
|
1586
|
+
'emit_count' => @emit_count_metrics.get,
|
|
1587
|
+
'write_count' => @write_count_metrics.get,
|
|
1588
|
+
'rollback_count' => @rollback_count_metrics.get,
|
|
1589
|
+
'slow_flush_count' => @slow_flush_count_metrics.get,
|
|
1590
|
+
'flush_time_count' => @flush_time_count_metrics.get,
|
|
1502
1591
|
}
|
|
1503
1592
|
|
|
1504
1593
|
if @buffer && @buffer.respond_to?(:statistics)
|
data/lib/fluent/plugin/parser.rb
CHANGED
|
@@ -89,7 +89,7 @@ module Fluent
|
|
|
89
89
|
# : format[, timezone]
|
|
90
90
|
|
|
91
91
|
config_param :time_key, :string, default: nil
|
|
92
|
-
config_param :null_value_pattern, :
|
|
92
|
+
config_param :null_value_pattern, :regexp, default: nil
|
|
93
93
|
config_param :null_empty_string, :bool, default: false
|
|
94
94
|
config_param :estimate_current_event, :bool, default: true
|
|
95
95
|
config_param :keep_time_key, :bool, default: false
|
|
@@ -115,9 +115,8 @@ module Fluent
|
|
|
115
115
|
super
|
|
116
116
|
|
|
117
117
|
@time_parser = time_parser_create
|
|
118
|
-
@null_value_regexp = @null_value_pattern && Regexp.new(@null_value_pattern)
|
|
119
118
|
@type_converters = build_type_converters(@types)
|
|
120
|
-
@execute_convert_values = @type_converters || @
|
|
119
|
+
@execute_convert_values = @type_converters || @null_value_pattern || @null_empty_string
|
|
121
120
|
@timeout_checker = if @timeout
|
|
122
121
|
class << self
|
|
123
122
|
alias_method :parse_orig, :parse
|
|
@@ -220,7 +219,7 @@ module Fluent
|
|
|
220
219
|
return time, record
|
|
221
220
|
end
|
|
222
221
|
|
|
223
|
-
def string_like_null(value, null_empty_string = @null_empty_string, null_value_regexp = @
|
|
222
|
+
def string_like_null(value, null_empty_string = @null_empty_string, null_value_regexp = @null_value_pattern)
|
|
224
223
|
null_empty_string && value.empty? || null_value_regexp && string_safe_encoding(value){|s| null_value_regexp.match(s) }
|
|
225
224
|
end
|
|
226
225
|
|
|
@@ -21,7 +21,7 @@ module Fluent
|
|
|
21
21
|
class Apache2Parser < Parser
|
|
22
22
|
Plugin.register_parser('apache2', self)
|
|
23
23
|
|
|
24
|
-
REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>(?:[^\"]
|
|
24
|
+
REGEXP = /^(?<host>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>(?:[^\"]|\\")*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>(?:[^\"]|\\")*)" "(?<agent>(?:[^\"]|\\")*)")?$/
|
|
25
25
|
TIME_FORMAT = "%d/%b/%Y:%H:%M:%S %z"
|
|
26
26
|
|
|
27
27
|
def initialize
|
|
@@ -484,7 +484,7 @@ module Fluent
|
|
|
484
484
|
|
|
485
485
|
time = begin
|
|
486
486
|
@time_parser_rfc5424.parse(time_str)
|
|
487
|
-
rescue Fluent::TimeParser::TimeParseError
|
|
487
|
+
rescue Fluent::TimeParser::TimeParseError
|
|
488
488
|
@time_parser_rfc5424_without_subseconds.parse(time_str)
|
|
489
489
|
end
|
|
490
490
|
record['time'] = time_str if @keep_time_key
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
|
|
17
|
+
require 'fluent/env'
|
|
17
18
|
require 'fluent/plugin'
|
|
18
19
|
require 'fluent/plugin/storage'
|
|
19
20
|
|
|
@@ -25,14 +26,11 @@ module Fluent
|
|
|
25
26
|
class LocalStorage < Storage
|
|
26
27
|
Fluent::Plugin.register_storage('local', self)
|
|
27
28
|
|
|
28
|
-
DEFAULT_DIR_MODE = 0755
|
|
29
|
-
DEFAULT_FILE_MODE = 0644
|
|
30
|
-
|
|
31
29
|
config_param :path, :string, default: nil
|
|
32
|
-
config_param :mode, default:
|
|
30
|
+
config_param :mode, default: Fluent::DEFAULT_FILE_PERMISSION do |v|
|
|
33
31
|
v.to_i(8)
|
|
34
32
|
end
|
|
35
|
-
config_param :dir_mode, default:
|
|
33
|
+
config_param :dir_mode, default: Fluent::DEFAULT_DIR_PERMISSION do |v|
|
|
36
34
|
v.to_i(8)
|
|
37
35
|
end
|
|
38
36
|
config_param :pretty_print, :bool, default: false
|