fluentd 1.9.3-x64-mingw32 → 1.10.0-x64-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/workflows/issue-auto-closer.yml +12 -0
- data/CHANGELOG.md +48 -0
- data/lib/fluent/msgpack_factory.rb +13 -6
- data/lib/fluent/plugin/buffer.rb +2 -2
- data/lib/fluent/plugin/in_dummy.rb +1 -1
- data/lib/fluent/plugin/in_tail.rb +35 -26
- data/lib/fluent/plugin/out_forward.rb +4 -6
- data/lib/fluent/plugin/out_forward/handshake_protocol.rb +4 -0
- data/lib/fluent/plugin/parser_syslog.rb +114 -34
- data/lib/fluent/plugin/sd_file.rb +1 -0
- data/lib/fluent/plugin/sd_srv.rb +135 -0
- data/lib/fluent/plugin_helper/cert_option.rb +15 -2
- data/lib/fluent/plugin_helper/server.rb +3 -1
- data/lib/fluent/plugin_helper/socket_option.rb +19 -1
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_fluentd.rb +14 -2
- data/test/helper.rb +2 -2
- data/test/plugin/in_tail/test_fifo.rb +121 -0
- data/test/plugin/in_tail/test_io_handler.rb +132 -0
- data/test/plugin/in_tail/test_position_file.rb +1 -1
- data/test/plugin/out_forward/test_handshake_protocol.rb +10 -1
- data/test/plugin/test_buf_file.rb +3 -1
- data/test/plugin/test_buffer.rb +20 -0
- data/test/plugin/test_compressable.rb +7 -4
- data/test/plugin/test_in_dummy.rb +12 -14
- data/test/plugin/test_in_forward.rb +2 -2
- data/test/plugin/test_in_tail.rb +6 -6
- data/test/plugin/test_out_forward.rb +28 -1
- data/test/plugin/test_output_as_buffered_secondary.rb +1 -1
- data/test/plugin/test_parser_syslog.rb +46 -34
- data/test/plugin/test_sd_file.rb +17 -0
- data/test/plugin/test_sd_srv.rb +230 -0
- data/test/plugin_helper/data/cert/cert-with-CRLF.pem +19 -0
- data/test/plugin_helper/test_cert_option.rb +2 -0
- data/test/plugin_helper/test_child_process.rb +5 -3
- data/test/test_msgpack_factory.rb +18 -0
- metadata +14 -2
@@ -0,0 +1,135 @@
|
|
1
|
+
#
|
2
|
+
# Fluentd
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'resolv'
|
18
|
+
|
19
|
+
require 'fluent/plugin_helper'
|
20
|
+
require 'fluent/plugin/service_discovery'
|
21
|
+
|
22
|
+
module Fluent
|
23
|
+
module Plugin
|
24
|
+
class SrvServiceDiscovery < ServiceDiscovery
|
25
|
+
include PluginHelper::Mixin
|
26
|
+
|
27
|
+
Plugin.register_sd('srv', self)
|
28
|
+
|
29
|
+
helpers :timer
|
30
|
+
|
31
|
+
desc 'Service without underscore in RFC2782'
|
32
|
+
config_param :service, :string
|
33
|
+
desc 'Proto without underscore in RFC2782'
|
34
|
+
config_param :proto, :string, default: 'tcp'
|
35
|
+
desc 'Name in RFC2782'
|
36
|
+
config_param :hostname, :string
|
37
|
+
desc 'hostname of DNS server to request the SRV record'
|
38
|
+
config_param :dns_server_host, :string, default: nil
|
39
|
+
desc 'interval of requesting to DNS server'
|
40
|
+
config_param :interval, :integer, default: 60
|
41
|
+
desc "resolve hostname to IP addr of SRV's Target"
|
42
|
+
config_param :dns_lookup, :bool, default: true
|
43
|
+
desc 'The shared key per server'
|
44
|
+
config_param :shared_key, :string, default: nil, secret: true
|
45
|
+
desc 'The username for authentication'
|
46
|
+
config_param :username, :string, default: ''
|
47
|
+
desc 'The password for authentication'
|
48
|
+
config_param :password, :string, default: '', secret: true
|
49
|
+
|
50
|
+
def initialize
|
51
|
+
super
|
52
|
+
@target = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def configure(conf)
|
56
|
+
super
|
57
|
+
|
58
|
+
@target = "_#{@service}._#{@proto}.#{@hostname}"
|
59
|
+
@dns_resolve =
|
60
|
+
if @dns_server_host.nil?
|
61
|
+
Resolv::DNS.new
|
62
|
+
elsif @dns_server_host.include?(':') # e.g. 127.0.0.1:8600
|
63
|
+
host, port = @dns_server_host.split(':', 2)
|
64
|
+
Resolv::DNS.new(nameserver_port: [[host, port.to_i]])
|
65
|
+
else
|
66
|
+
Resolv::DNS.new(nameserver: @dns_server_host)
|
67
|
+
end
|
68
|
+
|
69
|
+
@services = fetch_srv_record
|
70
|
+
end
|
71
|
+
|
72
|
+
def start(queue)
|
73
|
+
timer_execute(:"sd_srv_record_#{@target}", @interval) do
|
74
|
+
refresh_srv_records(queue)
|
75
|
+
end
|
76
|
+
|
77
|
+
super()
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def refresh_srv_records(queue)
|
83
|
+
s = begin
|
84
|
+
fetch_srv_record
|
85
|
+
rescue => e
|
86
|
+
@log.error("sd_srv: #{e}")
|
87
|
+
return
|
88
|
+
end
|
89
|
+
|
90
|
+
if s.nil? || s.empty?
|
91
|
+
return
|
92
|
+
end
|
93
|
+
|
94
|
+
diff = []
|
95
|
+
join = s - @services
|
96
|
+
# Need service_in first to guarantee that server exist at least one all time.
|
97
|
+
join.each do |j|
|
98
|
+
diff << ServiceDiscovery.service_in_msg(j)
|
99
|
+
end
|
100
|
+
|
101
|
+
drain = @services - s
|
102
|
+
drain.each do |d|
|
103
|
+
diff << ServiceDiscovery.service_out_msg(d)
|
104
|
+
end
|
105
|
+
|
106
|
+
@services = s
|
107
|
+
|
108
|
+
diff.each do |a|
|
109
|
+
queue.push(a)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def fetch_srv_record
|
114
|
+
adders = @dns_resolve.getresources(@target, Resolv::DNS::Resource::IN::SRV)
|
115
|
+
|
116
|
+
services = []
|
117
|
+
|
118
|
+
adders.each do |addr|
|
119
|
+
host = @dns_lookup ? dns_lookup!(addr.target) : addr.target
|
120
|
+
services << [
|
121
|
+
addr.priority,
|
122
|
+
Service.new(:srv, host.to_s, addr.port.to_i, addr.target.to_s, addr.weight, false, @username, @password, @shared_key)
|
123
|
+
]
|
124
|
+
end
|
125
|
+
|
126
|
+
services.sort_by(&:first).flat_map { |s| s[1] }
|
127
|
+
end
|
128
|
+
|
129
|
+
def dns_lookup!(host)
|
130
|
+
# may need to cache the result
|
131
|
+
@dns_resolve.getaddress(host) # get first result for now
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -36,7 +36,7 @@ module Fluent
|
|
36
36
|
end
|
37
37
|
|
38
38
|
if conf.client_cert_auth
|
39
|
-
|
39
|
+
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
40
40
|
end
|
41
41
|
|
42
42
|
ctx.ca_file = conf.ca_path
|
@@ -45,6 +45,16 @@ module Fluent
|
|
45
45
|
if extra && !extra.empty?
|
46
46
|
ctx.extra_chain_cert = extra
|
47
47
|
end
|
48
|
+
if conf.cert_verifier
|
49
|
+
sandbox = Class.new
|
50
|
+
ctx.verify_callback = if File.exist?(conf.cert_verifier)
|
51
|
+
verifier = File.read(conf.cert_verifier)
|
52
|
+
sandbox.instance_eval(verifier, File.basename(conf.cert_verifier))
|
53
|
+
else
|
54
|
+
sandbox.instance_eval(conf.cert_verifier)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
48
58
|
Fluent::TLS.set_version_to_context(ctx, version, conf.min_version, conf.max_version)
|
49
59
|
|
50
60
|
ctx
|
@@ -171,9 +181,12 @@ module Fluent
|
|
171
181
|
|
172
182
|
def cert_option_certificates_from_file(path)
|
173
183
|
data = File.read(path)
|
174
|
-
pattern = Regexp.compile('-+BEGIN CERTIFICATE-+\n(?:[^-]*\n)+-+END CERTIFICATE-+\n?', Regexp::MULTILINE)
|
184
|
+
pattern = Regexp.compile('-+BEGIN CERTIFICATE-+\r?\n(?:[^-]*\r?\n)+-+END CERTIFICATE-+\r?\n?', Regexp::MULTILINE)
|
175
185
|
list = []
|
176
186
|
data.scan(pattern){|match| list << OpenSSL::X509::Certificate.new(match) }
|
187
|
+
if list.length == 0
|
188
|
+
log.warn "cert_path does not contain a valid certificate"
|
189
|
+
end
|
177
190
|
list
|
178
191
|
end
|
179
192
|
end
|
@@ -243,7 +243,7 @@ module Fluent
|
|
243
243
|
:protocol, :version, :min_version, :max_version, :ciphers, :insecure,
|
244
244
|
:ca_path, :cert_path, :private_key_path, :private_key_passphrase, :client_cert_auth,
|
245
245
|
:ca_cert_path, :ca_private_key_path, :ca_private_key_passphrase,
|
246
|
-
:generate_private_key_length,
|
246
|
+
:cert_verifier, :generate_private_key_length,
|
247
247
|
:generate_cert_country, :generate_cert_state, :generate_cert_state,
|
248
248
|
:generate_cert_locality, :generate_cert_common_name,
|
249
249
|
:generate_cert_expiration, :generate_cert_digest,
|
@@ -281,6 +281,8 @@ module Fluent
|
|
281
281
|
config_param :ca_private_key_path, :string, default: nil
|
282
282
|
config_param :ca_private_key_passphrase, :string, default: nil, secret: true
|
283
283
|
|
284
|
+
config_param :cert_verifier, :string, default: nil
|
285
|
+
|
284
286
|
# Options for generating certs by private CA certs or self-signed
|
285
287
|
config_param :generate_private_key_length, :integer, default: 2048
|
286
288
|
config_param :generate_cert_country, :string, default: 'US'
|
@@ -21,6 +21,8 @@ require 'fcntl'
|
|
21
21
|
module Fluent
|
22
22
|
module PluginHelper
|
23
23
|
module SocketOption
|
24
|
+
# ref: https://docs.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-linger
|
25
|
+
FORMAT_STRUCT_LINGER_WINDOWS = 'S!S!' # { u_short l_onoff; u_short l_linger; }
|
24
26
|
FORMAT_STRUCT_LINGER = 'I!I!' # { int l_onoff; int l_linger; }
|
25
27
|
FORMAT_STRUCT_TIMEVAL = 'L!L!' # { time_t tv_sec; suseconds_t tv_usec; }
|
26
28
|
|
@@ -49,9 +51,25 @@ module Fluent
|
|
49
51
|
if nonblock
|
50
52
|
sock.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
|
51
53
|
end
|
52
|
-
if
|
54
|
+
if Fluent.windows?
|
55
|
+
# To prevent closing socket forcibly on Windows,
|
56
|
+
# this options shouldn't be set up when linger_timeout equals to 0 (including nil).
|
57
|
+
# This unintended behavior always ocurrs on Windows when linger_timeout.to_i == 0.
|
58
|
+
# This unintented behavior causes "Errno::ECONNRESET: An existing connection was forcibly
|
59
|
+
# closed by the remote host." on Windows.
|
60
|
+
if linger_timeout.to_i > 0
|
61
|
+
if linger_timeout >= 2**16
|
62
|
+
log.warn "maximum linger_timeout is 65535(2^16 - 1). Set to 65535 forcibly."
|
63
|
+
linger_timeout = 2**16 - 1
|
64
|
+
end
|
65
|
+
optval = [1, linger_timeout.to_i].pack(FORMAT_STRUCT_LINGER_WINDOWS)
|
66
|
+
socket_option_set_one(sock, :SO_LINGER, optval)
|
67
|
+
end
|
68
|
+
else
|
69
|
+
if linger_timeout
|
53
70
|
optval = [1, linger_timeout.to_i].pack(FORMAT_STRUCT_LINGER)
|
54
71
|
socket_option_set_one(sock, :SO_LINGER, optval)
|
72
|
+
end
|
55
73
|
end
|
56
74
|
if recv_timeout
|
57
75
|
optval = [recv_timeout.to_i, 0].pack(FORMAT_STRUCT_TIMEVAL)
|
data/lib/fluent/version.rb
CHANGED
@@ -84,6 +84,18 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
84
84
|
null_stream.close rescue nil
|
85
85
|
end
|
86
86
|
|
87
|
+
def eager_read(io)
|
88
|
+
buf = +''
|
89
|
+
|
90
|
+
loop do
|
91
|
+
b = io.read_nonblock(1024, nil, exception: false)
|
92
|
+
if b == :wait_readable || b.nil?
|
93
|
+
return buf
|
94
|
+
end
|
95
|
+
buf << b
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
87
99
|
def assert_log_matches(cmdline, *pattern_list, patterns_not_match: [], timeout: 10, env: {})
|
88
100
|
matched = false
|
89
101
|
assert_error_msg = "matched correctly"
|
@@ -97,7 +109,7 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
97
109
|
next unless readables
|
98
110
|
break if readables.first.eof?
|
99
111
|
|
100
|
-
buf = readables.first
|
112
|
+
buf = eager_read(readables.first)
|
101
113
|
# puts buf
|
102
114
|
stdio_buf << buf
|
103
115
|
lines = stdio_buf.split("\n")
|
@@ -150,7 +162,7 @@ class TestFluentdCommand < ::Test::Unit::TestCase
|
|
150
162
|
next unless readables
|
151
163
|
next if readables.first.eof?
|
152
164
|
|
153
|
-
stdio_buf << readables.first
|
165
|
+
stdio_buf << eager_read(readables.first)
|
154
166
|
lines = stdio_buf.split("\n")
|
155
167
|
if lines.any?{|line| line.include?("fluentd worker is now running") }
|
156
168
|
running = true
|
data/test/helper.rb
CHANGED
@@ -49,8 +49,8 @@ require 'fluent/plugin_helper'
|
|
49
49
|
require 'fluent/msgpack_factory'
|
50
50
|
require 'fluent/time'
|
51
51
|
require 'serverengine'
|
52
|
-
|
53
|
-
|
52
|
+
require_relative 'helpers/fuzzy_assert'
|
53
|
+
require_relative 'helpers/process_extenstion'
|
54
54
|
|
55
55
|
module Fluent
|
56
56
|
module Plugin
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require_relative '../../helper'
|
2
|
+
|
3
|
+
require 'fluent/plugin/in_tail'
|
4
|
+
|
5
|
+
class IntailFIFO < Test::Unit::TestCase
|
6
|
+
sub_test_case '#read_line' do
|
7
|
+
test 'returns lines spliting per `\n`' do
|
8
|
+
fifo = Fluent::Plugin::TailInput::TailWatcher::FIFO.new(Encoding::ASCII_8BIT, Encoding::ASCII_8BIT)
|
9
|
+
text = ("test\n" * 3).force_encoding(Encoding::ASCII_8BIT)
|
10
|
+
fifo << text
|
11
|
+
lines = []
|
12
|
+
fifo.read_lines(lines)
|
13
|
+
assert_equal Encoding::ASCII_8BIT, lines[0].encoding
|
14
|
+
assert_equal ["test\n", "test\n", "test\n"], lines
|
15
|
+
end
|
16
|
+
|
17
|
+
test 'concant line when line is separated' do
|
18
|
+
fifo = Fluent::Plugin::TailInput::TailWatcher::FIFO.new(Encoding::ASCII_8BIT, Encoding::ASCII_8BIT)
|
19
|
+
text = ("test\n" * 3 + 'test').force_encoding(Encoding::ASCII_8BIT)
|
20
|
+
fifo << text
|
21
|
+
lines = []
|
22
|
+
fifo.read_lines(lines)
|
23
|
+
assert_equal Encoding::ASCII_8BIT, lines[0].encoding
|
24
|
+
assert_equal ["test\n", "test\n", "test\n"], lines
|
25
|
+
|
26
|
+
fifo << "2\n"
|
27
|
+
fifo.read_lines(lines)
|
28
|
+
assert_equal Encoding::ASCII_8BIT, lines[0].encoding
|
29
|
+
assert_equal ["test\n", "test\n", "test\n", "test2\n"], lines
|
30
|
+
end
|
31
|
+
|
32
|
+
test 'returns lines which convert encoding' do
|
33
|
+
fifo = Fluent::Plugin::TailInput::TailWatcher::FIFO.new(Encoding::ASCII_8BIT, Encoding::UTF_8)
|
34
|
+
text = ("test\n" * 3).force_encoding(Encoding::ASCII_8BIT)
|
35
|
+
fifo << text
|
36
|
+
lines = []
|
37
|
+
fifo.read_lines(lines)
|
38
|
+
assert_equal Encoding::UTF_8, lines[0].encoding
|
39
|
+
assert_equal ["test\n", "test\n", "test\n"], lines
|
40
|
+
end
|
41
|
+
|
42
|
+
test 'reads lines as from_encoding' do
|
43
|
+
fifo = Fluent::Plugin::TailInput::TailWatcher::FIFO.new(Encoding::UTF_8, Encoding::ASCII_8BIT)
|
44
|
+
text = ("test\n" * 3).force_encoding(Encoding::UTF_8)
|
45
|
+
fifo << text
|
46
|
+
lines = []
|
47
|
+
fifo.read_lines(lines)
|
48
|
+
assert_equal Encoding::ASCII_8BIT, lines[0].encoding
|
49
|
+
assert_equal ["test\n", "test\n", "test\n"], lines
|
50
|
+
end
|
51
|
+
|
52
|
+
sub_test_case 'when it includes multi byte chars' do
|
53
|
+
test 'handles it as ascii_8bit' do
|
54
|
+
fifo = Fluent::Plugin::TailInput::TailWatcher::FIFO.new(Encoding::ASCII_8BIT, Encoding::ASCII_8BIT)
|
55
|
+
text = ("てすと\n" * 3).force_encoding(Encoding::ASCII_8BIT)
|
56
|
+
fifo << text
|
57
|
+
lines = []
|
58
|
+
fifo.read_lines(lines)
|
59
|
+
assert_equal Encoding::ASCII_8BIT, lines[0].encoding
|
60
|
+
assert_equal ["てすと\n", "てすと\n", "てすと\n"].map { |e| e.force_encoding(Encoding::ASCII_8BIT) }, lines
|
61
|
+
end
|
62
|
+
|
63
|
+
test 'replaces character with ? when convert error happens' do
|
64
|
+
fifo = Fluent::Plugin::TailInput::TailWatcher::FIFO.new(Encoding::UTF_8, Encoding::ASCII_8BIT)
|
65
|
+
text = ("てすと\n" * 3).force_encoding(Encoding::UTF_8)
|
66
|
+
fifo << text
|
67
|
+
lines = []
|
68
|
+
fifo.read_lines(lines)
|
69
|
+
assert_equal Encoding::ASCII_8BIT, lines[0].encoding
|
70
|
+
assert_equal ["???\n", "???\n", "???\n"].map { |e| e.force_encoding(Encoding::ASCII_8BIT) }, lines
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
test 'reutrns nothing when buffer is empty' do
|
75
|
+
fifo = Fluent::Plugin::TailInput::TailWatcher::FIFO.new(Encoding::ASCII_8BIT, Encoding::ASCII_8BIT)
|
76
|
+
lines = []
|
77
|
+
fifo.read_lines(lines)
|
78
|
+
assert_equal [], lines
|
79
|
+
|
80
|
+
text = "test\n" * 3
|
81
|
+
fifo << text
|
82
|
+
fifo.read_lines(lines)
|
83
|
+
assert_equal ["test\n", "test\n", "test\n"], lines
|
84
|
+
|
85
|
+
lines = []
|
86
|
+
fifo.read_lines(lines)
|
87
|
+
assert_equal [], lines
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
sub_test_case '#<<' do
|
92
|
+
test 'does not make any change about encoding to an argument' do
|
93
|
+
fifo = Fluent::Plugin::TailInput::TailWatcher::FIFO.new(Encoding::ASCII_8BIT, Encoding::ASCII_8BIT)
|
94
|
+
text = ("test\n" * 3).force_encoding(Encoding::UTF_8)
|
95
|
+
|
96
|
+
assert_equal Encoding::UTF_8, text.encoding
|
97
|
+
fifo << text
|
98
|
+
assert_equal Encoding::UTF_8, text.encoding
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
sub_test_case '#bytesize' do
|
103
|
+
test 'reutrns buffer size' do
|
104
|
+
fifo = Fluent::Plugin::TailInput::TailWatcher::FIFO.new(Encoding::ASCII_8BIT, Encoding::ASCII_8BIT)
|
105
|
+
text = "test\n" * 3 + 'test'
|
106
|
+
fifo << text
|
107
|
+
|
108
|
+
assert_equal text.bytesize, fifo.bytesize
|
109
|
+
lines = []
|
110
|
+
fifo.read_lines(lines)
|
111
|
+
assert_equal ["test\n", "test\n", "test\n"], lines
|
112
|
+
|
113
|
+
assert_equal 'test'.bytesize, fifo.bytesize
|
114
|
+
fifo << "2\n"
|
115
|
+
fifo.read_lines(lines)
|
116
|
+
assert_equal ["test\n", "test\n", "test\n", "test2\n"], lines
|
117
|
+
|
118
|
+
assert_equal 0, fifo.bytesize
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require_relative '../../helper'
|
2
|
+
|
3
|
+
require 'fluent/plugin/in_tail'
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
class IntailIOHandlerTest < Test::Unit::TestCase
|
7
|
+
setup do
|
8
|
+
@file = Tempfile.new('intail_io_handler').binmode
|
9
|
+
end
|
10
|
+
|
11
|
+
teardown do
|
12
|
+
@file.close rescue nil
|
13
|
+
@file.unlink rescue nil
|
14
|
+
end
|
15
|
+
|
16
|
+
test '#on_notify load file content and passed it to receive_lines method' do
|
17
|
+
text = "this line is test\ntest line is test\n"
|
18
|
+
@file.write(text)
|
19
|
+
@file.close
|
20
|
+
|
21
|
+
watcher = 'watcher'
|
22
|
+
|
23
|
+
update_pos = 0
|
24
|
+
|
25
|
+
stub(watcher).pe do
|
26
|
+
pe = 'position_file'
|
27
|
+
stub(pe).read_pos { 0 }
|
28
|
+
stub(pe).update_pos { |val| update_pos = val }
|
29
|
+
pe
|
30
|
+
end
|
31
|
+
|
32
|
+
returned_lines = ''
|
33
|
+
r = Fluent::Plugin::TailInput::TailWatcher::IOHandler.new(watcher, path: @file.path, read_lines_limit: 100, log: $log, open_on_every_update: false) do |lines, _watcher|
|
34
|
+
returned_lines << lines.join
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
r.on_notify
|
39
|
+
assert_equal text.bytesize, update_pos
|
40
|
+
assert_equal text, returned_lines
|
41
|
+
|
42
|
+
r.on_notify
|
43
|
+
|
44
|
+
assert_equal text.bytesize, update_pos
|
45
|
+
assert_equal text, returned_lines
|
46
|
+
end
|
47
|
+
|
48
|
+
sub_test_case 'when open_on_every_update is true and read_pos returns always 0' do
|
49
|
+
test 'open new IO and change pos to 0 and read it' do
|
50
|
+
text = "this line is test\ntest line is test\n"
|
51
|
+
@file.write(text)
|
52
|
+
@file.close
|
53
|
+
|
54
|
+
update_pos = 0
|
55
|
+
|
56
|
+
watcher = 'watcher'
|
57
|
+
stub(watcher).pe do
|
58
|
+
pe = 'position_file'
|
59
|
+
stub(pe).read_pos { 0 }
|
60
|
+
stub(pe).update_pos { |val| update_pos = val }
|
61
|
+
pe
|
62
|
+
end
|
63
|
+
|
64
|
+
returned_lines = ''
|
65
|
+
r = Fluent::Plugin::TailInput::TailWatcher::IOHandler.new(watcher, path: @file.path, read_lines_limit: 100, log: $log, open_on_every_update: true) do |lines, _watcher|
|
66
|
+
returned_lines << lines.join
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
r.on_notify
|
71
|
+
assert_equal text.bytesize, update_pos
|
72
|
+
assert_equal text, returned_lines
|
73
|
+
|
74
|
+
r.on_notify
|
75
|
+
assert_equal text * 2, returned_lines
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
sub_test_case 'when limit is 5' do
|
80
|
+
test 'call receive_lines once when short line(less than 8192)' do
|
81
|
+
text = "line\n" * 8
|
82
|
+
@file.write(text)
|
83
|
+
@file.close
|
84
|
+
|
85
|
+
update_pos = 0
|
86
|
+
|
87
|
+
watcher = 'watcher'
|
88
|
+
stub(watcher).pe do
|
89
|
+
pe = 'position_file'
|
90
|
+
stub(pe).read_pos { 0 }
|
91
|
+
stub(pe).update_pos { |val| update_pos = val }
|
92
|
+
pe
|
93
|
+
end
|
94
|
+
|
95
|
+
returned_lines = []
|
96
|
+
r = Fluent::Plugin::TailInput::TailWatcher::IOHandler.new(watcher, path: @file.path, read_lines_limit: 5, log: $log, open_on_every_update: false) do |lines, _watcher|
|
97
|
+
returned_lines << lines.dup
|
98
|
+
true
|
99
|
+
end
|
100
|
+
|
101
|
+
r.on_notify
|
102
|
+
assert_equal 8, returned_lines[0].size
|
103
|
+
end
|
104
|
+
|
105
|
+
test 'call receive_lines some times when long line(more than 8192)' do
|
106
|
+
t = 'line' * (8192 / 8)
|
107
|
+
text = "#{t}\n" * 8
|
108
|
+
@file.write(text)
|
109
|
+
@file.close
|
110
|
+
|
111
|
+
update_pos = 0
|
112
|
+
|
113
|
+
watcher = 'watcher'
|
114
|
+
stub(watcher).pe do
|
115
|
+
pe = 'position_file'
|
116
|
+
stub(pe).read_pos { 0 }
|
117
|
+
stub(pe).update_pos { |val| update_pos = val }
|
118
|
+
pe
|
119
|
+
end
|
120
|
+
|
121
|
+
returned_lines = []
|
122
|
+
r = Fluent::Plugin::TailInput::TailWatcher::IOHandler.new(watcher, path: @file.path, read_lines_limit: 5, log: $log, open_on_every_update: false) do |lines, _watcher|
|
123
|
+
returned_lines << lines.dup
|
124
|
+
true
|
125
|
+
end
|
126
|
+
|
127
|
+
r.on_notify
|
128
|
+
assert_equal 5, returned_lines[0].size
|
129
|
+
assert_equal 3, returned_lines[1].size
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|