fluentd 0.14.6 → 0.14.7
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 +46 -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 -4
- 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 +3 -2
- 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 +10 -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 +23 -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)
|
@@ -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.'
|
@@ -208,7 +208,7 @@ module Fluent::Plugin
|
|
208
208
|
line_buffer_timer_flusher = (@multiline_mode && @multiline_flush_interval) ? TailWatcher::LineBufferTimerFlusher.new(log, @multiline_flush_interval, &method(:flush_buffer)) : nil
|
209
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))
|
210
210
|
tw.attach do |watcher|
|
211
|
-
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
|
212
212
|
event_loop_attach(watcher.stat_trigger)
|
213
213
|
end
|
214
214
|
tw
|
@@ -248,6 +248,12 @@ module Fluent::Plugin
|
|
248
248
|
|
249
249
|
# refresh_watchers calls @tails.keys so we don't use stop_watcher -> start_watcher sequence for safety.
|
250
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
|
251
257
|
rotated_tw = @tails[path]
|
252
258
|
@tails[path] = setup_watcher(path, pe)
|
253
259
|
close_watcher_after_rotate_wait(rotated_tw) if rotated_tw
|
@@ -398,6 +404,7 @@ module Fluent::Plugin
|
|
398
404
|
@update_watcher = update_watcher
|
399
405
|
|
400
406
|
@stat_trigger = StatWatcher.new(path, log, &method(:on_notify))
|
407
|
+
@timer_trigger = nil
|
401
408
|
|
402
409
|
@rotate_handler = RotateHandler.new(path, log, &method(:on_rotate))
|
403
410
|
@io_handler = nil
|
@@ -421,11 +428,12 @@ module Fluent::Plugin
|
|
421
428
|
end
|
422
429
|
|
423
430
|
def attach
|
424
|
-
yield self
|
425
431
|
on_notify
|
432
|
+
yield self
|
426
433
|
end
|
427
434
|
|
428
435
|
def detach
|
436
|
+
@timer_trigger.detach if @enable_watch_timer && @timer_trigger.attached?
|
429
437
|
@stat_trigger.detach if @stat_trigger.attached?
|
430
438
|
end
|
431
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
|
@@ -80,6 +80,9 @@ module Fluent
|
|
80
80
|
desc 'Enable client-side DNS round robin.'
|
81
81
|
config_param :dns_round_robin, :bool, default: false # heartbeat_type 'udp' is not available for this
|
82
82
|
|
83
|
+
desc 'Compress buffered data.'
|
84
|
+
config_param :compress, :enum, list: [:text, :gzip], default: :text
|
85
|
+
|
83
86
|
config_section :security, required: false, multi: false do
|
84
87
|
desc 'The hostname'
|
85
88
|
config_param :self_hostname, :string
|
@@ -137,6 +140,12 @@ module Fluent
|
|
137
140
|
end
|
138
141
|
end
|
139
142
|
|
143
|
+
if @compress == :gzip && @buffer.compress == :text
|
144
|
+
@buffer.compress = :gzip
|
145
|
+
elsif @compress == :text && @buffer.compress == :gzip
|
146
|
+
log.info "buffer is compressed. If you also want to save the bandwidth of a network, Add `compress` configuration in <match>"
|
147
|
+
end
|
148
|
+
|
140
149
|
if @nodes.empty?
|
141
150
|
raise ConfigError, "forward output plugin requires at least one <server> is required"
|
142
151
|
end
|
@@ -331,6 +340,7 @@ module Fluent
|
|
331
340
|
def initialize(sender, server, failure:)
|
332
341
|
@sender = sender
|
333
342
|
@log = sender.log
|
343
|
+
@compress = sender.compress
|
334
344
|
|
335
345
|
@name = server.name
|
336
346
|
@host = server.host
|
@@ -432,7 +442,7 @@ module Fluent
|
|
432
442
|
raise ForwardOutputConnectionClosedError, "failed to establish connection with node #{@name}"
|
433
443
|
end
|
434
444
|
|
435
|
-
option = { 'size' => chunk.size_of_events }
|
445
|
+
option = { 'size' => chunk.size_of_events, 'compressed' => @compress }
|
436
446
|
option['chunk'] = Base64.encode64(chunk.unique_id) if @sender.require_ack_response
|
437
447
|
|
438
448
|
# out_forward always uses Raw32 type for content.
|
@@ -440,13 +450,15 @@ module Fluent
|
|
440
450
|
|
441
451
|
sock.write @sender.forward_header # beginArray(3)
|
442
452
|
sock.write tag.to_msgpack # 1. writeRaw(tag)
|
443
|
-
|
444
|
-
|
453
|
+
chunk.open(compressed: @compress) do |chunk_io|
|
454
|
+
sock.write [0xdb, chunk_io.size].pack('CN') # 2. beginRaw(size) raw32
|
455
|
+
IO.copy_stream(chunk_io, sock) # writeRawBody(packed_es)
|
456
|
+
end
|
445
457
|
sock.write option.to_msgpack # 3. writeOption(option)
|
446
458
|
|
447
459
|
if @sender.require_ack_response
|
448
460
|
# Waiting for a response here results in a decrease of throughput because a chunk queue is locked.
|
449
|
-
# To avoid a decrease of
|
461
|
+
# To avoid a decrease of throughput, it is necessary to prepare a list of chunks that wait for responses
|
450
462
|
# and process them asynchronously.
|
451
463
|
if IO.select([sock], nil, nil, @sender.ack_response_timeout)
|
452
464
|
raw_data = begin
|
@@ -510,7 +522,7 @@ module Fluent
|
|
510
522
|
sock.close
|
511
523
|
end
|
512
524
|
when :udp
|
513
|
-
@usock.send "\0", 0, Socket.pack_sockaddr_in(
|
525
|
+
@usock.send "\0", 0, Socket.pack_sockaddr_in(@port, resolved_host)
|
514
526
|
when :none # :none doesn't use this class
|
515
527
|
raise "BUG: heartbeat_type none must not use Node"
|
516
528
|
else
|