fluentd 1.13.0-x86-mingw32 → 1.14.0-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of fluentd might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.yaml +69 -0
- data/.github/ISSUE_TEMPLATE/feature_request.yaml +38 -0
- data/.github/workflows/linux-test.yaml +1 -1
- data/.github/workflows/windows-test.yaml +4 -4
- data/.gitlab-ci.yml +0 -22
- data/CHANGELOG.md +131 -0
- data/README.md +2 -2
- data/example/v0_12_filter.conf +2 -2
- data/fluentd.gemspec +1 -1
- data/lib/fluent/command/fluentd.rb +8 -0
- data/lib/fluent/command/plugin_generator.rb +15 -5
- data/lib/fluent/compat/output.rb +9 -6
- data/lib/fluent/config/section.rb +5 -0
- data/lib/fluent/config/types.rb +15 -0
- data/lib/fluent/config/v1_parser.rb +3 -2
- data/lib/fluent/config.rb +1 -1
- data/lib/fluent/env.rb +2 -1
- data/lib/fluent/event_router.rb +28 -1
- data/lib/fluent/oj_options.rb +62 -0
- data/lib/fluent/plugin/bare_output.rb +49 -8
- data/lib/fluent/plugin/buffer.rb +84 -22
- data/lib/fluent/plugin/file_wrapper.rb +22 -0
- data/lib/fluent/plugin/filter.rb +35 -1
- data/lib/fluent/plugin/formatter.rb +1 -0
- data/lib/fluent/plugin/formatter_json.rb +9 -7
- data/lib/fluent/plugin/in_http.rb +21 -2
- data/lib/fluent/plugin/in_monitor_agent.rb +4 -2
- data/lib/fluent/plugin/in_syslog.rb +13 -1
- data/lib/fluent/plugin/in_tail/position_file.rb +20 -18
- data/lib/fluent/plugin/in_tail.rb +45 -4
- 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_forward.rb +1 -3
- data/lib/fluent/plugin/output.rb +74 -33
- data/lib/fluent/plugin/parser_json.rb +2 -3
- data/lib/fluent/plugin/service_discovery.rb +0 -15
- data/lib/fluent/plugin.rb +10 -1
- data/lib/fluent/plugin_helper/event_emitter.rb +8 -1
- data/lib/fluent/plugin_helper/http_server/router.rb +1 -1
- data/lib/fluent/plugin_helper/metrics.rb +129 -0
- data/lib/fluent/plugin_helper/server.rb +4 -2
- data/lib/fluent/plugin_helper.rb +1 -0
- data/lib/fluent/root_agent.rb +6 -0
- data/lib/fluent/supervisor.rb +2 -0
- data/lib/fluent/system_config.rb +9 -1
- data/lib/fluent/test/driver/storage.rb +30 -0
- data/lib/fluent/version.rb +1 -1
- data/templates/new_gem/lib/fluent/plugin/storage.rb.erb +40 -0
- data/templates/new_gem/test/plugin/test_storage.rb.erb +18 -0
- data/test/command/test_cat.rb +11 -8
- data/test/command/test_plugin_generator.rb +2 -1
- data/test/config/test_section.rb +9 -0
- data/test/config/test_system_config.rb +6 -0
- data/test/config/test_types.rb +7 -0
- data/test/plugin/in_tail/test_position_file.rb +48 -8
- data/test/plugin/test_bare_output.rb +13 -0
- data/test/plugin/test_buffer.rb +8 -2
- data/test/plugin/test_file_wrapper.rb +11 -0
- data/test/plugin/test_filter.rb +11 -0
- data/test/plugin/test_in_forward.rb +59 -83
- data/test/plugin/test_in_http.rb +86 -43
- data/test/plugin/test_in_monitor_agent.rb +214 -8
- data/test/plugin/test_in_syslog.rb +101 -56
- data/test/plugin/test_in_tail.rb +149 -48
- data/test/plugin/test_in_tcp.rb +45 -32
- data/test/plugin/test_in_udp.rb +47 -33
- data/test/plugin/test_input.rb +11 -0
- 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_forward.rb +103 -89
- data/test/plugin/test_out_stream.rb +18 -8
- data/test/plugin/test_output.rb +16 -0
- data/test/plugin_helper/http_server/test_route.rb +1 -1
- data/test/plugin_helper/test_child_process.rb +1 -1
- data/test/plugin_helper/test_event_emitter.rb +29 -0
- data/test/plugin_helper/test_http_server_helper.rb +33 -26
- data/test/plugin_helper/test_metrics.rb +137 -0
- data/test/plugin_helper/test_server.rb +137 -138
- data/test/plugin_helper/test_socket.rb +16 -9
- data/test/test_event_time.rb +2 -2
- data/test/test_oj_options.rb +55 -0
- data/test/test_plugin_classes.rb +102 -0
- data/test/test_root_agent.rb +30 -1
- metadata +22 -7
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -23
@@ -155,7 +155,29 @@ module Fluent
|
|
155
155
|
by_handle_file_information.unpack("I11Q1")[11] # fileindex
|
156
156
|
end
|
157
157
|
|
158
|
+
# DeletePending is a Windows-specific file state that roughly means
|
159
|
+
# "this file is queued for deletion, so close any open handlers"
|
160
|
+
#
|
161
|
+
# This flag can be retrieved via GetFileInformationByHandleEx().
|
162
|
+
#
|
163
|
+
# https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfileinformationbyhandleex
|
164
|
+
#
|
165
|
+
def delete_pending
|
166
|
+
file_standard_info = 0x01
|
167
|
+
bufsize = 1024
|
168
|
+
buf = '\0' * bufsize
|
169
|
+
|
170
|
+
unless GetFileInformationByHandleEx.call(@file_handle, file_standard_info, buf, bufsize)
|
171
|
+
return false
|
172
|
+
end
|
173
|
+
|
174
|
+
return buf.unpack("QQICC")[3] != 0
|
175
|
+
end
|
176
|
+
|
177
|
+
private :delete_pending
|
178
|
+
|
158
179
|
def stat
|
180
|
+
raise Errno::ENOENT if delete_pending
|
159
181
|
s = File.stat(@path)
|
160
182
|
s.instance_variable_set :@ino, self.ino
|
161
183
|
def s.ino; @ino; end
|
data/lib/fluent/plugin/filter.rb
CHANGED
@@ -28,13 +28,47 @@ module Fluent
|
|
28
28
|
include PluginLoggerMixin
|
29
29
|
include PluginHelper::Mixin
|
30
30
|
|
31
|
-
helpers_internal :event_emitter
|
31
|
+
helpers_internal :event_emitter, :metrics
|
32
32
|
|
33
33
|
attr_reader :has_filter_with_time
|
34
34
|
|
35
35
|
def initialize
|
36
36
|
super
|
37
37
|
@has_filter_with_time = has_filter_with_time?
|
38
|
+
@emit_records_metrics = nil
|
39
|
+
@emit_size_metrics = nil
|
40
|
+
@counter_mutex = Mutex.new
|
41
|
+
@enable_size_metrics = false
|
42
|
+
end
|
43
|
+
|
44
|
+
def emit_records
|
45
|
+
@emit_records_metrics.get
|
46
|
+
end
|
47
|
+
|
48
|
+
def emit_size
|
49
|
+
@emit_size_metrics.get
|
50
|
+
end
|
51
|
+
|
52
|
+
def configure(conf)
|
53
|
+
super
|
54
|
+
|
55
|
+
@emit_records_metrics = metrics_create(namespace: "fluentd", subsystem: "filter", name: "emit_records", help_text: "Number of count emit records")
|
56
|
+
@emit_size_metrics = metrics_create(namespace: "fluentd", subsystem: "filter", name: "emit_size", help_text: "Total size of emit events")
|
57
|
+
@enable_size_metrics = !!system_config.enable_size_metrics
|
58
|
+
end
|
59
|
+
|
60
|
+
def statistics
|
61
|
+
stats = {
|
62
|
+
'emit_records' => @emit_records_metrics.get,
|
63
|
+
'emit_size' => @emit_size_metrics.get,
|
64
|
+
}
|
65
|
+
|
66
|
+
{ 'filter' => stats }
|
67
|
+
end
|
68
|
+
|
69
|
+
def measure_metrics(es)
|
70
|
+
@emit_records_metrics.add(es.size)
|
71
|
+
@emit_size_metrics.add(es.to_msgpack_stream.bytesize) if @enable_size_metrics
|
38
72
|
end
|
39
73
|
|
40
74
|
def filter(tag, time, record)
|
@@ -15,7 +15,7 @@
|
|
15
15
|
#
|
16
16
|
|
17
17
|
require 'fluent/plugin/formatter'
|
18
|
-
require 'fluent/
|
18
|
+
require 'fluent/oj_options'
|
19
19
|
|
20
20
|
module Fluent
|
21
21
|
module Plugin
|
@@ -30,12 +30,14 @@ module Fluent
|
|
30
30
|
def configure(conf)
|
31
31
|
super
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
if @json_parser == 'oj'
|
34
|
+
if Fluent::OjOptions.available?
|
35
|
+
@dump_proc = Oj.method(:dump)
|
36
|
+
else
|
37
|
+
log.info "Oj isn't installed, fallback to Yajl as json parser"
|
38
|
+
@dump_proc = Yajl.method(:dump)
|
39
|
+
end
|
40
|
+
else
|
39
41
|
@dump_proc = Yajl.method(:dump)
|
40
42
|
end
|
41
43
|
|
@@ -74,6 +74,8 @@ module Fluent::Plugin
|
|
74
74
|
config_param :blocking_timeout, :time, default: 0.5
|
75
75
|
desc 'Set a allow list of domains that can do CORS (Cross-Origin Resource Sharing)'
|
76
76
|
config_param :cors_allow_origins, :array, default: nil
|
77
|
+
desc 'Tells browsers whether to expose the response to frontend when the credentials mode is "include".'
|
78
|
+
config_param :cors_allow_credentials, :bool, default: false
|
77
79
|
desc 'Respond with empty gif image of 1x1 pixel.'
|
78
80
|
config_param :respond_with_empty_img, :bool, default: false
|
79
81
|
desc 'Respond status code with 204.'
|
@@ -112,6 +114,12 @@ module Fluent::Plugin
|
|
112
114
|
|
113
115
|
super
|
114
116
|
|
117
|
+
if @cors_allow_credentials
|
118
|
+
if @cors_allow_origins.nil? || @cors_allow_origins.include?('*')
|
119
|
+
raise Fluent::ConfigError, "Cannot enable cors_allow_credentials without specific origins"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
115
123
|
m = if @parser_configs.first['@type'] == 'in_http'
|
116
124
|
@parser_msgpack = parser_create(usage: 'parser_in_http_msgpack', type: 'msgpack')
|
117
125
|
@parser_msgpack.time_key = nil
|
@@ -279,7 +287,10 @@ module Fluent::Plugin
|
|
279
287
|
private
|
280
288
|
|
281
289
|
def on_server_connect(conn)
|
282
|
-
handler = Handler.new(conn, @km, method(:on_request),
|
290
|
+
handler = Handler.new(conn, @km, method(:on_request),
|
291
|
+
@body_size_limit, @format_name, log,
|
292
|
+
@cors_allow_origins, @cors_allow_credentials,
|
293
|
+
@add_query_params)
|
283
294
|
|
284
295
|
conn.on(:data) do |data|
|
285
296
|
handler.on_read(data)
|
@@ -356,7 +367,8 @@ module Fluent::Plugin
|
|
356
367
|
class Handler
|
357
368
|
attr_reader :content_type
|
358
369
|
|
359
|
-
def initialize(io, km, callback, body_size_limit, format_name, log,
|
370
|
+
def initialize(io, km, callback, body_size_limit, format_name, log,
|
371
|
+
cors_allow_origins, cors_allow_credentials, add_query_params)
|
360
372
|
@io = io
|
361
373
|
@km = km
|
362
374
|
@callback = callback
|
@@ -365,6 +377,7 @@ module Fluent::Plugin
|
|
365
377
|
@format_name = format_name
|
366
378
|
@log = log
|
367
379
|
@cors_allow_origins = cors_allow_origins
|
380
|
+
@cors_allow_credentials = cors_allow_credentials
|
368
381
|
@idle = 0
|
369
382
|
@add_query_params = add_query_params
|
370
383
|
@km.add(self)
|
@@ -491,6 +504,9 @@ module Fluent::Plugin
|
|
491
504
|
send_response_and_close(RES_200_STATUS, header, "")
|
492
505
|
elsif include_cors_allow_origin
|
493
506
|
header["Access-Control-Allow-Origin"] = @origin
|
507
|
+
if @cors_allow_credentials
|
508
|
+
header["Access-Control-Allow-Credentials"] = true
|
509
|
+
end
|
494
510
|
send_response_and_close(RES_200_STATUS, header, "")
|
495
511
|
else
|
496
512
|
send_response_and_close(RES_403_STATUS, {}, "")
|
@@ -576,6 +592,9 @@ module Fluent::Plugin
|
|
576
592
|
header['Access-Control-Allow-Origin'] = '*'
|
577
593
|
elsif include_cors_allow_origin
|
578
594
|
header['Access-Control-Allow-Origin'] = @origin
|
595
|
+
if @cors_allow_credentials
|
596
|
+
header["Access-Control-Allow-Credentials"] = true
|
597
|
+
end
|
579
598
|
end
|
580
599
|
end
|
581
600
|
|
@@ -238,7 +238,7 @@ module Fluent::Plugin
|
|
238
238
|
'buffer_queue_length' => ->(){ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer); @buffer.queue.size },
|
239
239
|
'buffer_timekeys' => ->(){ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer); @buffer.timekeys },
|
240
240
|
'buffer_total_queued_size' => ->(){ throw(:skip) unless instance_variable_defined?(:@buffer) && !@buffer.nil? && @buffer.is_a?(::Fluent::Plugin::Buffer); @buffer.stage_size + @buffer.queue_size },
|
241
|
-
'retry_count' => ->(){
|
241
|
+
'retry_count' => ->(){ respond_to?(:num_errors) ? num_errors : nil },
|
242
242
|
}
|
243
243
|
|
244
244
|
def all_plugins
|
@@ -335,7 +335,9 @@ module Fluent::Plugin
|
|
335
335
|
}
|
336
336
|
|
337
337
|
if pe.respond_to?(:statistics)
|
338
|
-
obj.merge!(pe.statistics
|
338
|
+
obj.merge!(pe.statistics.dig('output') || {})
|
339
|
+
obj.merge!(pe.statistics.dig('filter') || {})
|
340
|
+
obj.merge!(pe.statistics.dig('input') || {})
|
339
341
|
end
|
340
342
|
|
341
343
|
obj['retry'] = get_retry_info(pe.retry) if opts[:with_retry] && pe.instance_variable_defined?(:@retry)
|
@@ -89,6 +89,8 @@ module Fluent::Plugin
|
|
89
89
|
config_param :source_hostname_key, :string, default: nil
|
90
90
|
desc 'Try to resolve hostname from IP addresses or not.'
|
91
91
|
config_param :resolve_hostname, :bool, default: nil
|
92
|
+
desc 'Check the remote connection is still available by sending a keepalive packet if this value is true.'
|
93
|
+
config_param :send_keepalive_packet, :bool, default: false
|
92
94
|
desc 'The field name of source address of sender.'
|
93
95
|
config_param :source_address_key, :string, default: nil
|
94
96
|
desc 'The field name of the severity.'
|
@@ -143,6 +145,11 @@ module Fluent::Plugin
|
|
143
145
|
end
|
144
146
|
|
145
147
|
@_event_loop_run_timeout = @blocking_timeout
|
148
|
+
|
149
|
+
protocol = @protocol_type || @transport_config.protocol
|
150
|
+
if @send_keepalive_packet && protocol == :udp
|
151
|
+
raise Fluent::ConfigError, "send_keepalive_packet is available for tcp/tls"
|
152
|
+
end
|
146
153
|
end
|
147
154
|
|
148
155
|
def multi_workers_ready?
|
@@ -173,7 +180,12 @@ module Fluent::Plugin
|
|
173
180
|
|
174
181
|
delimiter = octet_count_frame ? " " : @delimiter
|
175
182
|
delimiter_size = delimiter.size
|
176
|
-
server_create_connection(
|
183
|
+
server_create_connection(
|
184
|
+
tls ? :in_syslog_tls_server : :in_syslog_tcp_server, @port,
|
185
|
+
bind: @bind,
|
186
|
+
resolve_name: @resolve_hostname,
|
187
|
+
send_keepalive_packet: @send_keepalive_packet
|
188
|
+
) do |conn|
|
177
189
|
conn.data do |data|
|
178
190
|
buffer = conn.buffer
|
179
191
|
buffer << data
|
@@ -22,19 +22,18 @@ module Fluent::Plugin
|
|
22
22
|
UNWATCHED_POSITION = 0xffffffffffffffff
|
23
23
|
POSITION_FILE_ENTRY_REGEX = /^([^\t]+)\t([0-9a-fA-F]+)\t([0-9a-fA-F]+)/.freeze
|
24
24
|
|
25
|
-
def self.load(file, follow_inodes,
|
26
|
-
pf = new(file, follow_inodes,
|
27
|
-
pf.load
|
25
|
+
def self.load(file, follow_inodes, existing_targets, logger:)
|
26
|
+
pf = new(file, follow_inodes, logger: logger)
|
27
|
+
pf.load(existing_targets)
|
28
28
|
pf
|
29
29
|
end
|
30
30
|
|
31
|
-
def initialize(file, follow_inodes,
|
31
|
+
def initialize(file, follow_inodes, logger: nil)
|
32
32
|
@file = file
|
33
33
|
@logger = logger
|
34
34
|
@file_mutex = Mutex.new
|
35
35
|
@map = {}
|
36
36
|
@follow_inodes = follow_inodes
|
37
|
-
@existing_paths = existing_paths
|
38
37
|
end
|
39
38
|
|
40
39
|
def [](target_info)
|
@@ -60,8 +59,8 @@ module Fluent::Plugin
|
|
60
59
|
end
|
61
60
|
end
|
62
61
|
|
63
|
-
def load
|
64
|
-
compact
|
62
|
+
def load(existing_targets = nil)
|
63
|
+
compact(existing_targets)
|
65
64
|
|
66
65
|
map = {}
|
67
66
|
@file_mutex.synchronize do
|
@@ -118,9 +117,9 @@ module Fluent::Plugin
|
|
118
117
|
|
119
118
|
private
|
120
119
|
|
121
|
-
def compact
|
120
|
+
def compact(existing_targets = nil)
|
122
121
|
@file_mutex.synchronize do
|
123
|
-
entries = fetch_compacted_entries.values.map(&:to_entry_fmt)
|
122
|
+
entries = fetch_compacted_entries(existing_targets).values.map(&:to_entry_fmt)
|
124
123
|
|
125
124
|
@file.pos = 0
|
126
125
|
@file.truncate(0)
|
@@ -128,7 +127,7 @@ module Fluent::Plugin
|
|
128
127
|
end
|
129
128
|
end
|
130
129
|
|
131
|
-
def fetch_compacted_entries
|
130
|
+
def fetch_compacted_entries(existing_targets = nil)
|
132
131
|
entries = {}
|
133
132
|
|
134
133
|
@file.pos = 0
|
@@ -151,23 +150,26 @@ module Fluent::Plugin
|
|
151
150
|
end
|
152
151
|
|
153
152
|
if @follow_inodes
|
154
|
-
entries[ino] = Entry.new(path, pos, ino, file_pos + path.
|
153
|
+
entries[ino] = Entry.new(path, pos, ino, file_pos + path.bytesize + 1)
|
155
154
|
else
|
156
|
-
entries[path] = Entry.new(path, pos, ino, file_pos + path.
|
155
|
+
entries[path] = Entry.new(path, pos, ino, file_pos + path.bytesize + 1)
|
157
156
|
end
|
158
157
|
file_pos += line.size
|
159
158
|
end
|
160
159
|
end
|
161
160
|
|
162
|
-
entries = remove_deleted_files_entries(entries,
|
161
|
+
entries = remove_deleted_files_entries(entries, existing_targets)
|
163
162
|
entries
|
164
163
|
end
|
165
164
|
|
166
|
-
def remove_deleted_files_entries(existent_entries,
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
165
|
+
def remove_deleted_files_entries(existent_entries, existing_targets)
|
166
|
+
if existing_targets
|
167
|
+
existent_entries.select { |path_or_ino|
|
168
|
+
existing_targets.key?(path_or_ino)
|
169
|
+
}
|
170
|
+
else
|
171
|
+
existent_entries
|
172
|
+
end
|
171
173
|
end
|
172
174
|
end
|
173
175
|
|
@@ -426,6 +426,7 @@ module Fluent::Plugin
|
|
426
426
|
|
427
427
|
begin
|
428
428
|
target_info = TargetInfo.new(target_info.path, Fluent::FileWrapper.stat(target_info.path).ino)
|
429
|
+
@tails.delete(target_info)
|
429
430
|
@tails[target_info] = tw
|
430
431
|
tw.on_notify
|
431
432
|
rescue Errno::ENOENT, Errno::EACCES => e
|
@@ -491,10 +492,17 @@ module Fluent::Plugin
|
|
491
492
|
new_position_entry = @pf[target_info]
|
492
493
|
|
493
494
|
if new_position_entry.read_inode == 0
|
495
|
+
# When follow_inodes is true, it's not cleaned up by refresh_watcher.
|
496
|
+
# So it should be unwatched here explicitly.
|
497
|
+
rotated_tw.unwatched = true
|
498
|
+
# Make sure to delete old key, it has a different ino while the hash key is same.
|
499
|
+
@tails.delete(rotated_target_info)
|
494
500
|
@tails[new_target_info] = setup_watcher(new_target_info, new_position_entry)
|
495
501
|
@tails[new_target_info].on_notify
|
496
502
|
end
|
497
503
|
else
|
504
|
+
# Make sure to delete old key, it has a different ino while the hash key is same.
|
505
|
+
@tails.delete(rotated_target_info)
|
498
506
|
@tails[new_target_info] = setup_watcher(new_target_info, pe)
|
499
507
|
@tails[new_target_info].on_notify
|
500
508
|
end
|
@@ -522,8 +530,25 @@ module Fluent::Plugin
|
|
522
530
|
def detach_watcher_after_rotate_wait(tw, ino)
|
523
531
|
# Call event_loop_attach/event_loop_detach is high-cost for short-live object.
|
524
532
|
# If this has a problem with large number of files, use @_event_loop directly instead of timer_execute.
|
525
|
-
|
533
|
+
if @open_on_every_update
|
534
|
+
# Detach now because it's already closed, waiting it doesn't make sense.
|
526
535
|
detach_watcher(tw, ino)
|
536
|
+
elsif @read_bytes_limit_per_second < 0
|
537
|
+
# throttling isn't enabled, just wait @rotate_wait
|
538
|
+
timer_execute(:in_tail_close_watcher, @rotate_wait, repeat: false) do
|
539
|
+
detach_watcher(tw, ino)
|
540
|
+
end
|
541
|
+
else
|
542
|
+
# When the throttling feature is enabled, it might not reach EOF yet.
|
543
|
+
# Should ensure to read all contents before closing it, with keeping throttling.
|
544
|
+
start_time_to_wait = Fluent::Clock.now
|
545
|
+
timer = timer_execute(:in_tail_close_watcher, 1, repeat: true) do
|
546
|
+
elapsed = Fluent::Clock.now - start_time_to_wait
|
547
|
+
if tw.eof? && elapsed >= @rotate_wait
|
548
|
+
timer.detach
|
549
|
+
detach_watcher(tw, ino)
|
550
|
+
end
|
551
|
+
end
|
527
552
|
end
|
528
553
|
end
|
529
554
|
|
@@ -736,6 +761,10 @@ module Fluent::Plugin
|
|
736
761
|
end
|
737
762
|
end
|
738
763
|
|
764
|
+
def eof?
|
765
|
+
@io_handler.eof?
|
766
|
+
end
|
767
|
+
|
739
768
|
def on_notify
|
740
769
|
begin
|
741
770
|
stat = Fluent::FileWrapper.stat(@path)
|
@@ -810,7 +839,7 @@ module Fluent::Plugin
|
|
810
839
|
# new watcher, and old watcher will be closed by stop_watcher in refresh_watchers method
|
811
840
|
# don't want to swap state because we need latest read offset in pos file even after rotate_wait
|
812
841
|
if stat
|
813
|
-
target_info = TargetInfo.new(@path, stat)
|
842
|
+
target_info = TargetInfo.new(@path, stat.ino)
|
814
843
|
@update_watcher.call(target_info, @pe)
|
815
844
|
end
|
816
845
|
else
|
@@ -923,6 +952,7 @@ module Fluent::Plugin
|
|
923
952
|
@shutdown_start_time = nil
|
924
953
|
@shutdown_timeout = SHUTDOWN_TIMEOUT
|
925
954
|
@shutdown_mutex = Mutex.new
|
955
|
+
@eof = false
|
926
956
|
|
927
957
|
@log.info "following tail of #{@path}"
|
928
958
|
end
|
@@ -949,6 +979,10 @@ module Fluent::Plugin
|
|
949
979
|
!!@io
|
950
980
|
end
|
951
981
|
|
982
|
+
def eof?
|
983
|
+
@eof
|
984
|
+
end
|
985
|
+
|
952
986
|
private
|
953
987
|
|
954
988
|
def limit_bytes_per_second_reached?
|
@@ -989,11 +1023,11 @@ module Fluent::Plugin
|
|
989
1023
|
while true
|
990
1024
|
@start_reading_time ||= Fluent::Clock.now
|
991
1025
|
data = io.readpartial(BYTES_TO_READ, @iobuf)
|
1026
|
+
@eof = false
|
992
1027
|
@number_bytes_read += data.bytesize
|
993
1028
|
@fifo << data
|
994
1029
|
@fifo.read_lines(@lines)
|
995
1030
|
|
996
|
-
@log.debug("reading file: #{@path}")
|
997
1031
|
if limit_bytes_per_second_reached? || should_shutdown_now?
|
998
1032
|
# Just get out from tailing loop.
|
999
1033
|
read_more = false
|
@@ -1006,6 +1040,7 @@ module Fluent::Plugin
|
|
1006
1040
|
end
|
1007
1041
|
end
|
1008
1042
|
rescue EOFError
|
1043
|
+
@eof = true
|
1009
1044
|
end
|
1010
1045
|
end
|
1011
1046
|
|
@@ -1028,7 +1063,10 @@ module Fluent::Plugin
|
|
1028
1063
|
rescue RangeError
|
1029
1064
|
io.close if io
|
1030
1065
|
raise WatcherSetupError, "seek error with #{@path}: file position = #{@watcher.pe.read_pos.to_s(16)}, reading bytesize = #{@fifo.bytesize.to_s(16)}"
|
1031
|
-
rescue Errno::
|
1066
|
+
rescue Errno::EACCES => e
|
1067
|
+
@log.warn "#{e}"
|
1068
|
+
nil
|
1069
|
+
rescue Errno::ENOENT
|
1032
1070
|
nil
|
1033
1071
|
end
|
1034
1072
|
|
@@ -1043,14 +1081,17 @@ module Fluent::Plugin
|
|
1043
1081
|
else
|
1044
1082
|
@io ||= open
|
1045
1083
|
yield @io
|
1084
|
+
@eof = true if @io.nil?
|
1046
1085
|
end
|
1047
1086
|
rescue WatcherSetupError => e
|
1048
1087
|
close
|
1088
|
+
@eof = true
|
1049
1089
|
raise e
|
1050
1090
|
rescue
|
1051
1091
|
@log.error $!.to_s
|
1052
1092
|
@log.error_backtrace
|
1053
1093
|
close
|
1094
|
+
@eof = true
|
1054
1095
|
end
|
1055
1096
|
end
|
1056
1097
|
|