fluentd 0.14.2 → 0.14.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +77 -1131
  3. data/Rakefile +15 -0
  4. data/appveyor.yml +2 -2
  5. data/example/in_forward.conf +3 -0
  6. data/example/in_forward_client.conf +37 -0
  7. data/example/in_forward_shared_key.conf +15 -0
  8. data/example/in_forward_users.conf +24 -0
  9. data/example/multi_filters.conf +61 -0
  10. data/example/out_forward.conf +13 -13
  11. data/example/out_forward_client.conf +109 -0
  12. data/example/out_forward_shared_key.conf +36 -0
  13. data/example/out_forward_users.conf +65 -0
  14. data/example/{out_buffered_null.conf → out_null.conf} +10 -6
  15. data/example/secondary_file.conf +41 -0
  16. data/fluentd.gemspec +19 -16
  17. data/lib/fluent/agent.rb +5 -0
  18. data/lib/fluent/command/debug.rb +4 -4
  19. data/lib/fluent/compat/handle_tag_and_time_mixin.rb +2 -0
  20. data/lib/fluent/compat/output.rb +5 -2
  21. data/lib/fluent/config/configure_proxy.rb +26 -5
  22. data/lib/fluent/config/error.rb +3 -0
  23. data/lib/fluent/config/section.rb +15 -0
  24. data/lib/fluent/event_router.rb +77 -4
  25. data/lib/fluent/plugin/base.rb +12 -3
  26. data/lib/fluent/plugin/buffer.rb +5 -1
  27. data/lib/fluent/plugin/filter.rb +48 -6
  28. data/lib/fluent/plugin/filter_record_transformer.rb +3 -1
  29. data/lib/fluent/plugin/filter_stdout.rb +0 -4
  30. data/lib/fluent/plugin/in_debug_agent.rb +5 -5
  31. data/lib/fluent/plugin/in_dummy.rb +9 -1
  32. data/lib/fluent/plugin/in_forward.rb +330 -62
  33. data/lib/fluent/plugin/in_monitor_agent.rb +31 -77
  34. data/lib/fluent/plugin/in_tail.rb +76 -92
  35. data/lib/fluent/plugin/multi_output.rb +4 -0
  36. data/lib/fluent/plugin/out_forward.rb +328 -222
  37. data/lib/fluent/plugin/out_null.rb +37 -0
  38. data/lib/fluent/plugin/out_secondary_file.rb +128 -0
  39. data/lib/fluent/plugin/out_stdout.rb +38 -2
  40. data/lib/fluent/plugin/output.rb +29 -6
  41. data/lib/fluent/plugin/storage_local.rb +16 -0
  42. data/lib/fluent/plugin_helper/timer.rb +6 -1
  43. data/lib/fluent/root_agent.rb +4 -1
  44. data/lib/fluent/supervisor.rb +62 -9
  45. data/lib/fluent/test/base.rb +3 -0
  46. data/lib/fluent/test/driver/base.rb +5 -0
  47. data/lib/fluent/test/formatter_test.rb +2 -0
  48. data/lib/fluent/test/parser_test.rb +2 -0
  49. data/lib/fluent/test/startup_shutdown.rb +33 -0
  50. data/lib/fluent/version.rb +1 -1
  51. data/lib/fluent/winsvc.rb +1 -2
  52. data/test/compat/test_calls_super.rb +2 -0
  53. data/test/config/test_configurable.rb +88 -0
  54. data/test/config/test_types.rb +7 -3
  55. data/test/plugin/test_filter.rb +121 -23
  56. data/test/plugin/test_filter_record_transformer.rb +22 -6
  57. data/test/plugin/test_in_debug_agent.rb +2 -2
  58. data/test/plugin/test_in_forward.rb +920 -407
  59. data/test/plugin/test_in_monitor_agent.rb +333 -0
  60. data/test/plugin/test_in_tail.rb +686 -595
  61. data/test/plugin/test_out_forward.rb +150 -207
  62. data/test/plugin/test_out_null.rb +85 -9
  63. data/test/plugin/test_out_secondary_file.rb +432 -0
  64. data/test/plugin/test_out_stdout.rb +143 -45
  65. data/test/plugin/test_output.rb +53 -0
  66. data/test/plugin/test_output_as_buffered.rb +13 -0
  67. data/test/plugin/test_output_as_buffered_overflow.rb +3 -0
  68. data/test/plugin/test_output_as_buffered_retries.rb +11 -0
  69. data/test/plugin/test_output_as_buffered_secondary.rb +12 -0
  70. data/test/plugin/test_output_as_standard.rb +12 -0
  71. data/test/plugin_helper/test_compat_parameters.rb +2 -0
  72. data/test/plugin_helper/test_timer.rb +31 -0
  73. data/test/test_event_router.rb +87 -0
  74. data/test/test_filter.rb +48 -6
  75. data/test/test_log.rb +5 -2
  76. data/test/test_output.rb +41 -1
  77. data/test/test_plugin_classes.rb +17 -9
  78. data/test/test_root_agent.rb +188 -0
  79. metadata +62 -68
  80. data/lib/fluent/plugin/out_buffered_null.rb +0 -59
  81. data/lib/fluent/plugin/out_buffered_stdout.rb +0 -70
  82. data/test/plugin/test_out_buffered_null.rb +0 -79
  83. data/test/plugin/test_out_buffered_stdout.rb +0 -122
@@ -20,13 +20,16 @@ require 'cgi'
20
20
 
21
21
  require 'cool.io'
22
22
 
23
- require 'fluent/input'
24
- require 'fluent/output'
25
- require 'fluent/filter'
23
+ require 'fluent/plugin/input'
24
+ require 'fluent/plugin/output'
25
+ require 'fluent/plugin/multi_output'
26
+ require 'fluent/plugin/filter'
26
27
 
27
- module Fluent
28
+ module Fluent::Plugin
28
29
  class MonitorAgentInput < Input
29
- Plugin.register_input('monitor_agent', self)
30
+ Fluent::Plugin.register_input('monitor_agent', self)
31
+
32
+ helpers :timer, :thread
30
33
 
31
34
  config_param :bind, :string, default: '0.0.0.0'
32
35
  config_param :port, :integer, default: 24220
@@ -142,7 +145,7 @@ module Fluent
142
145
 
143
146
  class LTSVMonitorServlet < MonitorServlet
144
147
  def process(req, res)
145
- list, opts = build_object(req, res)
148
+ list, _opts = build_object(req, res)
146
149
  return unless list
147
150
 
148
151
  normalized = JSON.parse(list.to_json)
@@ -204,36 +207,6 @@ module Fluent
204
207
  end
205
208
  end
206
209
 
207
- class TimerWatcher < Coolio::TimerWatcher
208
- def initialize(interval, log, &callback)
209
- @callback = callback
210
- @log = log
211
-
212
- # Avoid long shutdown time
213
- @num_call = 0
214
- if interval >= 10
215
- min_interval = 10
216
- @call_interval = interval / 10
217
- else
218
- min_interval = interval
219
- @call_interval = 0
220
- end
221
-
222
- super(min_interval, true)
223
- end
224
-
225
- def on_timer
226
- @num_call += 1
227
- if @num_call >= @call_interval
228
- @num_call = 0
229
- @callback.call
230
- end
231
- rescue => e
232
- @log.error e.to_s
233
- @log.error_backtrace
234
- end
235
- end
236
-
237
210
  def start
238
211
  super
239
212
 
@@ -248,76 +221,55 @@ module Fluent
248
221
  @srv.mount('/api/plugins.json', JSONMonitorServlet, self)
249
222
  @srv.mount('/api/config', LTSVConfigMonitorServlet, self)
250
223
  @srv.mount('/api/config.json', JSONConfigMonitorServlet, self)
251
- @thread = Thread.new {
224
+ thread_create :in_monitor_agent_servlet do
252
225
  @srv.start
253
- }
226
+ end
254
227
  if @tag
255
228
  log.debug "tag parameter is specified. Emit plugins info to '#{@tag}'"
256
229
 
257
- @loop = Coolio::Loop.new
258
230
  opts = {with_config: false}
259
- timer = TimerWatcher.new(@emit_interval, log) {
260
- es = MultiEventStream.new
261
- now = Engine.now
231
+ timer_execute(:in_monitor_agent_emit, @emit_interval, repeat: true) {
232
+ es = Fluent::MultiEventStream.new
233
+ now = Fluent::Engine.now
262
234
  plugins_info_all(opts).each { |record|
263
235
  es.add(now, record)
264
236
  }
265
237
  router.emit_stream(@tag, es)
266
238
  }
267
- @loop.attach(timer)
268
- @thread_for_emit = Thread.new(&method(:run))
269
239
  end
270
240
  end
271
241
 
272
- def run
273
- @loop.run
274
- rescue => e
275
- log.error "unexpected error", error: e.to_s
276
- log.error_backtrace
277
- end
278
-
279
242
  def shutdown
280
243
  if @srv
281
244
  @srv.shutdown
282
245
  @srv = nil
283
246
  end
284
- if @thread
285
- @thread.join
286
- @thread = nil
287
- end
288
- if @tag
289
- @loop.watchers.each { |w| w.detach }
290
- @loop.stop
291
- @loop = nil
292
- @thread_for_emit.join
293
- @thread_for_emit = nil
294
- end
295
247
 
296
248
  super
297
249
  end
298
250
 
299
251
  MONITOR_INFO = {
300
- 'output_plugin' => 'is_a?(::Fluent::Plugin::Output)',
301
- 'buffer_queue_length' => '@buffer.queue.size',
302
- 'buffer_total_queued_size' => '@buffer.stage_size + @buffer.queue_size',
303
- 'retry_count' => '@num_errors',
252
+ 'output_plugin' => ->(){ is_a?(::Fluent::Plugin::Output) },
253
+ 'buffer_queue_length' => ->(){ throw(:skip) unless instance_variable_defined?(:@buffer); @buffer.queue.size },
254
+ 'buffer_total_queued_size' => ->(){ throw(:skip) unless instance_variable_defined?(:@buffer); @buffer.stage_size },
255
+ 'retry_count' => ->(){ instance_variable_defined?(:@num_errors) ? @num_errors : nil },
304
256
  }
305
257
 
306
258
  def all_plugins
307
259
  array = []
308
260
 
309
261
  # get all input plugins
310
- array.concat Engine.root_agent.inputs
262
+ array.concat Fluent::Engine.root_agent.inputs
311
263
 
312
264
  # get all output plugins
313
- Engine.root_agent.outputs.each { |o|
265
+ Fluent::Engine.root_agent.outputs.each { |o|
314
266
  MonitorAgentInput.collect_children(o, array)
315
267
  }
316
268
  # get all filter plugins
317
- Engine.root_agent.filters.each { |f|
269
+ Fluent::Engine.root_agent.filters.each { |f|
318
270
  MonitorAgentInput.collect_children(f, array)
319
271
  }
320
- Engine.root_agent.labels.each { |name, l|
272
+ Fluent::Engine.root_agent.labels.each { |name, l|
321
273
  # TODO: Add label name to outputs / filters for identifing plugins
322
274
  l.outputs.each { |o| MonitorAgentInput.collect_children(o, array) }
323
275
  l.filters.each { |f| MonitorAgentInput.collect_children(f, array) }
@@ -330,7 +282,7 @@ module Fluent
330
282
  # from the plugin `pe` recursively
331
283
  def self.collect_children(pe, array=[])
332
284
  array << pe
333
- if pe.is_a?(MultiOutput) && pe.respond_to?(:outputs)
285
+ if pe.is_a?(Fluent::Plugin::MultiOutput) || pe.is_a?(Fluent::MultiOutput) && pe.respond_to?(:outputs)
334
286
  pe.outputs.each {|nop|
335
287
  collect_children(nop, array)
336
288
  }
@@ -341,10 +293,10 @@ module Fluent
341
293
  # try to match the tag and get the info from the matched output plugin
342
294
  # TODO: Support output in label
343
295
  def plugin_info_by_tag(tag, opts={})
344
- matches = Engine.root_agent.event_router.instance_variable_get(:@match_rules)
296
+ matches = Fluent::Engine.root_agent.event_router.instance_variable_get(:@match_rules)
345
297
  matches.each { |rule|
346
298
  if rule.match?(tag)
347
- if rule.collector.is_a?(Output)
299
+ if rule.collector.is_a?(Fluent::Plugin::Output) || rule.collector.is_a?(Fluent::Output)
348
300
  return get_monitor_info(rule.collector, opts)
349
301
  end
350
302
  end
@@ -381,8 +333,7 @@ module Fluent
381
333
  }
382
334
  end
383
335
 
384
- # TODO: use %i() after drop ruby v1.9.3 support.
385
- IGNORE_ATTRIBUTES = %W(@config_root_section @config @masked_config).map(&:to_sym)
336
+ IGNORE_ATTRIBUTES = %i(@config_root_section @config @masked_config)
386
337
 
387
338
  # get monitor info from the plugin `pe` and return a hash object
388
339
  def get_monitor_info(pe, opts={})
@@ -397,8 +348,11 @@ module Fluent
397
348
  # run MONITOR_INFO in plugins' instance context and store the info to obj
398
349
  MONITOR_INFO.each_pair {|key,code|
399
350
  begin
400
- obj[key] = pe.instance_eval(code)
401
- rescue
351
+ catch(:skip) do
352
+ obj[key] = pe.instance_exec(&code)
353
+ end
354
+ rescue => e
355
+ log.warn "unexpected error in monitoring plugins", key: key, plugin: pe.class, error: e
402
356
  end
403
357
  }
404
358
 
@@ -16,10 +16,9 @@
16
16
 
17
17
  require 'cool.io'
18
18
 
19
- require 'fluent/input'
19
+ require 'fluent/plugin/input'
20
20
  require 'fluent/config/error'
21
21
  require 'fluent/event'
22
- require 'fluent/system_config'
23
22
  require 'fluent/plugin/buffer'
24
23
 
25
24
  if Fluent.windows?
@@ -28,11 +27,11 @@ else
28
27
  Fluent::FileWrapper = File
29
28
  end
30
29
 
31
- module Fluent
32
- class TailInput < Input
33
- include SystemConfig::Mixin
30
+ module Fluent::Plugin
31
+ class TailInput < Fluent::Plugin::Input
32
+ Fluent::Plugin.register_input('tail', self)
34
33
 
35
- Plugin.register_input('tail', self)
34
+ helpers :timer, :event_loop, :parser, :compat_parameters
36
35
 
37
36
  FILE_PERMISSION = 0644
38
37
 
@@ -67,25 +66,34 @@ module Fluent
67
66
  config_param :multiline_flush_interval, :time, default: nil
68
67
  desc 'Enable the additional watch timer.'
69
68
  config_param :enable_watch_timer, :bool, default: true
69
+ desc 'The encoding after conversion of the input.'
70
+ config_param :encoding, :string, default: nil
70
71
  desc 'The encoding of the input.'
71
- config_param :encoding, default: nil do |encoding_name|
72
- begin
73
- Encoding.find(encoding_name)
74
- rescue ArgumentError => e
75
- raise ConfigError, e.message
76
- end
77
- end
72
+ config_param :from_encoding, :string, default: nil
78
73
  desc 'Add the log path being tailed to records. Specify the field name to be used.'
79
74
  config_param :path_key, :string, default: nil
80
75
 
81
76
  attr_reader :paths
82
77
 
83
78
  def configure(conf)
79
+ compat_parameters_convert(conf, :parser)
80
+ parser_config = conf.elements('parse').first
81
+ unless parser_config
82
+ raise Fluent::ConfigError, "<parse> section is required."
83
+ end
84
+ unless parser_config["@type"]
85
+ raise Fluent::ConfigError, "parse/@type is required."
86
+ end
87
+
88
+ (1..Fluent::Plugin::MultilineParser::FORMAT_MAX_NUM).each do |n|
89
+ parser_config["format#{n}"] = conf["format#{n}"] if conf["format#{n}"]
90
+ end
91
+
84
92
  super
85
93
 
86
94
  @paths = @path.split(',').map {|path| path.strip }
87
95
  if @paths.empty?
88
- raise ConfigError, "tail: 'path' parameter is required on tail input"
96
+ raise Fluent::ConfigError, "tail: 'path' parameter is required on tail input"
89
97
  end
90
98
 
91
99
  unless @pos_file
@@ -93,21 +101,17 @@ module Fluent
93
101
  $log.warn "this parameter is highly recommended to save the position to resume tailing."
94
102
  end
95
103
 
96
- configure_parser(conf)
97
104
  configure_tag
105
+ configure_encoding
98
106
 
99
- @multiline_mode = conf['format'] =~ /multiline/
107
+ @multiline_mode = parser_config["@type"] =~ /multiline/
100
108
  @receive_handler = if @multiline_mode
101
109
  method(:parse_multilines)
102
110
  else
103
111
  method(:parse_singleline)
104
112
  end
105
113
  @file_perm = system_config.file_permission || FILE_PERMISSION
106
- end
107
-
108
- def configure_parser(conf)
109
- @parser = Plugin.new_parser(conf['format'])
110
- @parser.configure(conf)
114
+ @parser = parser_create(conf: parser_config)
111
115
  end
112
116
 
113
117
  def configure_tag
@@ -120,6 +124,25 @@ module Fluent
120
124
  end
121
125
  end
122
126
 
127
+ def configure_encoding
128
+ unless @encoding
129
+ if @from_encoding
130
+ raise Fluent::ConfigError, "tail: 'from_encoding' parameter must be specified with 'encoding' parameter."
131
+ end
132
+ end
133
+
134
+ @encoding = parse_encoding_param(@encoding) if @encoding
135
+ @from_encoding = parse_encoding_param(@from_encoding) if @from_encoding
136
+ end
137
+
138
+ def parse_encoding_param(encoding_name)
139
+ begin
140
+ Encoding.find(encoding_name) if encoding_name
141
+ rescue ArgumentError => e
142
+ raise Fluent::ConfigError, e.message
143
+ end
144
+ end
145
+
123
146
  def start
124
147
  super
125
148
 
@@ -129,20 +152,12 @@ module Fluent
129
152
  @pf = PositionFile.parse(@pf_file)
130
153
  end
131
154
 
132
- @loop = Coolio::Loop.new
133
155
  refresh_watchers
134
-
135
- @refresh_trigger = TailWatcher::TimerWatcher.new(@refresh_interval, true, log, &method(:refresh_watchers))
136
- @refresh_trigger.attach(@loop)
137
- @thread = Thread.new(&method(:run))
156
+ timer_execute(:in_tail_refresh_watchers, @refresh_interval, &method(:refresh_watchers))
138
157
  end
139
158
 
140
159
  def shutdown
141
- @refresh_trigger.detach if @refresh_trigger && @refresh_trigger.attached?
142
-
143
160
  stop_watchers(@tails.keys, true)
144
- @loop.stop rescue nil # when all watchers are detached, `stop` raises RuntimeError. We can ignore this exception.
145
- @thread.join
146
161
  @pf_file.close if @pf_file
147
162
 
148
163
  super
@@ -190,8 +205,11 @@ module Fluent
190
205
 
191
206
  def setup_watcher(path, pe)
192
207
  line_buffer_timer_flusher = (@multiline_mode && @multiline_flush_interval) ? TailWatcher::LineBufferTimerFlusher.new(log, @multiline_flush_interval, &method(:flush_buffer)) : nil
193
- 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))
194
- tw.attach(@loop)
208
+ 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
+ tw.attach do |watcher|
210
+ timer_execute(:in_tail_timer_trigger, 1, &watcher.method(:on_notify)) if watcher.enable_watch_timer
211
+ event_loop_attach(watcher.stat_trigger)
212
+ end
195
213
  tw
196
214
  end
197
215
 
@@ -202,7 +220,7 @@ module Fluent
202
220
  pe = @pf[path]
203
221
  if @read_from_head && pe.read_inode.zero?
204
222
  begin
205
- pe.update(FileWrapper.stat(path).ino, 0)
223
+ pe.update(Fluent::FileWrapper.stat(path).ino, 0)
206
224
  rescue Errno::ENOENT
207
225
  $log.warn "#{path} not found. Continuing without tailing it."
208
226
  end
@@ -247,14 +265,21 @@ module Fluent
247
265
  end
248
266
 
249
267
  def close_watcher_after_rotate_wait(tw)
250
- closer = TailWatcher::Closer.new(@rotate_wait, tw, log, &method(:close_watcher))
251
- closer.attach(@loop)
268
+ timer_execute(:in_tail_close_watcher, @rotate_wait, repeat: false) do
269
+ close_watcher(tw)
270
+ end
252
271
  end
253
272
 
254
273
  def flush_buffer(tw)
255
274
  if lb = tw.line_buffer
256
275
  lb.chomp!
257
- lb.force_encoding(@encoding) if @encoding
276
+ if @encoding
277
+ if @from_encoding
278
+ lb.encode!(@encoding, @from_encoding)
279
+ else
280
+ lb.force_encoding(@encoding)
281
+ end
282
+ end
258
283
  @parser.parse(lb) { |time, record|
259
284
  if time && record
260
285
  tag = if @tag_prefix || @tag_suffix
@@ -271,13 +296,6 @@ module Fluent
271
296
  end
272
297
  end
273
298
 
274
- def run
275
- @loop.run
276
- rescue
277
- log.error "unexpected error", error: $!.to_s
278
- log.error_backtrace
279
- end
280
-
281
299
  # @return true if no error or unrecoverable error happens in emit action. false if got BufferOverflowError
282
300
  def receive_lines(lines, tail_watcher)
283
301
  es = @receive_handler.call(lines, tail_watcher)
@@ -303,7 +321,13 @@ module Fluent
303
321
  def convert_line_to_event(line, es, tail_watcher)
304
322
  begin
305
323
  line.chomp! # remove \n
306
- line.force_encoding(@encoding) if @encoding
324
+ if @encoding
325
+ if @from_encoding
326
+ line.encode!(@encoding, @from_encoding)
327
+ else
328
+ line.force_encoding(@encoding)
329
+ end
330
+ end
307
331
  @parser.parse(line) { |time, record|
308
332
  if time && record
309
333
  record[@path_key] ||= tail_watcher.path unless @path_key.nil?
@@ -319,7 +343,7 @@ module Fluent
319
343
  end
320
344
 
321
345
  def parse_singleline(lines, tail_watcher)
322
- es = MultiEventStream.new
346
+ es = Fluent::MultiEventStream.new
323
347
  lines.each { |line|
324
348
  convert_line_to_event(line, es, tail_watcher)
325
349
  }
@@ -328,7 +352,7 @@ module Fluent
328
352
 
329
353
  def parse_multilines(lines, tail_watcher)
330
354
  lb = tail_watcher.line_buffer
331
- es = MultiEventStream.new
355
+ es = Fluent::MultiEventStream.new
332
356
  if @parser.has_firstline?
333
357
  tail_watcher.line_buffer_timer_flusher.reset_timer if tail_watcher.line_buffer_timer_flusher
334
358
  lines.each { |line|
@@ -372,8 +396,6 @@ module Fluent
372
396
  @receive_lines = receive_lines
373
397
  @update_watcher = update_watcher
374
398
 
375
- @timer_trigger = TimerWatcher.new(1, true, log, &method(:on_notify)) if @enable_watch_timer
376
-
377
399
  @stat_trigger = StatWatcher.new(path, log, &method(:on_notify))
378
400
 
379
401
  @rotate_handler = RotateHandler.new(path, log, &method(:on_rotate))
@@ -384,6 +406,8 @@ module Fluent
384
406
  end
385
407
 
386
408
  attr_reader :path
409
+ attr_reader :stat_trigger, :enable_watch_timer
410
+ attr_accessor :timer_trigger
387
411
  attr_accessor :line_buffer, :line_buffer_timer_flusher
388
412
  attr_accessor :unwatched # This is used for removing position entry from PositionFile
389
413
 
@@ -395,14 +419,12 @@ module Fluent
395
419
  @receive_lines.call(lines, self)
396
420
  end
397
421
 
398
- def attach(loop)
399
- @timer_trigger.attach(loop) if @enable_watch_timer
400
- @stat_trigger.attach(loop)
422
+ def attach
423
+ yield self
401
424
  on_notify
402
425
  end
403
426
 
404
427
  def detach
405
- @timer_trigger.detach if @enable_watch_timer && @timer_trigger.attached?
406
428
  @stat_trigger.detach if @stat_trigger.attached?
407
429
  end
408
430
 
@@ -495,22 +517,6 @@ module Fluent
495
517
  pe # This pe will be updated in on_rotate after TailWatcher is initialized
496
518
  end
497
519
 
498
- class TimerWatcher < Coolio::TimerWatcher
499
- def initialize(interval, repeat, log, &callback)
500
- @callback = callback
501
- @log = log
502
- super(interval, repeat)
503
- end
504
-
505
- def on_timer
506
- @callback.call
507
- rescue
508
- # TODO log?
509
- @log.error $!.to_s
510
- @log.error_backtrace
511
- end
512
- end
513
-
514
520
  class StatWatcher < Coolio::StatWatcher
515
521
  def initialize(path, log, &callback)
516
522
  @callback = callback
@@ -527,24 +533,6 @@ module Fluent
527
533
  end
528
534
  end
529
535
 
530
- class Closer < Coolio::TimerWatcher
531
- def initialize(interval, tw, log, &callback)
532
- @callback = callback
533
- @tw = tw
534
- @log = log
535
- super(interval, false)
536
- end
537
-
538
- def on_timer
539
- @callback.call(@tw)
540
- rescue => e
541
- @log.error e.to_s
542
- @log.error_backtrace(e.backtrace)
543
- ensure
544
- detach
545
- end
546
- end
547
-
548
536
  class IOHandler
549
537
  def initialize(io, pe, log, read_lines_limit, first = true, &receive_lines)
550
538
  @log = log
@@ -632,7 +620,7 @@ module Fluent
632
620
 
633
621
  def on_notify
634
622
  begin
635
- stat = FileWrapper.stat(@path)
623
+ stat = Fluent::FileWrapper.stat(@path)
636
624
  inode = stat.ino
637
625
  fsize = stat.size
638
626
  rescue Errno::ENOENT
@@ -645,7 +633,7 @@ module Fluent
645
633
  if @inode != inode || fsize < @fsize
646
634
  # rotated or truncated
647
635
  begin
648
- io = FileWrapper.open(@path)
636
+ io = Fluent::FileWrapper.open(@path)
649
637
  rescue Errno::ENOENT
650
638
  end
651
639
  @on_rotate.call(io)
@@ -660,7 +648,6 @@ module Fluent
660
648
  end
661
649
  end
662
650
 
663
-
664
651
  class LineBufferTimerFlusher
665
652
  def initialize(log, flush_interval, &flush_method)
666
653
  @log = log
@@ -685,7 +672,6 @@ module Fluent
685
672
  end
686
673
  end
687
674
 
688
-
689
675
  class PositionFile
690
676
  UNWATCHED_POSITION = 0xffffffffffffffff
691
677
 
@@ -805,6 +791,4 @@ module Fluent
805
791
  end
806
792
  end
807
793
  end
808
-
809
- NewTailInput = TailInput # for backward compatibility
810
794
  end
@@ -53,6 +53,10 @@ module Fluent
53
53
  # @rollback_count = 0
54
54
  end
55
55
 
56
+ def multi_output?
57
+ true
58
+ end
59
+
56
60
  def configure(conf)
57
61
  super
58
62