fluentd 1.13.3 → 1.16.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|