fluentd 0.14.5-x86-mingw32 → 0.14.7-x86-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.

Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +55 -0
  3. data/bin/fluent-binlog-reader +7 -0
  4. data/example/in_dummy_with_compression.conf +23 -0
  5. data/lib/fluent/agent.rb +8 -12
  6. data/lib/fluent/command/binlog_reader.rb +234 -0
  7. data/lib/fluent/command/fluentd.rb +17 -1
  8. data/lib/fluent/compat/file_util.rb +1 -1
  9. data/lib/fluent/compat/output.rb +5 -1
  10. data/lib/fluent/config/configure_proxy.rb +18 -3
  11. data/lib/fluent/config/element.rb +1 -1
  12. data/lib/fluent/config/section.rb +1 -1
  13. data/lib/fluent/config/v1_parser.rb +1 -1
  14. data/lib/fluent/env.rb +1 -0
  15. data/lib/fluent/event.rb +49 -2
  16. data/lib/fluent/event_router.rb +6 -2
  17. data/lib/fluent/label.rb +8 -0
  18. data/lib/fluent/log.rb +30 -1
  19. data/lib/fluent/plugin.rb +1 -1
  20. data/lib/fluent/plugin/base.rb +3 -0
  21. data/lib/fluent/plugin/buf_file.rb +2 -2
  22. data/lib/fluent/plugin/buf_memory.rb +1 -1
  23. data/lib/fluent/plugin/buffer.rb +12 -2
  24. data/lib/fluent/plugin/buffer/chunk.rb +68 -7
  25. data/lib/fluent/plugin/buffer/file_chunk.rb +4 -4
  26. data/lib/fluent/plugin/buffer/memory_chunk.rb +4 -4
  27. data/lib/fluent/plugin/compressable.rb +91 -0
  28. data/lib/fluent/plugin/filter_grep.rb +4 -4
  29. data/lib/fluent/plugin/formatter.rb +2 -2
  30. data/lib/fluent/plugin/formatter_json.rb +2 -1
  31. data/lib/fluent/plugin/formatter_out_file.rb +3 -30
  32. data/lib/fluent/plugin/in_forward.rb +6 -5
  33. data/lib/fluent/plugin/in_monitor_agent.rb +7 -21
  34. data/lib/fluent/plugin/in_syslog.rb +1 -1
  35. data/lib/fluent/plugin/in_tail.rb +11 -2
  36. data/lib/fluent/plugin/multi_output.rb +63 -3
  37. data/lib/fluent/plugin/out_exec.rb +1 -1
  38. data/lib/fluent/plugin/out_file.rb +5 -1
  39. data/lib/fluent/plugin/out_forward.rb +17 -5
  40. data/lib/fluent/plugin/out_stdout.rb +2 -1
  41. data/lib/fluent/plugin/output.rb +205 -19
  42. data/lib/fluent/plugin/parser.rb +5 -49
  43. data/lib/fluent/plugin/parser_apache2.rb +1 -1
  44. data/lib/fluent/plugin/parser_json.rb +4 -4
  45. data/lib/fluent/plugin/parser_multiline.rb +5 -5
  46. data/lib/fluent/plugin/parser_regexp.rb +1 -2
  47. data/lib/fluent/plugin/parser_syslog.rb +2 -2
  48. data/lib/fluent/plugin/storage_local.rb +2 -1
  49. data/lib/fluent/plugin_helper.rb +1 -0
  50. data/lib/fluent/plugin_helper/compat_parameters.rb +39 -21
  51. data/lib/fluent/plugin_helper/extract.rb +92 -0
  52. data/lib/fluent/plugin_helper/inject.rb +10 -12
  53. data/lib/fluent/plugin_helper/thread.rb +23 -3
  54. data/lib/fluent/registry.rb +1 -1
  55. data/lib/fluent/root_agent.rb +2 -1
  56. data/lib/fluent/supervisor.rb +28 -8
  57. data/lib/fluent/test/base.rb +0 -7
  58. data/lib/fluent/test/driver/base.rb +1 -0
  59. data/lib/fluent/test/driver/output.rb +3 -0
  60. data/lib/fluent/test/helpers.rb +18 -0
  61. data/lib/fluent/test/input_test.rb +4 -2
  62. data/lib/fluent/test/log.rb +3 -1
  63. data/lib/fluent/time.rb +232 -1
  64. data/lib/fluent/timezone.rb +1 -1
  65. data/lib/fluent/version.rb +1 -1
  66. data/test/command/test_binlog_reader.rb +351 -0
  67. data/test/config/test_config_parser.rb +6 -0
  68. data/test/config/test_configurable.rb +47 -1
  69. data/test/helper.rb +0 -1
  70. data/test/plugin/test_buffer.rb +22 -2
  71. data/test/plugin/test_buffer_chunk.rb +34 -4
  72. data/test/plugin/test_buffer_file_chunk.rb +73 -0
  73. data/test/plugin/test_buffer_memory_chunk.rb +73 -0
  74. data/test/plugin/test_compressable.rb +81 -0
  75. data/test/plugin/test_formatter_json.rb +14 -1
  76. data/test/plugin/test_in_forward.rb +67 -3
  77. data/test/plugin/test_in_monitor_agent.rb +17 -1
  78. data/test/plugin/test_in_tail.rb +8 -8
  79. data/test/plugin/test_out_file.rb +0 -8
  80. data/test/plugin/test_out_forward.rb +85 -0
  81. data/test/plugin/test_out_secondary_file.rb +20 -12
  82. data/test/plugin/test_out_stdout.rb +11 -10
  83. data/test/plugin/test_output.rb +234 -0
  84. data/test/plugin/test_output_as_buffered.rb +223 -0
  85. data/test/plugin/test_output_as_buffered_compress.rb +165 -0
  86. data/test/plugin/test_parser_json.rb +8 -0
  87. data/test/plugin/test_parser_regexp.rb +1 -1
  88. data/test/plugin_helper/test_child_process.rb +2 -2
  89. data/test/plugin_helper/test_extract.rb +195 -0
  90. data/test/plugin_helper/test_inject.rb +0 -7
  91. data/test/scripts/fluent/plugin/formatter1/formatter_test1.rb +7 -0
  92. data/test/scripts/fluent/plugin/formatter2/formatter_test2.rb +7 -0
  93. data/test/test_event.rb +186 -0
  94. data/test/test_event_router.rb +1 -1
  95. data/test/test_formatter.rb +0 -7
  96. data/test/test_log.rb +121 -0
  97. data/test/test_plugin_classes.rb +62 -0
  98. data/test/test_root_agent.rb +125 -0
  99. data/test/test_supervisor.rb +25 -2
  100. data/test/test_time_formatter.rb +103 -7
  101. data/test/test_time_parser.rb +211 -0
  102. metadata +22 -4
  103. 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 = {mode: :compat}
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
- config_param :time_type, :enum, list: [:float, :unixtime, :string], default: :string
36
- config_param :time_format, :string, default: nil
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 occures only when testing for sending responses to ForwardOutput.
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
- es = MessagePackEventStream.new(entries, nil, size.to_i)
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.each { |o|
266
- MonitorAgentInput.collect_children(o, array)
267
- }
265
+ array.concat Fluent::Engine.root_agent.outputs
266
+
268
267
  # get all filter plugins
269
- Fluent::Engine.root_agent.filters.each { |f|
270
- MonitorAgentInput.collect_children(f, array)
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.each { |o| MonitorAgentInput.collect_children(o, array) }
275
- l.filters.each { |f| MonitorAgentInput.collect_children(f, array) }
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
- latest_chunk = metadata_list.sort_by(&:timekey).last
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