fluentd 1.12.4 → 1.13.0
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/workflows/windows-test.yaml +13 -2
- data/CHANGELOG.md +42 -0
- data/CONTRIBUTING.md +2 -2
- data/MAINTAINERS.md +1 -1
- data/README.md +1 -1
- data/example/counter.conf +1 -1
- data/lib/fluent/command/cat.rb +19 -3
- data/lib/fluent/command/fluentd.rb +1 -2
- data/lib/fluent/log.rb +1 -0
- data/lib/fluent/plugin/file_wrapper.rb +13 -4
- data/lib/fluent/plugin/in_http.rb +10 -0
- data/lib/fluent/plugin/in_tail.rb +119 -39
- data/lib/fluent/plugin/out_forward.rb +13 -30
- data/lib/fluent/plugin_helper/service_discovery.rb +39 -1
- data/lib/fluent/plugin_helper/service_discovery/manager.rb +11 -5
- data/lib/fluent/supervisor.rb +15 -0
- data/lib/fluent/system_config.rb +14 -0
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_cat.rb +96 -0
- data/test/config/test_system_config.rb +46 -0
- data/test/plugin/in_tail/test_io_handler.rb +4 -4
- data/test/plugin/test_file_wrapper.rb +11 -1
- data/test/plugin/test_in_http.rb +15 -0
- data/test/plugin/test_in_tail.rb +223 -1
- data/test/plugin/test_out_forward.rb +11 -6
- data/test/plugin_helper/test_service_discovery.rb +74 -14
- data/test/test_config.rb +2 -1
- data/test/test_supervisor.rb +35 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20ece94d6aedf52ed5f7bdefedfda93056ef92bbc44a7b7a27c4b4e4660dc5e0
|
4
|
+
data.tar.gz: 76166c17b6018360db1d192c2a9aa8094c1fea780bc74f715264035f0485d601
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 214cbbef726516095e961786462e33b355fd77ecdcd278f5ada3a6f8d02489620ddbf84b9a7a4ba1de27b925f5455dda3c2b90c024bfa573afda05cc453d8e3a
|
7
|
+
data.tar.gz: 75de8aad92959bcb746be2c225c627e3f6590e2ffba38a91d0d0c540c7752bb2ebacc0623132a8ee613775ce63530a8083070fd008bb54646ecc37e4e2f6ca31
|
@@ -18,9 +18,17 @@ jobs:
|
|
18
18
|
- windows-latest
|
19
19
|
experimental: [false]
|
20
20
|
include:
|
21
|
-
- ruby-version: '3.0'
|
21
|
+
- ruby-version: '3.0.1'
|
22
22
|
os: windows-latest
|
23
23
|
experimental: true
|
24
|
+
# On Ruby 3.0, we need to use fiddle 1.0.8 or later to retrieve correct
|
25
|
+
# error code. In addition, we have to specify the path of fiddle by RUBYLIB
|
26
|
+
# because RubyInstaller loads Ruby's bundled fiddle before initializing gem.
|
27
|
+
# See also:
|
28
|
+
# * https://github.com/ruby/fiddle/issues/72
|
29
|
+
# * https://bugs.ruby-lang.org/issues/17813
|
30
|
+
# * https://github.com/oneclick/rubyinstaller2/blob/8225034c22152d8195bc0aabc42a956c79d6c712/lib/ruby_installer/build/dll_directory.rb
|
31
|
+
ruby-lib-opt: RUBYLIB=%RUNNER_TOOL_CACHE%/Ruby/3.0.1/x64/lib/ruby/gems/3.0.0/gems/fiddle-1.0.8/lib
|
24
32
|
|
25
33
|
name: Unit testing with Ruby ${{ matrix.ruby-version }} on ${{ matrix.os }}
|
26
34
|
steps:
|
@@ -29,7 +37,10 @@ jobs:
|
|
29
37
|
uses: ruby/setup-ruby@v1
|
30
38
|
with:
|
31
39
|
ruby-version: ${{ matrix.ruby-version }}
|
40
|
+
- name: Add Fiddle 1.0.8
|
41
|
+
if: ${{ matrix.ruby-version == '3.0.1' }}
|
42
|
+
run: gem install fiddle --version 1.0.8
|
32
43
|
- name: Install dependencies
|
33
44
|
run: ridk exec bundle install
|
34
45
|
- name: Run tests
|
35
|
-
run: bundle exec rake test TESTOPTS=-v
|
46
|
+
run: bundle exec rake test TESTOPTS=-v ${{ matrix.ruby-lib-opt }}
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,45 @@
|
|
1
|
+
# v1.13
|
2
|
+
|
3
|
+
## Release v1.13.0 - 2021/05/29
|
4
|
+
|
5
|
+
### Enhancement
|
6
|
+
|
7
|
+
* in_tail: Handle log throttling per file feature
|
8
|
+
https://github.com/fluent/fluentd/pull/3185
|
9
|
+
https://github.com/fluent/fluentd/pull/3364
|
10
|
+
https://github.com/fluent/fluentd/pull/3379
|
11
|
+
* Extend to support service discovery manager in simpler way
|
12
|
+
https://github.com/fluent/fluentd/pull/3299
|
13
|
+
https://github.com/fluent/fluentd/pull/3362
|
14
|
+
* in_http: HTTP GET requests has been supported
|
15
|
+
https://github.com/fluent/fluentd/pull/3373
|
16
|
+
* The log rotate settings in system configuration has been supported
|
17
|
+
https://github.com/fluent/fluentd/pull/3352
|
18
|
+
|
19
|
+
### Bug fix
|
20
|
+
|
21
|
+
* Fix to disable `trace_instruction` when
|
22
|
+
`RubyVM::InstructionSequence` is available. It improves
|
23
|
+
compatibility with `truffleruby` some extent.
|
24
|
+
https://github.com/fluent/fluentd/pull/3376
|
25
|
+
* in_tail: Safely skip files which are used by another process on
|
26
|
+
Windows. It improves exception handling about
|
27
|
+
`ERROR_SHARING_VIOLATION` on Windows.
|
28
|
+
https://github.com/fluent/fluentd/pull/3378
|
29
|
+
* fluent-cat: the issue resending secondary file in specific format
|
30
|
+
has been fixed
|
31
|
+
https://github.com/fluent/fluentd/pull/3368
|
32
|
+
* in_tail: Shutdown immediately & safely even if reading huge files
|
33
|
+
Note that `skip_refresh_on_startup` must be enabled.
|
34
|
+
https://github.com/fluent/fluentd/pull/3380
|
35
|
+
|
36
|
+
### Misc
|
37
|
+
|
38
|
+
* example: Change a path to backup_path in counter_server correctly
|
39
|
+
https://github.com/fluent/fluentd/pull/3359
|
40
|
+
* README: Update link to community forum to discuss.fluentd.org
|
41
|
+
https://github.com/fluent/fluentd/pull/3360
|
42
|
+
|
1
43
|
# v1.12
|
2
44
|
|
3
45
|
## Release v1.12.4 - 2021/05/26
|
data/CONTRIBUTING.md
CHANGED
@@ -6,7 +6,7 @@ We'd love your contribution. Here are the guidelines!
|
|
6
6
|
|
7
7
|
RESOURCES of [Official site](https://www.fluentd.org/) and [Fluentd documentation](https://docs.fluentd.org/) may help you.
|
8
8
|
|
9
|
-
If you have further questions about Fluentd and plugins, please direct these to [
|
9
|
+
If you have further questions about Fluentd and plugins, please direct these to [Community Forum](https://discuss.fluentd.org/).
|
10
10
|
Don't use Github issue for asking questions. Here are examples:
|
11
11
|
|
12
12
|
- I installed xxx plugin but it doesn't work. Why?
|
@@ -16,7 +16,7 @@ Don't use Github issue for asking questions. Here are examples:
|
|
16
16
|
We may close such questions to keep clear repository for developers and users.
|
17
17
|
Github issue is mainly for submitting a bug report or feature request. See below.
|
18
18
|
|
19
|
-
If you can't judge your case is a bug or not, use
|
19
|
+
If you can't judge your case is a bug or not, use community forum or slack first.
|
20
20
|
|
21
21
|
## Found a bug?
|
22
22
|
|
data/MAINTAINERS.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
- [Naotoshi Seo](https://github.com/sonots), [ZOZO Technologies](https://tech.zozo.com/en/)
|
4
4
|
- [Okkez](https://github.com/okkez)
|
5
|
-
- [Hiroshi Hatake](https://github.com/cosmo0920), [
|
5
|
+
- [Hiroshi Hatake](https://github.com/cosmo0920), [Calyptia](https://www.calyptia.com/)
|
6
6
|
- [Masahiro Nakagawa](https://github.com/repeatedly), [Treasure Data](https://www.treasuredata.com/)
|
7
7
|
- [Satoshi Tagomori](https://github.com/tagomoris), [Treasure Data](https://www.treasuredata.com/)
|
8
8
|
- [Eduardo Silva](https://github.com/edsiper), [Arm Treasure Data](https://www.treasuredata.com/)
|
data/README.md
CHANGED
@@ -77,7 +77,7 @@ You can run specified test via `TEST` environment variable:
|
|
77
77
|
- Website: https://www.fluentd.org/
|
78
78
|
- Documentation: https://docs.fluentd.org/
|
79
79
|
- Project repository: https://github.com/fluent
|
80
|
-
- Discussion: https://
|
80
|
+
- Discussion: https://discuss.fluentd.org/
|
81
81
|
- Slack / Community: https://slack.fluentd.org
|
82
82
|
- Newsletters: https://www.fluentd.org/newsletter
|
83
83
|
- Author: [Sadayuki Furuhashi](https://github.com/frsyuki)
|
data/example/counter.conf
CHANGED
data/lib/fluent/command/cat.rb
CHANGED
@@ -152,14 +152,30 @@ class Writer
|
|
152
152
|
super()
|
153
153
|
end
|
154
154
|
|
155
|
+
def secondary_record?(record)
|
156
|
+
record.class != Hash &&
|
157
|
+
record.size == 2 &&
|
158
|
+
record.first.class == Fluent::EventTime &&
|
159
|
+
record.last.class == Hash
|
160
|
+
end
|
161
|
+
|
155
162
|
def write(record)
|
156
|
-
|
157
|
-
|
163
|
+
unless secondary_record?(record)
|
164
|
+
if record.class != Hash
|
165
|
+
raise ArgumentError, "Input must be a map (got #{record.class})"
|
166
|
+
end
|
158
167
|
end
|
159
168
|
|
160
169
|
time = Fluent::EventTime.now
|
161
170
|
time = time.to_i if @time_as_integer
|
162
|
-
entry =
|
171
|
+
entry = if secondary_record?(record)
|
172
|
+
# Even though secondary contains Fluent::EventTime in record,
|
173
|
+
# fluent-cat just ignore it and set Fluent::EventTime.now instead.
|
174
|
+
# This specification is adopted to keep consistency.
|
175
|
+
[time, record.last]
|
176
|
+
else
|
177
|
+
[time, record]
|
178
|
+
end
|
163
179
|
synchronize {
|
164
180
|
unless write_impl([entry])
|
165
181
|
# write failed
|
@@ -85,9 +85,8 @@ op.on('-o', '--log PATH', "log file path") {|s|
|
|
85
85
|
opts[:log_path] = s
|
86
86
|
}
|
87
87
|
|
88
|
-
ROTATE_AGE = %w(daily weekly monthly)
|
89
88
|
op.on('--log-rotate-age AGE', 'generations to keep rotated log files') {|age|
|
90
|
-
if
|
89
|
+
if Fluent::Log::LOG_ROTATE_AGE.include?(age)
|
91
90
|
opts[:log_rotate_age] = age
|
92
91
|
else
|
93
92
|
begin
|
data/lib/fluent/log.rb
CHANGED
@@ -49,6 +49,7 @@ module Fluent
|
|
49
49
|
LOG_TYPE_DEFAULT = :default # show logs in all supervisor/workers, with worker id in workers (default)
|
50
50
|
|
51
51
|
LOG_TYPES = [LOG_TYPE_SUPERVISOR, LOG_TYPE_WORKER0, LOG_TYPE_DEFAULT].freeze
|
52
|
+
LOG_ROTATE_AGE = %w(daily weekly monthly)
|
52
53
|
|
53
54
|
def self.str_to_level(log_level_str)
|
54
55
|
case log_level_str.downcase
|
@@ -52,6 +52,8 @@ module Fluent
|
|
52
52
|
|
53
53
|
attr_reader :errcode, :msg
|
54
54
|
|
55
|
+
WSABASEERR = 10000
|
56
|
+
|
55
57
|
def initialize(errcode, msg = nil)
|
56
58
|
@errcode = errcode
|
57
59
|
@msg = msg
|
@@ -80,6 +82,10 @@ module Fluent
|
|
80
82
|
return false if other.class != Win32Error
|
81
83
|
@errcode == other.errcode && @msg == other.msg
|
82
84
|
end
|
85
|
+
|
86
|
+
def wsaerr?
|
87
|
+
@errcode >= WSABASEERR
|
88
|
+
end
|
83
89
|
end
|
84
90
|
|
85
91
|
# To open and get stat with setting FILE_SHARE_DELETE
|
@@ -113,11 +119,14 @@ module Fluent
|
|
113
119
|
@file_handle = CreateFile.call(@path, access, sharemode,
|
114
120
|
0, creationdisposition, FILE_ATTRIBUTE_NORMAL, 0)
|
115
121
|
if @file_handle == INVALID_HANDLE_VALUE
|
116
|
-
|
117
|
-
|
118
|
-
|
122
|
+
win32err = Win32Error.new(Win32::API.last_error, path)
|
123
|
+
errno = ServerEngine::RbWinSock.rb_w32_map_errno(win32err.errcode)
|
124
|
+
if errno == Errno::EINVAL::Errno || win32err.wsaerr?
|
125
|
+
# maybe failed to map
|
126
|
+
raise win32err
|
127
|
+
else
|
128
|
+
raise SystemCallError.new(win32err.message, errno)
|
119
129
|
end
|
120
|
-
raise Win32Error.new(err, path)
|
121
130
|
end
|
122
131
|
end
|
123
132
|
|
@@ -461,6 +461,12 @@ module Fluent::Plugin
|
|
461
461
|
RES_200_STATUS = "200 OK".freeze
|
462
462
|
RES_403_STATUS = "403 Forbidden".freeze
|
463
463
|
|
464
|
+
# Azure App Service sends GET requests for health checking purpose.
|
465
|
+
# Respond with `200 OK` to accommodate it.
|
466
|
+
def handle_get_request
|
467
|
+
return send_response_and_close(RES_200_STATUS, {}, "")
|
468
|
+
end
|
469
|
+
|
464
470
|
# Web browsers can send an OPTIONS request before performing POST
|
465
471
|
# to check if cross-origin requests are supported.
|
466
472
|
def handle_options_request
|
@@ -494,6 +500,10 @@ module Fluent::Plugin
|
|
494
500
|
def on_message_complete
|
495
501
|
return if closing?
|
496
502
|
|
503
|
+
if @parser.http_method == 'GET'.freeze
|
504
|
+
return handle_get_request()
|
505
|
+
end
|
506
|
+
|
497
507
|
if @parser.http_method == 'OPTIONS'.freeze
|
498
508
|
return handle_options_request()
|
499
509
|
end
|
@@ -56,6 +56,7 @@ module Fluent::Plugin
|
|
56
56
|
@pf_file = nil
|
57
57
|
@pf = nil
|
58
58
|
@ignore_list = []
|
59
|
+
@shutdown_start_time = nil
|
59
60
|
end
|
60
61
|
|
61
62
|
desc 'The paths to read. Multiple paths can be specified, separated by comma.'
|
@@ -81,6 +82,8 @@ module Fluent::Plugin
|
|
81
82
|
config_param :refresh_interval, :time, default: 60
|
82
83
|
desc 'The number of reading lines at each IO.'
|
83
84
|
config_param :read_lines_limit, :integer, default: 1000
|
85
|
+
desc 'The number of reading bytes per second'
|
86
|
+
config_param :read_bytes_limit_per_second, :size, default: -1
|
84
87
|
desc 'The interval of flushing the buffer for multiline format'
|
85
88
|
config_param :multiline_flush_interval, :time, default: nil
|
86
89
|
desc 'Enable the option to emit unmatched lines.'
|
@@ -178,6 +181,16 @@ module Fluent::Plugin
|
|
178
181
|
# parser is already created by parser helper
|
179
182
|
@parser = parser_create(usage: parser_config['usage'] || @parser_configs.first.usage)
|
180
183
|
@capability = Fluent::Capability.new(:current_process)
|
184
|
+
if @read_bytes_limit_per_second > 0
|
185
|
+
if !@enable_watch_timer
|
186
|
+
raise Fluent::ConfigError, "Need to enable watch timer when using log throttling feature"
|
187
|
+
end
|
188
|
+
min_bytes = TailWatcher::IOHandler::BYTES_TO_READ
|
189
|
+
if @read_bytes_limit_per_second < min_bytes
|
190
|
+
log.warn "Should specify greater equal than #{min_bytes}. Use #{min_bytes} for read_bytes_limit_per_second"
|
191
|
+
@read_bytes_limit_per_second = min_bytes
|
192
|
+
end
|
193
|
+
end
|
181
194
|
end
|
182
195
|
|
183
196
|
def configure_tag
|
@@ -244,6 +257,7 @@ module Fluent::Plugin
|
|
244
257
|
end
|
245
258
|
|
246
259
|
def shutdown
|
260
|
+
@shutdown_start_time = Fluent::Clock.now
|
247
261
|
# during shutdown phase, don't close io. It should be done in close after all threads are stopped. See close.
|
248
262
|
stop_watchers(existence_path, immediate: true, remove_watcher: false)
|
249
263
|
@pf_file.close if @pf_file
|
@@ -290,7 +304,7 @@ module Fluent::Plugin
|
|
290
304
|
end
|
291
305
|
false
|
292
306
|
end
|
293
|
-
rescue Errno::ENOENT
|
307
|
+
rescue Errno::ENOENT, Errno::EACCES
|
294
308
|
log.debug("#{p} is missing after refresh file list")
|
295
309
|
false
|
296
310
|
end
|
@@ -322,8 +336,8 @@ module Fluent::Plugin
|
|
322
336
|
else
|
323
337
|
hash[target_info.path] = target_info
|
324
338
|
end
|
325
|
-
rescue Errno::ENOENT
|
326
|
-
$log.warn "expand_paths: stat() for #{path} failed with
|
339
|
+
rescue Errno::ENOENT, Errno::EACCES => e
|
340
|
+
$log.warn "expand_paths: stat() for #{path} failed with #{e.class.name}. Skip file."
|
327
341
|
end
|
328
342
|
}
|
329
343
|
hash
|
@@ -373,8 +387,6 @@ module Fluent::Plugin
|
|
373
387
|
tw.register_watcher(tt)
|
374
388
|
end
|
375
389
|
|
376
|
-
tw.on_notify
|
377
|
-
|
378
390
|
tw.watchers.each do |watcher|
|
379
391
|
event_loop_attach(watcher)
|
380
392
|
end
|
@@ -386,42 +398,48 @@ module Fluent::Plugin
|
|
386
398
|
event_loop_detach(watcher)
|
387
399
|
end
|
388
400
|
|
389
|
-
tw.detach
|
401
|
+
tw.detach(@shutdown_start_time)
|
390
402
|
tw.close
|
391
403
|
end
|
392
404
|
raise e
|
393
405
|
end
|
394
406
|
|
395
|
-
def
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
$log.warn "#{target_info.path} not found. Continuing without tailing it."
|
405
|
-
end
|
407
|
+
def construct_watcher(target_info)
|
408
|
+
pe = nil
|
409
|
+
if @pf
|
410
|
+
pe = @pf[target_info]
|
411
|
+
if @read_from_head && pe.read_inode.zero?
|
412
|
+
begin
|
413
|
+
pe.update(Fluent::FileWrapper.stat(target_info.path).ino, 0)
|
414
|
+
rescue Errno::ENOENT, Errno::EACCES
|
415
|
+
$log.warn "stat() for #{target_info.path} failed. Continuing without tailing it."
|
406
416
|
end
|
407
417
|
end
|
418
|
+
end
|
408
419
|
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
420
|
+
begin
|
421
|
+
tw = setup_watcher(target_info, pe)
|
422
|
+
rescue WatcherSetupError => e
|
423
|
+
log.warn "Skip #{target_info.path} because unexpected setup error happens: #{e}"
|
424
|
+
return
|
425
|
+
end
|
415
426
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
427
|
+
begin
|
428
|
+
target_info = TargetInfo.new(target_info.path, Fluent::FileWrapper.stat(target_info.path).ino)
|
429
|
+
@tails[target_info] = tw
|
430
|
+
tw.on_notify
|
431
|
+
rescue Errno::ENOENT, Errno::EACCES => e
|
432
|
+
$log.warn "stat() for #{target_info.path} failed with #{e.class.name}. Drop tail watcher for now."
|
433
|
+
# explicitly detach and unwatch watcher `tw`.
|
434
|
+
tw.unwatched = true
|
435
|
+
detach_watcher(tw, target_info.ino, false)
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
def start_watchers(targets_info)
|
440
|
+
targets_info.each_value {|target_info|
|
441
|
+
construct_watcher(target_info)
|
442
|
+
break if before_shutdown?
|
425
443
|
}
|
426
444
|
end
|
427
445
|
|
@@ -474,9 +492,11 @@ module Fluent::Plugin
|
|
474
492
|
|
475
493
|
if new_position_entry.read_inode == 0
|
476
494
|
@tails[new_target_info] = setup_watcher(new_target_info, new_position_entry)
|
495
|
+
@tails[new_target_info].on_notify
|
477
496
|
end
|
478
497
|
else
|
479
498
|
@tails[new_target_info] = setup_watcher(new_target_info, pe)
|
499
|
+
@tails[new_target_info].on_notify
|
480
500
|
end
|
481
501
|
detach_watcher_after_rotate_wait(rotated_tw, pe.read_inode) if rotated_tw
|
482
502
|
end
|
@@ -489,7 +509,7 @@ module Fluent::Plugin
|
|
489
509
|
tw.watchers.each do |watcher|
|
490
510
|
event_loop_detach(watcher)
|
491
511
|
end
|
492
|
-
tw.detach
|
512
|
+
tw.detach(@shutdown_start_time)
|
493
513
|
|
494
514
|
tw.close if close_io
|
495
515
|
|
@@ -633,6 +653,7 @@ module Fluent::Plugin
|
|
633
653
|
path: path,
|
634
654
|
log: log,
|
635
655
|
read_lines_limit: @read_lines_limit,
|
656
|
+
read_bytes_limit_per_second: @read_bytes_limit_per_second,
|
636
657
|
open_on_every_update: @open_on_every_update,
|
637
658
|
from_encoding: @from_encoding,
|
638
659
|
encoding: @encoding,
|
@@ -700,8 +721,11 @@ module Fluent::Plugin
|
|
700
721
|
@watchers << watcher
|
701
722
|
end
|
702
723
|
|
703
|
-
def detach
|
704
|
-
|
724
|
+
def detach(shutdown_start_time = nil)
|
725
|
+
if @io_handler
|
726
|
+
@io_handler.ready_to_shutdown(shutdown_start_time)
|
727
|
+
@io_handler.on_notify
|
728
|
+
end
|
705
729
|
@line_buffer_timer_flusher&.close(self)
|
706
730
|
end
|
707
731
|
|
@@ -715,7 +739,7 @@ module Fluent::Plugin
|
|
715
739
|
def on_notify
|
716
740
|
begin
|
717
741
|
stat = Fluent::FileWrapper.stat(@path)
|
718
|
-
rescue Errno::ENOENT
|
742
|
+
rescue Errno::ENOENT, Errno::EACCES
|
719
743
|
# moved or deleted
|
720
744
|
stat = nil
|
721
745
|
end
|
@@ -876,10 +900,16 @@ module Fluent::Plugin
|
|
876
900
|
end
|
877
901
|
|
878
902
|
class IOHandler
|
879
|
-
|
903
|
+
BYTES_TO_READ = 8192
|
904
|
+
SHUTDOWN_TIMEOUT = 5
|
905
|
+
|
906
|
+
attr_accessor :shutdown_timeout
|
907
|
+
|
908
|
+
def initialize(watcher, path:, read_lines_limit:, read_bytes_limit_per_second:, log:, open_on_every_update:, from_encoding: nil, encoding: nil, &receive_lines)
|
880
909
|
@watcher = watcher
|
881
910
|
@path = path
|
882
911
|
@read_lines_limit = read_lines_limit
|
912
|
+
@read_bytes_limit_per_second = read_bytes_limit_per_second
|
883
913
|
@receive_lines = receive_lines
|
884
914
|
@open_on_every_update = open_on_every_update
|
885
915
|
@fifo = FIFO.new(from_encoding || Encoding::ASCII_8BIT, encoding || Encoding::ASCII_8BIT)
|
@@ -888,6 +918,11 @@ module Fluent::Plugin
|
|
888
918
|
@io = nil
|
889
919
|
@notify_mutex = Mutex.new
|
890
920
|
@log = log
|
921
|
+
@start_reading_time = nil
|
922
|
+
@number_bytes_read = 0
|
923
|
+
@shutdown_start_time = nil
|
924
|
+
@shutdown_timeout = SHUTDOWN_TIMEOUT
|
925
|
+
@shutdown_mutex = Mutex.new
|
891
926
|
|
892
927
|
@log.info "following tail of #{@path}"
|
893
928
|
end
|
@@ -896,6 +931,13 @@ module Fluent::Plugin
|
|
896
931
|
@notify_mutex.synchronize { handle_notify }
|
897
932
|
end
|
898
933
|
|
934
|
+
def ready_to_shutdown(shutdown_start_time = nil)
|
935
|
+
@shutdown_mutex.synchronize {
|
936
|
+
@shutdown_start_time =
|
937
|
+
shutdown_start_time || Fluent::Clock.now
|
938
|
+
}
|
939
|
+
end
|
940
|
+
|
899
941
|
def close
|
900
942
|
if @io && !@io.closed?
|
901
943
|
@io.close
|
@@ -909,7 +951,35 @@ module Fluent::Plugin
|
|
909
951
|
|
910
952
|
private
|
911
953
|
|
954
|
+
def limit_bytes_per_second_reached?
|
955
|
+
return false if @read_bytes_limit_per_second < 0 # not enabled by conf
|
956
|
+
return false if @number_bytes_read < @read_bytes_limit_per_second
|
957
|
+
|
958
|
+
@start_reading_time ||= Fluent::Clock.now
|
959
|
+
time_spent_reading = Fluent::Clock.now - @start_reading_time
|
960
|
+
@log.debug("time_spent_reading: #{time_spent_reading} #{ @watcher.path}")
|
961
|
+
|
962
|
+
if time_spent_reading < 1
|
963
|
+
true
|
964
|
+
else
|
965
|
+
@start_reading_time = nil
|
966
|
+
@number_bytes_read = 0
|
967
|
+
false
|
968
|
+
end
|
969
|
+
end
|
970
|
+
|
971
|
+
def should_shutdown_now?
|
972
|
+
# Ensure to read all remaining lines, but abort immediately if it
|
973
|
+
# seems to take too long time.
|
974
|
+
@shutdown_mutex.synchronize {
|
975
|
+
return false if @shutdown_start_time.nil?
|
976
|
+
return Fluent::Clock.now - @shutdown_start_time > @shutdown_timeout
|
977
|
+
}
|
978
|
+
end
|
979
|
+
|
912
980
|
def handle_notify
|
981
|
+
return if limit_bytes_per_second_reached?
|
982
|
+
|
913
983
|
with_io do |io|
|
914
984
|
begin
|
915
985
|
read_more = false
|
@@ -917,8 +987,18 @@ module Fluent::Plugin
|
|
917
987
|
if !io.nil? && @lines.empty?
|
918
988
|
begin
|
919
989
|
while true
|
920
|
-
@
|
990
|
+
@start_reading_time ||= Fluent::Clock.now
|
991
|
+
data = io.readpartial(BYTES_TO_READ, @iobuf)
|
992
|
+
@number_bytes_read += data.bytesize
|
993
|
+
@fifo << data
|
921
994
|
@fifo.read_lines(@lines)
|
995
|
+
|
996
|
+
@log.debug("reading file: #{@path}")
|
997
|
+
if limit_bytes_per_second_reached? || should_shutdown_now?
|
998
|
+
# Just get out from tailing loop.
|
999
|
+
read_more = false
|
1000
|
+
break
|
1001
|
+
end
|
922
1002
|
if @lines.size >= @read_lines_limit
|
923
1003
|
# not to use too much memory in case the file is very large
|
924
1004
|
read_more = true
|
@@ -948,7 +1028,7 @@ module Fluent::Plugin
|
|
948
1028
|
rescue RangeError
|
949
1029
|
io.close if io
|
950
1030
|
raise WatcherSetupError, "seek error with #{@path}: file position = #{@watcher.pe.read_pos.to_s(16)}, reading bytesize = #{@fifo.bytesize.to_s(16)}"
|
951
|
-
rescue Errno::ENOENT
|
1031
|
+
rescue Errno::ENOENT, Errno::EACCES
|
952
1032
|
nil
|
953
1033
|
end
|
954
1034
|
|