fluentd 0.14.5-x64-mingw32 → 0.14.7-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/ChangeLog +55 -0
- data/bin/fluent-binlog-reader +7 -0
- data/example/in_dummy_with_compression.conf +23 -0
- data/lib/fluent/agent.rb +8 -12
- data/lib/fluent/command/binlog_reader.rb +234 -0
- data/lib/fluent/command/fluentd.rb +17 -1
- data/lib/fluent/compat/file_util.rb +1 -1
- data/lib/fluent/compat/output.rb +5 -1
- data/lib/fluent/config/configure_proxy.rb +18 -3
- data/lib/fluent/config/element.rb +1 -1
- data/lib/fluent/config/section.rb +1 -1
- data/lib/fluent/config/v1_parser.rb +1 -1
- data/lib/fluent/env.rb +1 -0
- data/lib/fluent/event.rb +49 -2
- data/lib/fluent/event_router.rb +6 -2
- data/lib/fluent/label.rb +8 -0
- data/lib/fluent/log.rb +30 -1
- data/lib/fluent/plugin.rb +1 -1
- data/lib/fluent/plugin/base.rb +3 -0
- data/lib/fluent/plugin/buf_file.rb +2 -2
- data/lib/fluent/plugin/buf_memory.rb +1 -1
- data/lib/fluent/plugin/buffer.rb +12 -2
- data/lib/fluent/plugin/buffer/chunk.rb +68 -7
- data/lib/fluent/plugin/buffer/file_chunk.rb +4 -4
- data/lib/fluent/plugin/buffer/memory_chunk.rb +4 -4
- data/lib/fluent/plugin/compressable.rb +91 -0
- data/lib/fluent/plugin/filter_grep.rb +4 -4
- data/lib/fluent/plugin/formatter.rb +2 -2
- data/lib/fluent/plugin/formatter_json.rb +2 -1
- data/lib/fluent/plugin/formatter_out_file.rb +3 -30
- data/lib/fluent/plugin/in_forward.rb +6 -5
- data/lib/fluent/plugin/in_monitor_agent.rb +7 -21
- data/lib/fluent/plugin/in_syslog.rb +1 -1
- data/lib/fluent/plugin/in_tail.rb +11 -2
- data/lib/fluent/plugin/multi_output.rb +63 -3
- data/lib/fluent/plugin/out_exec.rb +1 -1
- data/lib/fluent/plugin/out_file.rb +5 -1
- data/lib/fluent/plugin/out_forward.rb +17 -5
- data/lib/fluent/plugin/out_stdout.rb +2 -1
- data/lib/fluent/plugin/output.rb +205 -19
- data/lib/fluent/plugin/parser.rb +5 -49
- data/lib/fluent/plugin/parser_apache2.rb +1 -1
- data/lib/fluent/plugin/parser_json.rb +4 -4
- data/lib/fluent/plugin/parser_multiline.rb +5 -5
- data/lib/fluent/plugin/parser_regexp.rb +1 -2
- data/lib/fluent/plugin/parser_syslog.rb +2 -2
- data/lib/fluent/plugin/storage_local.rb +2 -1
- data/lib/fluent/plugin_helper.rb +1 -0
- data/lib/fluent/plugin_helper/compat_parameters.rb +39 -21
- data/lib/fluent/plugin_helper/extract.rb +92 -0
- data/lib/fluent/plugin_helper/inject.rb +10 -12
- data/lib/fluent/plugin_helper/thread.rb +23 -3
- data/lib/fluent/registry.rb +1 -1
- data/lib/fluent/root_agent.rb +2 -1
- data/lib/fluent/supervisor.rb +28 -8
- data/lib/fluent/test/base.rb +0 -7
- data/lib/fluent/test/driver/base.rb +1 -0
- data/lib/fluent/test/driver/output.rb +3 -0
- data/lib/fluent/test/helpers.rb +18 -0
- data/lib/fluent/test/input_test.rb +4 -2
- data/lib/fluent/test/log.rb +3 -1
- data/lib/fluent/time.rb +232 -1
- data/lib/fluent/timezone.rb +1 -1
- data/lib/fluent/version.rb +1 -1
- data/test/command/test_binlog_reader.rb +351 -0
- data/test/config/test_config_parser.rb +6 -0
- data/test/config/test_configurable.rb +47 -1
- data/test/helper.rb +0 -1
- data/test/plugin/test_buffer.rb +22 -2
- data/test/plugin/test_buffer_chunk.rb +34 -4
- data/test/plugin/test_buffer_file_chunk.rb +73 -0
- data/test/plugin/test_buffer_memory_chunk.rb +73 -0
- data/test/plugin/test_compressable.rb +81 -0
- data/test/plugin/test_formatter_json.rb +14 -1
- data/test/plugin/test_in_forward.rb +67 -3
- data/test/plugin/test_in_monitor_agent.rb +17 -1
- data/test/plugin/test_in_tail.rb +8 -8
- data/test/plugin/test_out_file.rb +0 -8
- data/test/plugin/test_out_forward.rb +85 -0
- data/test/plugin/test_out_secondary_file.rb +20 -12
- data/test/plugin/test_out_stdout.rb +11 -10
- data/test/plugin/test_output.rb +234 -0
- data/test/plugin/test_output_as_buffered.rb +223 -0
- data/test/plugin/test_output_as_buffered_compress.rb +165 -0
- data/test/plugin/test_parser_json.rb +8 -0
- data/test/plugin/test_parser_regexp.rb +1 -1
- data/test/plugin_helper/test_child_process.rb +2 -2
- data/test/plugin_helper/test_extract.rb +195 -0
- data/test/plugin_helper/test_inject.rb +0 -7
- data/test/scripts/fluent/plugin/formatter1/formatter_test1.rb +7 -0
- data/test/scripts/fluent/plugin/formatter2/formatter_test2.rb +7 -0
- data/test/test_event.rb +186 -0
- data/test/test_event_router.rb +1 -1
- data/test/test_formatter.rb +0 -7
- data/test/test_log.rb +121 -0
- data/test/test_plugin_classes.rb +62 -0
- data/test/test_root_agent.rb +125 -0
- data/test/test_supervisor.rb +25 -2
- data/test/test_time_formatter.rb +103 -7
- data/test/test_time_parser.rb +211 -0
- metadata +22 -4
- data/test/plugin/test_parser_time.rb +0 -46
@@ -0,0 +1,91 @@
|
|
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 'zlib'
|
18
|
+
|
19
|
+
module Fluent
|
20
|
+
module Plugin
|
21
|
+
module Compressable
|
22
|
+
def compress(data, **kwargs)
|
23
|
+
output_io = kwargs[:output_io]
|
24
|
+
io = output_io || StringIO.new
|
25
|
+
Zlib::GzipWriter.wrap(io) do |gz|
|
26
|
+
gz.write data
|
27
|
+
end
|
28
|
+
|
29
|
+
output_io || io.string
|
30
|
+
end
|
31
|
+
|
32
|
+
# compressed_data is String like `compress(data1) + compress(data2) + ... + compress(dataN)`
|
33
|
+
# https://www.ruby-forum.com/topic/971591#979503
|
34
|
+
def decompress(compressed_data = nil, output_io: nil, input_io: nil)
|
35
|
+
case
|
36
|
+
when input_io && output_io
|
37
|
+
io_decompress(input_io, output_io)
|
38
|
+
when input_io
|
39
|
+
output_io = StringIO.new
|
40
|
+
io = io_decompress(input_io, output_io)
|
41
|
+
io.string
|
42
|
+
when compressed_data.nil? || compressed_data.empty?
|
43
|
+
# check compressed_data(String) is 0 length
|
44
|
+
compressed_data
|
45
|
+
when output_io
|
46
|
+
# exeucte after checking compressed_data is empty or not
|
47
|
+
io = StringIO.new(compressed_data)
|
48
|
+
io_decompress(io, output_io)
|
49
|
+
else
|
50
|
+
string_decompress(compressed_data)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def string_decompress(compressed_data)
|
57
|
+
io = StringIO.new(compressed_data)
|
58
|
+
|
59
|
+
out = ''
|
60
|
+
loop do
|
61
|
+
gz = Zlib::GzipReader.new(io)
|
62
|
+
out += gz.read
|
63
|
+
unused = gz.unused
|
64
|
+
gz.finish
|
65
|
+
|
66
|
+
break if unused.nil?
|
67
|
+
adjust = unused.length
|
68
|
+
io.pos -= adjust
|
69
|
+
end
|
70
|
+
|
71
|
+
out
|
72
|
+
end
|
73
|
+
|
74
|
+
def io_decompress(input, output)
|
75
|
+
loop do
|
76
|
+
gz = Zlib::GzipReader.new(input)
|
77
|
+
v = gz.read
|
78
|
+
output.write(v)
|
79
|
+
unused = gz.unused
|
80
|
+
gz.finish
|
81
|
+
|
82
|
+
break if unused.nil?
|
83
|
+
adjust = unused.length
|
84
|
+
input.pos -= adjust
|
85
|
+
end
|
86
|
+
|
87
|
+
output
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -38,8 +38,8 @@ module Fluent::Plugin
|
|
38
38
|
(1..REGEXP_MAX_NUM).each do |i|
|
39
39
|
next unless conf["regexp#{i}"]
|
40
40
|
key, regexp = conf["regexp#{i}"].split(/ /, 2)
|
41
|
-
raise ConfigError, "regexp#{i} does not contain 2 parameters" unless regexp
|
42
|
-
raise ConfigError, "regexp#{i} contains a duplicated key, #{key}" if @regexps[key]
|
41
|
+
raise Fluent::ConfigError, "regexp#{i} does not contain 2 parameters" unless regexp
|
42
|
+
raise Fluent::ConfigError, "regexp#{i} contains a duplicated key, #{key}" if @regexps[key]
|
43
43
|
@regexps[key] = Regexp.compile(regexp)
|
44
44
|
end
|
45
45
|
|
@@ -47,8 +47,8 @@ module Fluent::Plugin
|
|
47
47
|
(1..REGEXP_MAX_NUM).each do |i|
|
48
48
|
next unless conf["exclude#{i}"]
|
49
49
|
key, exclude = conf["exclude#{i}"].split(/ /, 2)
|
50
|
-
raise ConfigError, "exclude#{i} does not contain 2 parameters" unless exclude
|
51
|
-
raise ConfigError, "exclude#{i} contains a duplicated key, #{key}" if @excludes[key]
|
50
|
+
raise Fluent::ConfigError, "exclude#{i} does not contain 2 parameters" unless exclude
|
51
|
+
raise Fluent::ConfigError, "exclude#{i} contains a duplicated key, #{key}" if @excludes[key]
|
52
52
|
@excludes[key] = Regexp.compile(exclude)
|
53
53
|
end
|
54
54
|
end
|
@@ -16,13 +16,13 @@
|
|
16
16
|
|
17
17
|
require 'fluent/plugin/base'
|
18
18
|
require 'fluent/plugin/owned_by_mixin'
|
19
|
-
|
20
|
-
require 'fluent/mixin' # for TimeFormatter
|
19
|
+
require 'fluent/time'
|
21
20
|
|
22
21
|
module Fluent
|
23
22
|
module Plugin
|
24
23
|
class Formatter < Base
|
25
24
|
include OwnedByMixin
|
25
|
+
include TimeMixin::Formatter
|
26
26
|
|
27
27
|
configured_in :format
|
28
28
|
|
@@ -15,6 +15,7 @@
|
|
15
15
|
#
|
16
16
|
|
17
17
|
require 'fluent/plugin/formatter'
|
18
|
+
require 'fluent/env'
|
18
19
|
|
19
20
|
module Fluent
|
20
21
|
module Plugin
|
@@ -29,7 +30,7 @@ module Fluent
|
|
29
30
|
begin
|
30
31
|
raise LoadError unless @json_parser == 'oj'
|
31
32
|
require 'oj'
|
32
|
-
Oj.default_options =
|
33
|
+
Oj.default_options = Fluent::DEFAULT_OJ_OPTIONS
|
33
34
|
@dump_proc = Oj.method(:dump)
|
34
35
|
rescue LoadError
|
35
36
|
@dump_proc = Yajl.method(:dump)
|
@@ -32,39 +32,12 @@ module Fluent
|
|
32
32
|
else "\t"
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
|
37
|
-
config_param :localtime, :bool, default: true # if localtime is false and timezone is nil, then utc
|
38
|
-
config_param :timezone, :string, default: nil
|
35
|
+
config_set_default :time_type, :string
|
36
|
+
config_set_default :time_format, nil # time_format nil => iso8601
|
39
37
|
|
40
38
|
def configure(conf)
|
41
|
-
# TODO: make a utility method in TimeFormatter to handle these conversion
|
42
|
-
# copies of this code: plugin_helper/compat_parameters, compat/formatter_utils and here
|
43
|
-
if conf.has_key?('time_as_epoch') && Fluent::Config.bool_value(conf['time_as_epoch'])
|
44
|
-
conf['time_type'] = 'unixtime'
|
45
|
-
end
|
46
|
-
if conf.has_key?('localtime') || conf.has_key?('utc')
|
47
|
-
if conf.has_key?('localtime') && conf.has_key?('utc')
|
48
|
-
raise Fluent::ConfigError, "both of utc and localtime are specified, use only one of them"
|
49
|
-
elsif conf.has_key?('localtime')
|
50
|
-
conf['localtime'] = Fluent::Config.bool_value(conf['localtime'])
|
51
|
-
elsif conf.has_key?('utc')
|
52
|
-
conf['localtime'] = !(Fluent::Config.bool_value(conf['utc']))
|
53
|
-
# Specifying "localtime false" means using UTC in TimeFormatter
|
54
|
-
# And specifying "utc" is different from specifying "timezone +0000"(it's not always UTC).
|
55
|
-
# There are difference between "Z" and "+0000" in timezone formatting.
|
56
|
-
# TODO: add kwargs to TimeFormatter to specify "using localtime", "using UTC" or "using specified timezone" in more explicit way
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
39
|
super
|
61
|
-
|
62
|
-
@timef = case @time_type
|
63
|
-
when :float then ->(time){ time.to_r.to_f }
|
64
|
-
when :unixtime then ->(time){ time.to_i }
|
65
|
-
else
|
66
|
-
Fluent::TimeFormatter.new(@time_format, @localtime, @timezone)
|
67
|
-
end
|
40
|
+
@timef = time_formatter_create
|
68
41
|
end
|
69
42
|
|
70
43
|
def format(tag, time, record)
|
@@ -58,7 +58,7 @@ module Fluent
|
|
58
58
|
desc 'The hostname'
|
59
59
|
config_param :self_hostname, :string
|
60
60
|
desc 'Shared key for authentication'
|
61
|
-
config_param :shared_key, :string
|
61
|
+
config_param :shared_key, :string, secret: true
|
62
62
|
desc 'If true, use user based authentication'
|
63
63
|
config_param :user_auth, :bool, default: false
|
64
64
|
desc 'Allow anonymous source. <client> sections required if disabled.'
|
@@ -69,7 +69,7 @@ module Fluent
|
|
69
69
|
desc 'The username for authentication'
|
70
70
|
config_param :username, :string
|
71
71
|
desc 'The password for authentication'
|
72
|
-
config_param :password, :string
|
72
|
+
config_param :password, :string, secret: true
|
73
73
|
end
|
74
74
|
|
75
75
|
### Client ip/network authentication & per_host shared key
|
@@ -79,7 +79,7 @@ module Fluent
|
|
79
79
|
desc 'Network address specification'
|
80
80
|
config_param :network, :string, default: nil
|
81
81
|
desc 'Shared key per client'
|
82
|
-
config_param :shared_key, :string, default: nil
|
82
|
+
config_param :shared_key, :string, default: nil, secret: true
|
83
83
|
desc 'Array of username.'
|
84
84
|
config_param :users, :array, default: []
|
85
85
|
end
|
@@ -153,7 +153,7 @@ module Fluent
|
|
153
153
|
# In test cases it occasionally appeared that when detaching a watcher, another watcher is also detached.
|
154
154
|
# In the case in the iteration of watchers, a watcher that has been already detached is intended to be detached
|
155
155
|
# and therfore RuntimeError occurs saying that it is not attached to a loop.
|
156
|
-
# It
|
156
|
+
# It occurs only when testing for sending responses to ForwardOutput.
|
157
157
|
# Sending responses needs to write the socket that is previously used only to read
|
158
158
|
# and a handler has 2 watchers that is used to read and to write.
|
159
159
|
# This problem occurs possibly because those watchers are thought to be related to each other
|
@@ -338,7 +338,8 @@ module Fluent
|
|
338
338
|
# PackedForward
|
339
339
|
option = msg[2]
|
340
340
|
size = (option && option['size']) || 0
|
341
|
-
|
341
|
+
es_class = (option && option['compressed'] == 'gzip') ? CompressedMessagePackEventStream : MessagePackEventStream
|
342
|
+
es = es_class.new(entries, nil, size.to_i)
|
342
343
|
es = check_and_skip_invalid_event(tag, es, peeraddr) if @skip_invalid_event
|
343
344
|
es = add_source_host(es, peeraddr[2]) if @source_hostname_key
|
344
345
|
router.emit_stream(tag, es)
|
@@ -262,34 +262,20 @@ module Fluent::Plugin
|
|
262
262
|
array.concat Fluent::Engine.root_agent.inputs
|
263
263
|
|
264
264
|
# get all output plugins
|
265
|
-
Fluent::Engine.root_agent.outputs
|
266
|
-
|
267
|
-
}
|
265
|
+
array.concat Fluent::Engine.root_agent.outputs
|
266
|
+
|
268
267
|
# get all filter plugins
|
269
|
-
Fluent::Engine.root_agent.filters
|
270
|
-
|
271
|
-
}
|
268
|
+
array.concat Fluent::Engine.root_agent.filters
|
269
|
+
|
272
270
|
Fluent::Engine.root_agent.labels.each { |name, l|
|
273
271
|
# TODO: Add label name to outputs / filters for identifing plugins
|
274
|
-
l.outputs
|
275
|
-
l.filters
|
272
|
+
array.concat l.outputs
|
273
|
+
array.concat l.filters
|
276
274
|
}
|
277
275
|
|
278
276
|
array
|
279
277
|
end
|
280
278
|
|
281
|
-
# get nexted plugins (such as <store> of the copy plugin)
|
282
|
-
# from the plugin `pe` recursively
|
283
|
-
def self.collect_children(pe, array=[])
|
284
|
-
array << pe
|
285
|
-
if pe.is_a?(Fluent::Plugin::MultiOutput) || pe.is_a?(Fluent::MultiOutput) && pe.respond_to?(:outputs)
|
286
|
-
pe.outputs.each {|nop|
|
287
|
-
collect_children(nop, array)
|
288
|
-
}
|
289
|
-
end
|
290
|
-
array
|
291
|
-
end
|
292
|
-
|
293
279
|
# try to match the tag and get the info from the matched output plugin
|
294
280
|
# TODO: Support output in label
|
295
281
|
def plugin_info_by_tag(tag, opts={})
|
@@ -376,7 +362,7 @@ module Fluent::Plugin
|
|
376
362
|
case pe
|
377
363
|
when Fluent::Plugin::Input
|
378
364
|
'input'.freeze
|
379
|
-
when Fluent::Plugin::Output, Fluent::Plugin::BareOutput
|
365
|
+
when Fluent::Plugin::Output, Fluent::Plugin::MultiOutput, Fluent::Plugin::BareOutput
|
380
366
|
'output'.freeze
|
381
367
|
when Fluent::Plugin::Filter
|
382
368
|
'filter'.freeze
|
@@ -86,7 +86,7 @@ module Fluent::Plugin
|
|
86
86
|
when 'udp'
|
87
87
|
:udp
|
88
88
|
else
|
89
|
-
raise ConfigError, "syslog input protocol type should be 'tcp' or 'udp'"
|
89
|
+
raise Fluent::ConfigError, "syslog input protocol type should be 'tcp' or 'udp'"
|
90
90
|
end
|
91
91
|
end
|
92
92
|
desc 'If true, add source host to event record.'
|
@@ -20,6 +20,7 @@ require 'fluent/plugin/input'
|
|
20
20
|
require 'fluent/config/error'
|
21
21
|
require 'fluent/event'
|
22
22
|
require 'fluent/plugin/buffer'
|
23
|
+
require 'fluent/plugin/parser_multiline'
|
23
24
|
|
24
25
|
if Fluent.windows?
|
25
26
|
require_relative 'file_wrapper'
|
@@ -207,7 +208,7 @@ module Fluent::Plugin
|
|
207
208
|
line_buffer_timer_flusher = (@multiline_mode && @multiline_flush_interval) ? TailWatcher::LineBufferTimerFlusher.new(log, @multiline_flush_interval, &method(:flush_buffer)) : nil
|
208
209
|
tw = TailWatcher.new(path, @rotate_wait, pe, log, @read_from_head, @enable_watch_timer, @read_lines_limit, method(:update_watcher), line_buffer_timer_flusher, &method(:receive_lines))
|
209
210
|
tw.attach do |watcher|
|
210
|
-
timer_execute(:in_tail_timer_trigger, 1, &watcher.method(:on_notify)) if watcher.enable_watch_timer
|
211
|
+
watcher.timer_trigger = timer_execute(:in_tail_timer_trigger, 1, &watcher.method(:on_notify)) if watcher.enable_watch_timer
|
211
212
|
event_loop_attach(watcher.stat_trigger)
|
212
213
|
end
|
213
214
|
tw
|
@@ -247,6 +248,12 @@ module Fluent::Plugin
|
|
247
248
|
|
248
249
|
# refresh_watchers calls @tails.keys so we don't use stop_watcher -> start_watcher sequence for safety.
|
249
250
|
def update_watcher(path, pe)
|
251
|
+
if @pf
|
252
|
+
unless pe.read_inode == @pf[path].read_inode
|
253
|
+
log.trace "Skip update_watcher because watcher has been already updated by other inotify event"
|
254
|
+
return
|
255
|
+
end
|
256
|
+
end
|
250
257
|
rotated_tw = @tails[path]
|
251
258
|
@tails[path] = setup_watcher(path, pe)
|
252
259
|
close_watcher_after_rotate_wait(rotated_tw) if rotated_tw
|
@@ -397,6 +404,7 @@ module Fluent::Plugin
|
|
397
404
|
@update_watcher = update_watcher
|
398
405
|
|
399
406
|
@stat_trigger = StatWatcher.new(path, log, &method(:on_notify))
|
407
|
+
@timer_trigger = nil
|
400
408
|
|
401
409
|
@rotate_handler = RotateHandler.new(path, log, &method(:on_rotate))
|
402
410
|
@io_handler = nil
|
@@ -420,11 +428,12 @@ module Fluent::Plugin
|
|
420
428
|
end
|
421
429
|
|
422
430
|
def attach
|
423
|
-
yield self
|
424
431
|
on_notify
|
432
|
+
yield self
|
425
433
|
end
|
426
434
|
|
427
435
|
def detach
|
436
|
+
@timer_trigger.detach if @enable_watch_timer && @timer_trigger.attached?
|
428
437
|
@stat_trigger.detach if @stat_trigger.attached?
|
429
438
|
end
|
430
439
|
|
@@ -32,7 +32,7 @@ module Fluent
|
|
32
32
|
config_param :@type, :string, default: nil
|
33
33
|
end
|
34
34
|
|
35
|
-
attr_reader :outputs
|
35
|
+
attr_reader :outputs, :outputs_statically_created
|
36
36
|
|
37
37
|
def process(tag, es)
|
38
38
|
raise NotImplementedError, "BUG: output plugins MUST implement this method"
|
@@ -41,8 +41,7 @@ module Fluent
|
|
41
41
|
def initialize
|
42
42
|
super
|
43
43
|
@outputs = []
|
44
|
-
|
45
|
-
@compat = false
|
44
|
+
@outputs_statically_created = false
|
46
45
|
|
47
46
|
@counters_monitor = Monitor.new
|
48
47
|
# TODO: well organized counters
|
@@ -78,11 +77,72 @@ module Fluent
|
|
78
77
|
end
|
79
78
|
end
|
80
79
|
|
80
|
+
def static_outputs
|
81
|
+
@outputs_statically_created = true
|
82
|
+
@outputs
|
83
|
+
end
|
84
|
+
|
81
85
|
# Child plugin's lifecycles are controlled by agent automatically.
|
82
86
|
# It calls `outputs` to traverse plugins, and invoke start/stop/*shutdown/close/terminate on these directly.
|
83
87
|
# * `start` of this plugin will be called after child plugins
|
84
88
|
# * `stop`, `*shutdown`, `close` and `terminate` of this plugin will be called before child plugins
|
85
89
|
|
90
|
+
# But when MultiOutput plugins are created dynamically (by forest plugin or others), agent cannot find
|
91
|
+
# sub-plugins. So child plugins' lifecycles MUST be controlled by MultiOutput plugin itself.
|
92
|
+
# TODO: this hack will be removed at v2.
|
93
|
+
def call_lifecycle_method(method_name, checker_name)
|
94
|
+
return if @outputs_statically_created
|
95
|
+
@outputs.each do |o|
|
96
|
+
begin
|
97
|
+
log.debug "calling #{method_name} on output plugin dynamically created", type: Fluent::Plugin.lookup_type_from_class(o.class), plugin_id: o.plugin_id
|
98
|
+
o.send(method_name) unless o.send(checker_name)
|
99
|
+
rescue Exception => e
|
100
|
+
log.warn "unexpected error while calling #{method_name} on output plugin dynamically created", plugin: o.class, plugin_id: o.plugin_id, error: e
|
101
|
+
log.warn_backtrace
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def start
|
107
|
+
super
|
108
|
+
call_lifecycle_method(:start, :started?)
|
109
|
+
end
|
110
|
+
|
111
|
+
def after_start
|
112
|
+
super
|
113
|
+
call_lifecycle_method(:after_start, :after_started?)
|
114
|
+
end
|
115
|
+
|
116
|
+
def stop
|
117
|
+
super
|
118
|
+
call_lifecycle_method(:stop, :stopped?)
|
119
|
+
end
|
120
|
+
|
121
|
+
def before_shutdown
|
122
|
+
super
|
123
|
+
call_lifecycle_method(:before_shutdown, :before_shutdown?)
|
124
|
+
end
|
125
|
+
|
126
|
+
def shutdown
|
127
|
+
super
|
128
|
+
call_lifecycle_method(:shutdown, :shutdown?)
|
129
|
+
end
|
130
|
+
|
131
|
+
def after_shutdown
|
132
|
+
super
|
133
|
+
call_lifecycle_method(:after_shutdown, :after_shutdown?)
|
134
|
+
end
|
135
|
+
|
136
|
+
def close
|
137
|
+
super
|
138
|
+
call_lifecycle_method(:close, :closed?)
|
139
|
+
end
|
140
|
+
|
141
|
+
def terminate
|
142
|
+
super
|
143
|
+
call_lifecycle_method(:terminate, :terminated?)
|
144
|
+
end
|
145
|
+
|
86
146
|
def emit_sync(tag, es)
|
87
147
|
@counters_monitor.synchronize{ @emit_count += 1 }
|
88
148
|
begin
|
@@ -42,7 +42,7 @@ module Fluent::Plugin
|
|
42
42
|
desc "The format used to map the incoming events to the program input. (#{Fluent::ExecUtil::SUPPORTED_FORMAT.keys.join(',')})"
|
43
43
|
config_param :format, default: :tsv, skip_accessor: true do |val|
|
44
44
|
f = Fluent::ExecUtil::SUPPORTED_FORMAT[val]
|
45
|
-
raise ConfigError, "Unsupported format '#{val}'" unless f
|
45
|
+
raise Fluent::ConfigError, "Unsupported format '#{val}'" unless f
|
46
46
|
f
|
47
47
|
end
|
48
48
|
config_param :localtime, :bool, default: false
|
@@ -59,7 +59,11 @@ module Fluent
|
|
59
59
|
|
60
60
|
def generate_chunk(metadata)
|
61
61
|
chunk = super
|
62
|
-
|
62
|
+
# "symlink" feature is to link from symlink_path to the latest file chunk. Records with latest
|
63
|
+
# timekey will be appended into that file chunk. On the other side, resumed file chunks might NOT
|
64
|
+
# have timekey, especially in the cases that resumed file chunks are generated by Fluentd v0.12.
|
65
|
+
# These chunks will be enqueued immediately, and will be flushed soon.
|
66
|
+
latest_chunk = metadata_list.select{|m| m.timekey }.sort_by(&:timekey).last
|
63
67
|
if chunk.metadata == latest_chunk
|
64
68
|
FileUtils.ln_sf(chunk.path, @_symlink_path)
|
65
69
|
end
|