fluentd 1.16.5-x64-mingw-ucrt → 1.17.0-x64-mingw-ucrt
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/DISCUSSION_TEMPLATE/q-a-japanese.yml +50 -0
- data/.github/DISCUSSION_TEMPLATE/q-a.yml +47 -0
- data/.github/workflows/test-ruby-head.yml +31 -0
- data/.github/workflows/test.yml +3 -3
- data/CHANGELOG.md +42 -0
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/fluentd.gemspec +9 -1
- data/lib/fluent/command/binlog_reader.rb +1 -1
- data/lib/fluent/config/configure_proxy.rb +2 -2
- data/lib/fluent/config/types.rb +1 -1
- data/lib/fluent/configurable.rb +2 -2
- data/lib/fluent/counter/mutex_hash.rb +1 -1
- data/lib/fluent/fluent_log_event_router.rb +0 -2
- data/lib/fluent/plugin/buf_file.rb +1 -1
- data/lib/fluent/plugin/buffer/file_chunk.rb +1 -1
- data/lib/fluent/plugin/buffer/file_single_chunk.rb +2 -3
- data/lib/fluent/plugin/filter_parser.rb +26 -8
- data/lib/fluent/plugin/in_http.rb +18 -53
- data/lib/fluent/plugin/in_tail.rb +34 -2
- data/lib/fluent/plugin/out_http.rb +125 -13
- data/lib/fluent/plugin/owned_by_mixin.rb +0 -1
- data/lib/fluent/plugin/parser_json.rb +22 -5
- data/lib/fluent/plugin/parser_msgpack.rb +24 -3
- data/lib/fluent/plugin_helper/metrics.rb +2 -2
- data/lib/fluent/registry.rb +6 -6
- data/lib/fluent/test/output_test.rb +1 -1
- data/lib/fluent/unique_id.rb +1 -1
- data/lib/fluent/version.rb +1 -1
- data/test/log/test_console_adapter.rb +10 -3
- data/test/plugin/data/log_numeric/01.log +0 -0
- data/test/plugin/data/log_numeric/02.log +0 -0
- data/test/plugin/data/log_numeric/12.log +0 -0
- data/test/plugin/data/log_numeric/14.log +0 -0
- data/test/plugin/test_in_http.rb +23 -1
- data/test/plugin/test_in_tail.rb +141 -0
- data/test/plugin/test_out_http.rb +128 -0
- data/test/plugin/test_owned_by.rb +0 -1
- data/test/plugin/test_parser_json.rb +106 -0
- data/test/plugin/test_parser_msgpack.rb +127 -0
- data/test/plugin/test_storage.rb +0 -1
- data/test/plugin_helper/test_child_process.rb +4 -4
- metadata +101 -4
@@ -37,6 +37,8 @@ module Fluent::Plugin
|
|
37
37
|
|
38
38
|
class RetryableResponse < StandardError; end
|
39
39
|
|
40
|
+
ConnectionCache = Struct.new(:uri, :conn)
|
41
|
+
|
40
42
|
helpers :formatter
|
41
43
|
|
42
44
|
desc 'The endpoint for HTTP request, e.g. http://example.com/api'
|
@@ -60,6 +62,8 @@ module Fluent::Plugin
|
|
60
62
|
config_param :read_timeout, :integer, default: nil
|
61
63
|
desc 'The TLS timeout in seconds'
|
62
64
|
config_param :ssl_timeout, :integer, default: nil
|
65
|
+
desc 'Try to reuse connections'
|
66
|
+
config_param :reuse_connections, :bool, default: false
|
63
67
|
|
64
68
|
desc 'The CA certificate path for TLS'
|
65
69
|
config_param :tls_ca_cert_path, :string, default: nil
|
@@ -87,11 +91,29 @@ module Fluent::Plugin
|
|
87
91
|
|
88
92
|
config_section :auth, required: false, multi: false do
|
89
93
|
desc 'The method for HTTP authentication'
|
90
|
-
config_param :method, :enum, list: [:basic], default: :basic
|
94
|
+
config_param :method, :enum, list: [:basic, :aws_sigv4], default: :basic
|
91
95
|
desc 'The username for basic authentication'
|
92
96
|
config_param :username, :string, default: nil
|
93
97
|
desc 'The password for basic authentication'
|
94
98
|
config_param :password, :string, default: nil, secret: true
|
99
|
+
desc 'The AWS service to authenticate against'
|
100
|
+
config_param :aws_service, :string, default: nil
|
101
|
+
desc 'The AWS region to use when authenticating'
|
102
|
+
config_param :aws_region, :string, default: nil
|
103
|
+
desc 'The AWS role ARN to assume when authenticating'
|
104
|
+
config_param :aws_role_arn, :string, default: nil
|
105
|
+
end
|
106
|
+
|
107
|
+
def connection_cache_id_thread_key
|
108
|
+
"#{plugin_id}_connection_cache_id"
|
109
|
+
end
|
110
|
+
|
111
|
+
def connection_cache_id_for_thread
|
112
|
+
Thread.current[connection_cache_id_thread_key]
|
113
|
+
end
|
114
|
+
|
115
|
+
def connection_cache_id_for_thread=(id)
|
116
|
+
Thread.current[connection_cache_id_thread_key] = id
|
95
117
|
end
|
96
118
|
|
97
119
|
def initialize
|
@@ -100,11 +122,23 @@ module Fluent::Plugin
|
|
100
122
|
@uri = nil
|
101
123
|
@proxy_uri = nil
|
102
124
|
@formatter = nil
|
125
|
+
|
126
|
+
@connection_cache = []
|
127
|
+
@connection_cache_id_mutex = Mutex.new
|
128
|
+
@connection_cache_next_id = 0
|
129
|
+
end
|
130
|
+
|
131
|
+
def close
|
132
|
+
super
|
133
|
+
|
134
|
+
@connection_cache.each {|entry| entry.conn.finish if entry.conn&.started? }
|
103
135
|
end
|
104
136
|
|
105
137
|
def configure(conf)
|
106
138
|
super
|
107
139
|
|
140
|
+
@connection_cache = Array.new(actual_flush_thread_count, ConnectionCache.new("", nil)) if @reuse_connections
|
141
|
+
|
108
142
|
if @retryable_response_codes.nil?
|
109
143
|
log.warn('Status code 503 is going to be removed from default `retryable_response_codes` from fluentd v2. Please add it by yourself if you wish')
|
110
144
|
@retryable_response_codes = [503]
|
@@ -121,6 +155,36 @@ module Fluent::Plugin
|
|
121
155
|
end
|
122
156
|
define_singleton_method(:format, method(:format_json_array))
|
123
157
|
end
|
158
|
+
|
159
|
+
if @auth and @auth.method == :aws_sigv4
|
160
|
+
begin
|
161
|
+
require 'aws-sigv4'
|
162
|
+
require 'aws-sdk-core'
|
163
|
+
rescue LoadError
|
164
|
+
raise Fluent::ConfigError, "The aws-sdk-core and aws-sigv4 gems are required for aws_sigv4 auth. Run: gem install aws-sdk-core -v '~> 3.191'"
|
165
|
+
end
|
166
|
+
|
167
|
+
raise Fluent::ConfigError, "aws_service is required for aws_sigv4 auth" unless @auth.aws_service != nil
|
168
|
+
raise Fluent::ConfigError, "aws_region is required for aws_sigv4 auth" unless @auth.aws_region != nil
|
169
|
+
|
170
|
+
if @auth.aws_role_arn == nil
|
171
|
+
aws_credentials = Aws::CredentialProviderChain.new.resolve
|
172
|
+
else
|
173
|
+
aws_credentials = Aws::AssumeRoleCredentials.new(
|
174
|
+
client: Aws::STS::Client.new(
|
175
|
+
region: @auth.aws_region
|
176
|
+
),
|
177
|
+
role_arn: @auth.aws_role_arn,
|
178
|
+
role_session_name: "fluentd"
|
179
|
+
)
|
180
|
+
end
|
181
|
+
|
182
|
+
@aws_signer = Aws::Sigv4::Signer.new(
|
183
|
+
service: @auth.aws_service,
|
184
|
+
region: @auth.aws_region,
|
185
|
+
credentials_provider: aws_credentials
|
186
|
+
)
|
187
|
+
end
|
124
188
|
end
|
125
189
|
|
126
190
|
def multi_workers_ready?
|
@@ -215,7 +279,7 @@ module Fluent::Plugin
|
|
215
279
|
URI.parse(endpoint)
|
216
280
|
end
|
217
281
|
|
218
|
-
def set_headers(req, chunk)
|
282
|
+
def set_headers(req, uri, chunk)
|
219
283
|
if @headers
|
220
284
|
@headers.each do |k, v|
|
221
285
|
req[k] = v
|
@@ -229,6 +293,28 @@ module Fluent::Plugin
|
|
229
293
|
req['Content-Type'] = @content_type
|
230
294
|
end
|
231
295
|
|
296
|
+
def set_auth(req, uri)
|
297
|
+
return unless @auth
|
298
|
+
|
299
|
+
if @auth.method == :basic
|
300
|
+
req.basic_auth(@auth.username, @auth.password)
|
301
|
+
elsif @auth.method == :aws_sigv4
|
302
|
+
signature = @aws_signer.sign_request(
|
303
|
+
http_method: req.method,
|
304
|
+
url: uri.request_uri,
|
305
|
+
headers: {
|
306
|
+
'Content-Type' => @content_type,
|
307
|
+
'Host' => uri.host
|
308
|
+
},
|
309
|
+
body: req.body
|
310
|
+
)
|
311
|
+
req.add_field('x-amz-date', signature.headers['x-amz-date'])
|
312
|
+
req.add_field('x-amz-security-token', signature.headers['x-amz-security-token'])
|
313
|
+
req.add_field('x-amz-content-sha256', signature.headers['x-amz-content-sha256'])
|
314
|
+
req.add_field('authorization', signature.headers['authorization'])
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
232
318
|
def create_request(chunk, uri)
|
233
319
|
req = case @http_method
|
234
320
|
when :post
|
@@ -236,23 +322,49 @@ module Fluent::Plugin
|
|
236
322
|
when :put
|
237
323
|
Net::HTTP::Put.new(uri.request_uri)
|
238
324
|
end
|
239
|
-
|
240
|
-
req.basic_auth(@auth.username, @auth.password)
|
241
|
-
end
|
242
|
-
set_headers(req, chunk)
|
325
|
+
set_headers(req, uri, chunk)
|
243
326
|
req.body = @json_array ? "[#{chunk.read.chop}]" : chunk.read
|
327
|
+
|
328
|
+
# At least one authentication method requires the body and other headers, so the order of this call matters
|
329
|
+
set_auth(req, uri)
|
244
330
|
req
|
245
331
|
end
|
246
332
|
|
333
|
+
def make_request_cached(uri, req)
|
334
|
+
id = self.connection_cache_id_for_thread
|
335
|
+
if id.nil?
|
336
|
+
@connection_cache_id_mutex.synchronize {
|
337
|
+
id = @connection_cache_next_id
|
338
|
+
@connection_cache_next_id += 1
|
339
|
+
}
|
340
|
+
self.connection_cache_id_for_thread = id
|
341
|
+
end
|
342
|
+
uri_str = uri.to_s
|
343
|
+
if @connection_cache[id].uri != uri_str
|
344
|
+
@connection_cache[id].conn.finish if @connection_cache[id].conn&.started?
|
345
|
+
http = if @proxy_uri
|
346
|
+
Net::HTTP.start(uri.host, uri.port, @proxy_uri.host, @proxy_uri.port, @proxy_uri.user, @proxy_uri.password, @http_opt)
|
347
|
+
else
|
348
|
+
Net::HTTP.start(uri.host, uri.port, @http_opt)
|
349
|
+
end
|
350
|
+
@connection_cache[id] = ConnectionCache.new(uri_str, http)
|
351
|
+
end
|
352
|
+
@connection_cache[id].conn.request(req)
|
353
|
+
end
|
354
|
+
|
355
|
+
def make_request(uri, req, &block)
|
356
|
+
if @proxy_uri
|
357
|
+
Net::HTTP.start(uri.host, uri.port, @proxy_uri.host, @proxy_uri.port, @proxy_uri.user, @proxy_uri.password, @http_opt, &block)
|
358
|
+
else
|
359
|
+
Net::HTTP.start(uri.host, uri.port, @http_opt, &block)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
247
363
|
def send_request(uri, req)
|
248
|
-
res = if @
|
249
|
-
|
250
|
-
http.request(req)
|
251
|
-
}
|
364
|
+
res = if @reuse_connections
|
365
|
+
make_request_cached(uri, req)
|
252
366
|
else
|
253
|
-
|
254
|
-
http.request(req)
|
255
|
-
}
|
367
|
+
make_request(uri, req) { |http| http.request(req) }
|
256
368
|
end
|
257
369
|
|
258
370
|
if res.is_a?(Net::HTTPSuccess)
|
@@ -70,16 +70,33 @@ module Fluent
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def parse(text)
|
73
|
-
|
74
|
-
|
75
|
-
if
|
76
|
-
time, record =
|
73
|
+
parsed_json = @load_proc.call(text)
|
74
|
+
|
75
|
+
if parsed_json.is_a?(Hash)
|
76
|
+
time, record = parse_one_record(parsed_json)
|
77
|
+
yield time, record
|
78
|
+
elsif parsed_json.is_a?(Array)
|
79
|
+
parsed_json.each do |record|
|
80
|
+
unless record.is_a?(Hash)
|
81
|
+
yield nil, nil
|
82
|
+
next
|
83
|
+
end
|
84
|
+
time, parsed_record = parse_one_record(record)
|
85
|
+
yield time, parsed_record
|
86
|
+
end
|
87
|
+
else
|
88
|
+
yield nil, nil
|
77
89
|
end
|
78
|
-
|
90
|
+
|
79
91
|
rescue @error_class, EncodingError # EncodingError is for oj 3.x or later
|
80
92
|
yield nil, nil
|
81
93
|
end
|
82
94
|
|
95
|
+
def parse_one_record(record)
|
96
|
+
time = parse_time(record)
|
97
|
+
convert_values(time, record)
|
98
|
+
end
|
99
|
+
|
83
100
|
def parser_type
|
84
101
|
:text
|
85
102
|
end
|
@@ -31,9 +31,9 @@ module Fluent
|
|
31
31
|
:binary
|
32
32
|
end
|
33
33
|
|
34
|
-
def parse(data)
|
34
|
+
def parse(data, &block)
|
35
35
|
@unpacker.feed_each(data) do |obj|
|
36
|
-
|
36
|
+
parse_unpacked_data(obj, &block)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
alias parse_partial_data parse
|
@@ -41,8 +41,29 @@ module Fluent
|
|
41
41
|
def parse_io(io, &block)
|
42
42
|
u = Fluent::MessagePackFactory.engine_factory.unpacker(io)
|
43
43
|
u.each do |obj|
|
44
|
-
|
44
|
+
parse_unpacked_data(obj, &block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_unpacked_data(data)
|
49
|
+
if data.is_a?(Hash)
|
50
|
+
time, record = convert_values(parse_time(data), data)
|
45
51
|
yield time, record
|
52
|
+
return
|
53
|
+
end
|
54
|
+
|
55
|
+
unless data.is_a?(Array)
|
56
|
+
yield nil, nil
|
57
|
+
return
|
58
|
+
end
|
59
|
+
|
60
|
+
data.each do |record|
|
61
|
+
unless record.is_a?(Hash)
|
62
|
+
yield nil, nil
|
63
|
+
next
|
64
|
+
end
|
65
|
+
time, converted_record = convert_values(parse_time(record), record)
|
66
|
+
yield time, converted_record
|
46
67
|
end
|
47
68
|
end
|
48
69
|
end
|
@@ -65,9 +65,9 @@ module Fluent
|
|
65
65
|
metrics.configure(config)
|
66
66
|
# For multi workers environment, cmetrics should be distinguish with static labels.
|
67
67
|
if Fluent::Engine.system_config.workers > 1
|
68
|
-
labels
|
68
|
+
labels[:worker_id] = fluentd_worker_id.to_s
|
69
69
|
end
|
70
|
-
labels
|
70
|
+
labels[:plugin] = @plugin_type_or_id
|
71
71
|
metrics.create(namespace: namespace, subsystem: subsystem, name: name, help_text: help_text, labels: labels)
|
72
72
|
|
73
73
|
@_metrics["#{@plugin_type_or_id}_#{namespace}_#{subsystem}_#{name}"] = metrics
|
data/lib/fluent/registry.rb
CHANGED
@@ -60,13 +60,13 @@ module Fluent
|
|
60
60
|
# search from additional plugin directories
|
61
61
|
if @dir_search_prefix
|
62
62
|
path = "#{@dir_search_prefix}#{type}"
|
63
|
-
files = @paths.
|
63
|
+
files = @paths.filter_map { |lp|
|
64
64
|
lpath = File.expand_path(File.join(lp, "#{path}.rb"))
|
65
65
|
File.exist?(lpath) ? lpath : nil
|
66
|
-
}
|
66
|
+
}
|
67
67
|
unless files.empty?
|
68
68
|
# prefer newer version
|
69
|
-
require files.
|
69
|
+
require files.max
|
70
70
|
return
|
71
71
|
end
|
72
72
|
end
|
@@ -74,17 +74,17 @@ module Fluent
|
|
74
74
|
path = "#{@search_prefix}#{type}"
|
75
75
|
|
76
76
|
# prefer LOAD_PATH than gems
|
77
|
-
files = $LOAD_PATH.
|
77
|
+
files = $LOAD_PATH.filter_map { |lp|
|
78
78
|
if lp == FLUENT_LIB_PATH
|
79
79
|
nil
|
80
80
|
else
|
81
81
|
lpath = File.expand_path(File.join(lp, "#{path}.rb"))
|
82
82
|
File.exist?(lpath) ? lpath : nil
|
83
83
|
end
|
84
|
-
}
|
84
|
+
}
|
85
85
|
unless files.empty?
|
86
86
|
# prefer newer version
|
87
|
-
require files.
|
87
|
+
require files.max
|
88
88
|
return
|
89
89
|
end
|
90
90
|
|
data/lib/fluent/unique_id.rb
CHANGED
data/lib/fluent/version.rb
CHANGED
@@ -72,11 +72,18 @@ class ConsoleAdapterTest < Test::Unit::TestCase
|
|
72
72
|
fatal: :fatal)
|
73
73
|
def test_options(level)
|
74
74
|
@console_logger.send(level, "subject", kwarg1: "opt1", kwarg2: "opt2")
|
75
|
+
lines = @logdev.logs[0].split("\n")
|
76
|
+
args = JSON.load(lines[1..].collect { |str| str.sub(/\s+\|/, "") }.join("\n"));
|
75
77
|
assert_equal([
|
76
|
-
|
77
|
-
"
|
78
|
+
1,
|
79
|
+
"#{@timestamp_str} [#{level}]: 0.0s: subject",
|
80
|
+
{ "kwarg1" => "opt1", "kwarg2" => "opt2" }
|
78
81
|
],
|
79
|
-
|
82
|
+
[
|
83
|
+
@logdev.logs.size,
|
84
|
+
lines[0],
|
85
|
+
args
|
86
|
+
])
|
80
87
|
end
|
81
88
|
|
82
89
|
data(debug: :debug,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/test/plugin/test_in_http.rb
CHANGED
@@ -517,6 +517,28 @@ class HttpInputTest < Test::Unit::TestCase
|
|
517
517
|
assert_equal_event_time time, d.events[1][1]
|
518
518
|
end
|
519
519
|
|
520
|
+
def test_csp_report
|
521
|
+
d = create_driver
|
522
|
+
time = event_time("2011-01-02 13:14:15 UTC")
|
523
|
+
time_i = time.to_i
|
524
|
+
events = [
|
525
|
+
["tag1", time, {"a"=>1}],
|
526
|
+
["tag2", time, {"a"=>2}],
|
527
|
+
]
|
528
|
+
res_codes = []
|
529
|
+
|
530
|
+
d.run(expect_records: 2) do
|
531
|
+
events.each do |tag, t, record|
|
532
|
+
res = post("/#{tag}?time=#{time_i.to_s}", record.to_json, {"Content-Type"=>"application/csp-report; charset=utf-8"})
|
533
|
+
res_codes << res.code
|
534
|
+
end
|
535
|
+
end
|
536
|
+
assert_equal ["200", "200"], res_codes
|
537
|
+
assert_equal events, d.events
|
538
|
+
assert_equal_event_time time, d.events[0][1]
|
539
|
+
assert_equal_event_time time, d.events[1][1]
|
540
|
+
end
|
541
|
+
|
520
542
|
def test_application_msgpack
|
521
543
|
d = create_driver
|
522
544
|
time = event_time("2011-01-02 13:14:15 UTC")
|
@@ -982,7 +1004,7 @@ class HttpInputTest < Test::Unit::TestCase
|
|
982
1004
|
assert_equal ["403", "403"], res_codes
|
983
1005
|
end
|
984
1006
|
|
985
|
-
def test_add_query_params
|
1007
|
+
def test_add_query_params
|
986
1008
|
d = create_driver(config + "add_query_params true")
|
987
1009
|
assert_equal true, d.instance.add_query_params
|
988
1010
|
|
data/test/plugin/test_in_tail.rb
CHANGED
@@ -1538,6 +1538,147 @@ class TailInputTest < Test::Unit::TestCase
|
|
1538
1538
|
assert_equal(ex_paths - [ex_paths.last], plugin.expand_paths.values.sort_by { |path_ino| path_ino.path })
|
1539
1539
|
end
|
1540
1540
|
|
1541
|
+
sub_test_case "expand_paths with glob" do |data|
|
1542
|
+
sub_test_case "extended_glob" do
|
1543
|
+
data("curly braces" => [true, "always", "test/plugin/data/log_numeric/{0,1}*.log"],
|
1544
|
+
"square brackets" => [true, "always", "test/plugin/data/log_numeric/[0-1][2-4].log"],
|
1545
|
+
"asterisk" => [true, "always", "test/plugin/data/log/*.log"],
|
1546
|
+
"one character matcher" => [true, "always", "test/plugin/data/log/tes?.log"],
|
1547
|
+
)
|
1548
|
+
def test_expand_paths_with_use_glob_p_and_almost_set_of_patterns
|
1549
|
+
result, option, path = data
|
1550
|
+
config = config_element("", "", {
|
1551
|
+
"tag" => "tail",
|
1552
|
+
"path" => path,
|
1553
|
+
"format" => "none",
|
1554
|
+
"pos_file" => "#{@tmp_dir}/tail.pos",
|
1555
|
+
"read_from_head" => true,
|
1556
|
+
"refresh_interval" => 30,
|
1557
|
+
"glob_policy" => option,
|
1558
|
+
"path_delimiter" => "|",
|
1559
|
+
"rotate_wait" => "#{EX_ROTATE_WAIT}s",
|
1560
|
+
"follow_inodes" => "#{EX_FOLLOW_INODES}",
|
1561
|
+
})
|
1562
|
+
plugin = create_driver(config, false).instance
|
1563
|
+
assert_equal(result, !!plugin.use_glob?(path))
|
1564
|
+
end
|
1565
|
+
|
1566
|
+
data("curly braces" => [true, false, "extended", "test/plugin/data/log_numeric/{0,1}*.log"],
|
1567
|
+
"square brackets" => [false, true, "extended", "test/plugin/data/log_numeric/[0-1][2-4].log"],
|
1568
|
+
"asterisk" => [false, true, "extended", "test/plugin/data/log/*.log"],
|
1569
|
+
"one character matcher" => [false, true, "extended", "test/plugin/data/log/tes?.log"],
|
1570
|
+
)
|
1571
|
+
def test_expand_paths_with_use_glob_p
|
1572
|
+
emit_exception_p, result, option, path = data
|
1573
|
+
config = config_element("", "", {
|
1574
|
+
"tag" => "tail",
|
1575
|
+
"path" => path,
|
1576
|
+
"format" => "none",
|
1577
|
+
"pos_file" => "#{@tmp_dir}/tail.pos",
|
1578
|
+
"read_from_head" => true,
|
1579
|
+
"refresh_interval" => 30,
|
1580
|
+
"glob_policy" => option,
|
1581
|
+
"rotate_wait" => "#{EX_ROTATE_WAIT}s",
|
1582
|
+
"follow_inodes" => "#{EX_FOLLOW_INODES}",
|
1583
|
+
})
|
1584
|
+
if emit_exception_p
|
1585
|
+
assert_raise(Fluent::ConfigError) do
|
1586
|
+
plugin = create_driver(config, false).instance
|
1587
|
+
end
|
1588
|
+
else
|
1589
|
+
plugin = create_driver(config, false).instance
|
1590
|
+
assert_equal(result, !!plugin.use_glob?(path))
|
1591
|
+
end
|
1592
|
+
end
|
1593
|
+
end
|
1594
|
+
|
1595
|
+
sub_test_case "only_use_backward_compatible" do
|
1596
|
+
data("square brackets" => [false, "backward_compatible", "test/plugin/data/log_numeric/[0-1][2-4].log"],
|
1597
|
+
"asterisk" => [true, "backward_compatible", "test/plugin/data/log/*.log"],
|
1598
|
+
"one character matcher" => [false, "backward_compatible", "test/plugin/data/log/tes?.log"],
|
1599
|
+
)
|
1600
|
+
def test_expand_paths_with_use_glob_p
|
1601
|
+
result, option, path = data
|
1602
|
+
config = config_element("", "", {
|
1603
|
+
"tag" => "tail",
|
1604
|
+
"path" => path,
|
1605
|
+
"format" => "none",
|
1606
|
+
"pos_file" => "#{@tmp_dir}/tail.pos",
|
1607
|
+
"read_from_head" => true,
|
1608
|
+
"refresh_interval" => 30,
|
1609
|
+
"glob_policy" => option,
|
1610
|
+
"rotate_wait" => "#{EX_ROTATE_WAIT}s",
|
1611
|
+
"follow_inodes" => "#{EX_FOLLOW_INODES}",
|
1612
|
+
})
|
1613
|
+
plugin = create_driver(config, false).instance
|
1614
|
+
assert_equal(result, !!plugin.use_glob?(path))
|
1615
|
+
end
|
1616
|
+
end
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
def ex_config_with_brackets
|
1620
|
+
config_element("", "", {
|
1621
|
+
"tag" => "tail",
|
1622
|
+
"path" => "test/plugin/data/log_numeric/[0-1][2-4].log",
|
1623
|
+
"format" => "none",
|
1624
|
+
"pos_file" => "#{@tmp_dir}/tail.pos",
|
1625
|
+
"read_from_head" => true,
|
1626
|
+
"refresh_interval" => 30,
|
1627
|
+
"glob_policy" => "extended",
|
1628
|
+
"rotate_wait" => "#{EX_ROTATE_WAIT}s",
|
1629
|
+
"follow_inodes" => "#{EX_FOLLOW_INODES}",
|
1630
|
+
})
|
1631
|
+
end
|
1632
|
+
|
1633
|
+
def test_config_with_always_with_default_delimiter
|
1634
|
+
assert_raise(Fluent::ConfigError) do
|
1635
|
+
config = config_element("", "", {
|
1636
|
+
"tag" => "tail",
|
1637
|
+
"path" => "test/plugin/data/log_numeric/[0-1][2-4].log",
|
1638
|
+
"format" => "none",
|
1639
|
+
"pos_file" => "#{@tmp_dir}/tail.pos",
|
1640
|
+
"read_from_head" => true,
|
1641
|
+
"refresh_interval" => 30,
|
1642
|
+
"glob_policy" => "always",
|
1643
|
+
"rotate_wait" => "#{EX_ROTATE_WAIT}s",
|
1644
|
+
"follow_inodes" => "#{EX_FOLLOW_INODES}",
|
1645
|
+
})
|
1646
|
+
|
1647
|
+
create_driver(config, false).instance
|
1648
|
+
end
|
1649
|
+
end
|
1650
|
+
|
1651
|
+
def test_config_with_always_with_custom_delimiter
|
1652
|
+
assert_nothing_raised do
|
1653
|
+
config = config_element("", "", {
|
1654
|
+
"tag" => "tail",
|
1655
|
+
"path" => "test/plugin/data/log_numeric/[0-1][2-4].log",
|
1656
|
+
"format" => "none",
|
1657
|
+
"pos_file" => "#{@tmp_dir}/tail.pos",
|
1658
|
+
"read_from_head" => true,
|
1659
|
+
"refresh_interval" => 30,
|
1660
|
+
"glob_policy" => "always",
|
1661
|
+
"path_delimiter" => "|",
|
1662
|
+
"rotate_wait" => "#{EX_ROTATE_WAIT}s",
|
1663
|
+
"follow_inodes" => "#{EX_FOLLOW_INODES}",
|
1664
|
+
})
|
1665
|
+
|
1666
|
+
create_driver(config, false).instance
|
1667
|
+
end
|
1668
|
+
end
|
1669
|
+
|
1670
|
+
def test_expand_paths_with_brackets
|
1671
|
+
expanded_paths = [
|
1672
|
+
create_target_info('test/plugin/data/log_numeric/01.log'),
|
1673
|
+
create_target_info('test/plugin/data/log_numeric/02.log'),
|
1674
|
+
create_target_info('test/plugin/data/log_numeric/12.log'),
|
1675
|
+
create_target_info('test/plugin/data/log_numeric/14.log'),
|
1676
|
+
]
|
1677
|
+
|
1678
|
+
plugin = create_driver(ex_config_with_brackets, false).instance
|
1679
|
+
assert_equal(expanded_paths - [expanded_paths.first], plugin.expand_paths.values.sort_by { |path_ino| path_ino.path })
|
1680
|
+
end
|
1681
|
+
|
1541
1682
|
def test_expand_paths_with_duplicate_configuration
|
1542
1683
|
expanded_paths = [
|
1543
1684
|
create_target_info('test/plugin/data/log/foo/bar.log'),
|