fluentd 0.14.12 → 0.14.13

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +2 -0
  3. data/ChangeLog +33 -0
  4. data/bin/fluent-plugin-config-format +5 -0
  5. data/bin/fluent-plugin-generate +5 -0
  6. data/lib/fluent/command/plugin_config_formatter.rb +258 -0
  7. data/lib/fluent/command/plugin_generator.rb +301 -0
  8. data/lib/fluent/compat/detach_process_mixin.rb +25 -0
  9. data/lib/fluent/compat/filter.rb +1 -1
  10. data/lib/fluent/compat/input.rb +1 -0
  11. data/lib/fluent/compat/output.rb +8 -5
  12. data/lib/fluent/config/configure_proxy.rb +31 -8
  13. data/lib/fluent/configurable.rb +2 -2
  14. data/lib/fluent/output.rb +3 -0
  15. data/lib/fluent/plugin/buffer/file_chunk.rb +52 -11
  16. data/lib/fluent/plugin/filter.rb +1 -1
  17. data/lib/fluent/plugin/filter_record_transformer.rb +5 -1
  18. data/lib/fluent/plugin/in_tail.rb +13 -6
  19. data/lib/fluent/plugin/input.rb +1 -1
  20. data/lib/fluent/plugin/output.rb +26 -6
  21. data/lib/fluent/plugin/parser_apache.rb +1 -1
  22. data/lib/fluent/plugin/parser_apache_error.rb +1 -1
  23. data/lib/fluent/plugin/parser_multiline.rb +1 -0
  24. data/lib/fluent/plugin/parser_nginx.rb +1 -1
  25. data/lib/fluent/plugin/parser_regexp.rb +18 -0
  26. data/lib/fluent/plugin_helper.rb +19 -1
  27. data/lib/fluent/plugin_helper/retry_state.rb +40 -16
  28. data/lib/fluent/process.rb +22 -0
  29. data/lib/fluent/supervisor.rb +2 -21
  30. data/lib/fluent/test/helpers.rb +14 -0
  31. data/lib/fluent/version.rb +1 -1
  32. data/templates/new_gem/Gemfile +3 -0
  33. data/templates/new_gem/README.md.erb +43 -0
  34. data/templates/new_gem/Rakefile +13 -0
  35. data/templates/new_gem/fluent-plugin.gemspec.erb +27 -0
  36. data/templates/new_gem/lib/fluent/plugin/filter.rb.erb +14 -0
  37. data/templates/new_gem/lib/fluent/plugin/formatter.rb.erb +14 -0
  38. data/templates/new_gem/lib/fluent/plugin/input.rb.erb +11 -0
  39. data/templates/new_gem/lib/fluent/plugin/output.rb.erb +11 -0
  40. data/templates/new_gem/lib/fluent/plugin/parser.rb.erb +15 -0
  41. data/templates/new_gem/test/helper.rb.erb +8 -0
  42. data/templates/new_gem/test/plugin/test_filter.rb.erb +18 -0
  43. data/templates/new_gem/test/plugin/test_formatter.rb.erb +18 -0
  44. data/templates/new_gem/test/plugin/test_input.rb.erb +18 -0
  45. data/templates/new_gem/test/plugin/test_output.rb.erb +18 -0
  46. data/templates/new_gem/test/plugin/test_parser.rb.erb +18 -0
  47. data/templates/plugin_config_formatter/param.md-compact.erb +25 -0
  48. data/templates/plugin_config_formatter/param.md.erb +34 -0
  49. data/templates/plugin_config_formatter/section.md.erb +12 -0
  50. data/test/command/test_binlog_reader.rb +0 -9
  51. data/test/command/test_plugin_config_formatter.rb +275 -0
  52. data/test/command/test_plugin_generator.rb +66 -0
  53. data/test/config/test_configure_proxy.rb +89 -45
  54. data/test/plugin/data/log/foo/bar2 +0 -0
  55. data/test/plugin/test_in_tail.rb +97 -8
  56. data/test/plugin/test_output.rb +18 -0
  57. data/test/plugin/test_output_as_buffered.rb +35 -0
  58. data/test/plugin_helper/test_compat_parameters.rb +2 -0
  59. data/test/plugin_helper/test_retry_state.rb +23 -0
  60. data/test/test_output.rb +5 -0
  61. data/test/test_process.rb +14 -0
  62. metadata +37 -3
@@ -0,0 +1,25 @@
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
+ module Fluent
18
+ module Compat
19
+ module DetachProcessMixin
20
+ end
21
+
22
+ module DetachMultiProcessMixin
23
+ end
24
+ end
25
+ end
@@ -25,7 +25,7 @@ module Fluent
25
25
  class Filter < Fluent::Plugin::Filter
26
26
  # TODO: warn when deprecated
27
27
 
28
- helpers :inject
28
+ helpers_internal :inject
29
29
 
30
30
  def initialize
31
31
  super
@@ -16,6 +16,7 @@
16
16
 
17
17
  require 'fluent/plugin'
18
18
  require 'fluent/plugin/input'
19
+ require 'fluent/process'
19
20
  require 'fluent/compat/call_super_mixin'
20
21
 
21
22
  module Fluent
@@ -15,6 +15,7 @@
15
15
  #
16
16
 
17
17
  require 'fluent/plugin'
18
+ require 'fluent/plugin/buffer'
18
19
  require 'fluent/plugin/output'
19
20
  require 'fluent/plugin/bare_output'
20
21
  require 'fluent/compat/call_super_mixin'
@@ -26,6 +27,7 @@ require 'fluent/compat/record_filter_mixin'
26
27
  require 'fluent/compat/output_chain'
27
28
  require 'fluent/timezone'
28
29
  require 'fluent/mixin'
30
+ require 'fluent/process'
29
31
  require 'fluent/event'
30
32
 
31
33
  require 'fluent/plugin_helper/compat_parameters'
@@ -35,6 +37,7 @@ require 'time'
35
37
  module Fluent
36
38
  module Compat
37
39
  NULL_OUTPUT_CHAIN = NullOutputChain.instance
40
+ BufferQueueLimitError = ::Fluent::Plugin::Buffer::BufferOverflowError
38
41
 
39
42
  module CompatOutputUtils
40
43
  def self.buffer_section(conf)
@@ -146,7 +149,7 @@ module Fluent
146
149
  class Output < Fluent::Plugin::Output
147
150
  # TODO: warn when deprecated
148
151
 
149
- helpers :event_emitter, :inject
152
+ helpers_internal :event_emitter, :inject
150
153
 
151
154
  def support_in_v12_style?(feature)
152
155
  case feature
@@ -202,7 +205,7 @@ module Fluent
202
205
  class MultiOutput < Fluent::Plugin::BareOutput
203
206
  # TODO: warn when deprecated
204
207
 
205
- helpers :event_emitter
208
+ helpers_internal :event_emitter
206
209
 
207
210
  def process(tag, es)
208
211
  emit(tag, es, NULL_OUTPUT_CHAIN)
@@ -212,7 +215,7 @@ module Fluent
212
215
  class BufferedOutput < Fluent::Plugin::Output
213
216
  # TODO: warn when deprecated
214
217
 
215
- helpers :event_emitter, :inject
218
+ helpers_internal :event_emitter, :inject
216
219
 
217
220
  def support_in_v12_style?(feature)
218
221
  case feature
@@ -422,7 +425,7 @@ module Fluent
422
425
  class ObjectBufferedOutput < Fluent::Plugin::Output
423
426
  # TODO: warn when deprecated
424
427
 
425
- helpers :event_emitter, :inject
428
+ helpers_internal :event_emitter, :inject
426
429
 
427
430
  # This plugin cannot inherit BufferedOutput because #configure sets chunk_key 'tag'
428
431
  # to flush chunks per tags, but BufferedOutput#configure doesn't allow setting chunk_key
@@ -559,7 +562,7 @@ module Fluent
559
562
  class TimeSlicedOutput < Fluent::Plugin::Output
560
563
  # TODO: warn when deprecated
561
564
 
562
- helpers :event_emitter, :inject
565
+ helpers_internal :event_emitter, :inject
563
566
 
564
567
  def support_in_v12_style?(feature)
565
568
  case feature
@@ -368,16 +368,40 @@ module Fluent
368
368
  name
369
369
  end
370
370
 
371
- def dump(level = 0)
372
- dumped_config = ""
373
- indent = " " * level
371
+ def dump_config_definition
372
+ dumped_config = {}
374
373
  @params.each do |name, config|
375
- dumped_config << "#{indent}#{name}: #{config[1][:type]}: <#{@defaults[name].inspect}>"
376
- dumped_config << " # #{@descriptions[name]}" if @descriptions[name]
377
- dumped_config << "\n"
374
+ dumped_config[name] = config[1]
375
+ dumped_config[name][:required] = !@defaults.key?(name)
376
+ dumped_config[name][:default] = @defaults[name] if @defaults.key?(name)
377
+ dumped_config[name][:desc] = @descriptions[name] if @descriptions.key?(name)
378
+ end
379
+ # Overwrite by config_set_default
380
+ @defaults.each do |name, value|
381
+ if @params.key?(name)
382
+ dumped_config[name][:default] = value
383
+ else
384
+ dumped_config[name] = { default: value }
385
+ end
386
+ end
387
+ # Overwrite by config_set_desc
388
+ @descriptions.each do |name, value|
389
+ if @params.key?(name)
390
+ dumped_config[name][:desc] = value
391
+ else
392
+ dumped_config[name] = { desc: value }
393
+ end
378
394
  end
379
395
  @sections.each do |section_name, sub_proxy|
380
- dumped_config << "#{indent}#{section_name}\n#{sub_proxy.dump(level + 1)}"
396
+ if dumped_config.key?(section_name)
397
+ dumped_config[section_name].update(sub_proxy.dump_config_definition)
398
+ else
399
+ dumped_config[section_name] = sub_proxy.dump_config_definition
400
+ dumped_config[section_name][:required] = sub_proxy.required?
401
+ dumped_config[section_name][:multi] = sub_proxy.multi?
402
+ dumped_config[section_name][:alias] = sub_proxy.alias
403
+ dumped_config[section_name][:section] = true
404
+ end
381
405
  end
382
406
  dumped_config
383
407
  end
@@ -392,4 +416,3 @@ module Fluent
392
416
  end
393
417
  end
394
418
  end
395
-
@@ -192,8 +192,8 @@ module Fluent
192
192
  configurables.map{ |a| a.configure_proxy(a.name || a.object_id.to_s) }.reduce(:merge)
193
193
  end
194
194
 
195
- def dump(level = 0)
196
- configure_proxy_map[self.to_s].dump(level)
195
+ def dump_config_definition
196
+ configure_proxy_map[self.to_s].dump_config_definition
197
197
  end
198
198
  end
199
199
  end
@@ -23,4 +23,7 @@ module Fluent
23
23
  ObjectBufferedOutput = Fluent::Compat::ObjectBufferedOutput
24
24
  TimeSlicedOutput = Fluent::Compat::TimeSlicedOutput
25
25
  MultiOutput = Fluent::Compat::MultiOutput
26
+
27
+ # Some input plugins refer BufferQueueLimitError for throttling
28
+ BufferQueueLimitError = Fluent::Compat::BufferQueueLimitError
26
29
  end
@@ -106,10 +106,37 @@ module Fluent
106
106
 
107
107
  write_metadata(update: false) # re-write metadata w/ finalized records
108
108
 
109
- file_rename(@chunk, @path, new_chunk_path, ->(new_io){ @chunk = new_io })
110
- @path = new_chunk_path
109
+ begin
110
+ file_rename(@chunk, @path, new_chunk_path, ->(new_io) { @chunk = new_io })
111
+ rescue => e
112
+ begin
113
+ file_rename(@chunk, new_chunk_path, @path, ->(new_io) { @chunk = new_io }) if File.exist?(new_chunk_path)
114
+ rescue => re
115
+ # In this point, restore buffer state is hard because previous `file_rename` failed by resource problem.
116
+ # Retry is one possible approach but it may cause livelock under limited resources or high load environment.
117
+ # So we ignore such errors for now and log better message instead.
118
+ # "Too many open files" should be fixed by proper buffer configuration and system setting.
119
+ raise "can't enqueue buffer file and failed to restore. This may causes inconsistent state: path = #{@path}, error = '#{e}', retry error = '#{re}'"
120
+ else
121
+ raise "can't enqueue buffer file: path = #{@path}, error = '#{e}'"
122
+ end
123
+ end
124
+
125
+ begin
126
+ file_rename(@meta, @meta_path, new_meta_path, ->(new_io) { @meta = new_io })
127
+ rescue => e
128
+ begin
129
+ file_rename(@chunk, new_chunk_path, @path, ->(new_io) { @chunk = new_io }) if File.exist?(new_chunk_path)
130
+ file_rename(@meta, new_meta_path, @meta_path, ->(new_io) { @meta = new_io }) if File.exist?(new_meta_path)
131
+ rescue => re
132
+ # See above
133
+ raise "can't enqueue buffer metadata and failed to restore. This may causes inconsistent state: path = #{@meta_path}, error = '#{e}', retry error = '#{re}'"
134
+ else
135
+ raise "can't enqueue buffer metadata: path = #{@meta_path}, error = '#{e}'"
136
+ end
137
+ end
111
138
 
112
- file_rename(@meta, @meta_path, new_meta_path, ->(new_io){ @meta = new_io })
139
+ @path = new_chunk_path
113
140
  @meta_path = new_meta_path
114
141
 
115
142
  super
@@ -242,14 +269,28 @@ module Fluent
242
269
  def create_new_chunk(path, perm)
243
270
  @path = self.class.generate_stage_chunk_path(path, @unique_id)
244
271
  @meta_path = @path + '.meta'
245
- @chunk = File.open(@path, 'wb+', perm)
246
- @chunk.set_encoding(Encoding::ASCII_8BIT)
247
- @chunk.sync = true
248
- @chunk.binmode
249
- @meta = File.open(@meta_path, 'wb', perm)
250
- @meta.set_encoding(Encoding::ASCII_8BIT)
251
- @meta.sync = true
252
- @meta.binmode
272
+ begin
273
+ @chunk = File.open(@path, 'wb+', perm)
274
+ @chunk.set_encoding(Encoding::ASCII_8BIT)
275
+ @chunk.sync = true
276
+ @chunk.binmode
277
+ rescue => e
278
+ # Here assumes "Too many open files" like recoverable error so raising BufferOverflowError.
279
+ # If other cases are possible, we will change erorr handling with proper classes.
280
+ raise BufferOverflowError, "can't create buffer file for #{path}. Stop creating buffer files: error = #{e}"
281
+ end
282
+ begin
283
+ @meta = File.open(@meta_path, 'wb', perm)
284
+ @meta.set_encoding(Encoding::ASCII_8BIT)
285
+ @meta.sync = true
286
+ @meta.binmode
287
+ rescue => e
288
+ # This case is easier than enqueued!. Just removing pre-create buffer file
289
+ @chunk.close rescue nil
290
+ File.unlink(@path) rescue nil
291
+ # Same as @chunk case. See above
292
+ raise BufferOverflowError, "can't create buffer metadata for #{path}. Stop creating buffer files: error = #{e}"
293
+ end
253
294
 
254
295
  @state = :unstaged
255
296
  @bytesize = 0
@@ -28,7 +28,7 @@ module Fluent
28
28
  include PluginLoggerMixin
29
29
  include PluginHelper::Mixin
30
30
 
31
- helpers :event_emitter
31
+ helpers_internal :event_emitter
32
32
 
33
33
  attr_reader :has_filter_with_time
34
34
 
@@ -308,10 +308,14 @@ module Fluent::Plugin
308
308
  raise "failed to expand `#{str}` : error = #{e}"
309
309
  end
310
310
 
311
- class CleanroomExpander < BasicObject
311
+ class CleanroomExpander
312
312
  def expand(__str_to_eval__, tag, time, record, tag_parts, tag_prefix, tag_suffix, hostname)
313
313
  instance_eval(__str_to_eval__)
314
314
  end
315
+
316
+ (Object.instance_methods).each do |m|
317
+ undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
318
+ end
315
319
  end
316
320
  end
317
321
  end
@@ -77,6 +77,8 @@ module Fluent::Plugin
77
77
  config_param :path_key, :string, default: nil
78
78
  desc 'Open and close the file on every update instead of leaving it open until it gets rotated.'
79
79
  config_param :open_on_every_update, :bool, default: false
80
+ desc 'Limit the watching files that the modification time is within the specified time range (when use \'*\' in path).'
81
+ config_param :limit_recently_modified, :time, default: nil
80
82
 
81
83
  attr_reader :paths
82
84
 
@@ -163,7 +165,8 @@ module Fluent::Plugin
163
165
  end
164
166
 
165
167
  def shutdown
166
- stop_watchers(@tails.keys, true)
168
+ # during shutdown phase, don't close io. It should be done in close after all threads are stopped. See close.
169
+ stop_watchers(@tails.keys, immediate: true, remove_watcher: false)
167
170
  @pf_file.close if @pf_file
168
171
 
169
172
  super
@@ -184,8 +187,12 @@ module Fluent::Plugin
184
187
  path = date.strftime(path)
185
188
  if path.include?('*')
186
189
  paths += Dir.glob(path).select { |p|
187
- if File.readable?(p)
188
- true
190
+ if File.readable?(p) && !File.directory?(p)
191
+ if @limit_recently_modified && File.mtime(p) < (date - @limit_recently_modified)
192
+ false
193
+ else
194
+ true
195
+ end
189
196
  else
190
197
  log.warn "#{p} unreadable. It is excluded and would be examined next time."
191
198
  false
@@ -211,7 +218,7 @@ module Fluent::Plugin
211
218
  unwatched = existence_paths - target_paths
212
219
  added = target_paths - existence_paths
213
220
 
214
- stop_watchers(unwatched, false, true) unless unwatched.empty?
221
+ stop_watchers(unwatched, immediate: false, unwatched: true) unless unwatched.empty?
215
222
  start_watchers(added) unless added.empty?
216
223
  end
217
224
 
@@ -243,9 +250,9 @@ module Fluent::Plugin
243
250
  }
244
251
  end
245
252
 
246
- def stop_watchers(paths, immediate = false, unwatched = false)
253
+ def stop_watchers(paths, immediate: false, unwatched: false, remove_watcher: true)
247
254
  paths.each { |path|
248
- tw = @tails[path]
255
+ tw = remove_watcher ? @tails.delete(path) : @tails[path]
249
256
  if tw
250
257
  tw.unwatched = unwatched
251
258
  if immediate
@@ -27,7 +27,7 @@ module Fluent
27
27
  include PluginLoggerMixin
28
28
  include PluginHelper::Mixin
29
29
 
30
- helpers :event_emitter
30
+ helpers_internal :event_emitter
31
31
 
32
32
  def multi_workers_ready?
33
33
  false
@@ -33,7 +33,7 @@ module Fluent
33
33
  include PluginHelper::Mixin
34
34
  include UniqueId::Mixin
35
35
 
36
- helpers :thread, :retry_state
36
+ helpers_internal :thread, :retry_state
37
37
 
38
38
  CHUNK_KEY_PATTERN = /^[-_.@a-zA-Z0-9]+$/
39
39
  CHUNK_KEY_PLACEHOLDER_PATTERN = /\$\{[-_.@a-zA-Z0-9]+\}/
@@ -229,6 +229,7 @@ module Fluent
229
229
  end
230
230
 
231
231
  has_buffer_section = (conf.elements(name: 'buffer').size > 0)
232
+ has_flush_interval = conf.has_key?('flush_interval')
232
233
 
233
234
  super
234
235
 
@@ -290,7 +291,12 @@ module Fluent
290
291
 
291
292
  @flush_mode = @buffer_config.flush_mode
292
293
  if @flush_mode == :default
293
- @flush_mode = (@chunk_key_time ? :lazy : :interval)
294
+ if has_flush_interval
295
+ log.info "'flush_interval' is configured at out side of <buffer>. 'flush_mode' is set to 'interval' to keep existing behaviour"
296
+ @flush_mode = :interval
297
+ else
298
+ @flush_mode = (@chunk_key_time ? :lazy : :interval)
299
+ end
294
300
  end
295
301
 
296
302
  buffer_type = @buffer_config[:@type]
@@ -310,6 +316,14 @@ module Fluent
310
316
  log.warn "'flush_at_shutdown' is false, and buffer plugin '#{buf_type}' is not persistent buffer."
311
317
  log.warn "your configuration will lose buffered data at shutdown. please confirm your configuration again."
312
318
  end
319
+
320
+ if (@flush_mode != :interval) && buffer_conf.has_key?('flush_interval')
321
+ if buffer_conf.has_key?('flush_mode')
322
+ raise Fluent::ConfigError, "'flush_interval' can't be specified when 'flush_mode' is not 'interval' explicitly: '#{@flush_mode}'"
323
+ else
324
+ log.warn "'flush_interval' is ignored because default 'flush_mode' is not 'interval': '#{@flush_mode}'"
325
+ end
326
+ end
313
327
  end
314
328
 
315
329
  if @secondary_config
@@ -850,8 +864,11 @@ module Fluent
850
864
  es.each do |time, record|
851
865
  meta = metadata(tag, time, record)
852
866
  meta_and_data[meta] ||= []
853
- meta_and_data[meta] << format(tag, time, record)
854
- records += 1
867
+ res = format(tag, time, record)
868
+ if res
869
+ meta_and_data[meta] << res
870
+ records += 1
871
+ end
855
872
  end
856
873
  write_guard do
857
874
  @buffer.write(meta_and_data, enqueue: enqueue)
@@ -885,8 +902,11 @@ module Fluent
885
902
  records = 0
886
903
  data = []
887
904
  es.each do |time, record|
888
- data << format(tag, time, record)
889
- records += 1
905
+ res = format(tag, time, record)
906
+ if res
907
+ data << res
908
+ records += 1
909
+ end
890
910
  end
891
911
  else
892
912
  format_proc = generate_format_proc
@@ -14,7 +14,7 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'fluent/plugin/parser'
17
+ require 'fluent/plugin/parser_regexp'
18
18
 
19
19
  module Fluent
20
20
  module Plugin
@@ -14,7 +14,7 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'fluent/plugin/parser'
17
+ require 'fluent/plugin/parser_regexp'
18
18
 
19
19
  module Fluent
20
20
  module Plugin
@@ -15,6 +15,7 @@
15
15
  #
16
16
 
17
17
  require 'fluent/plugin/parser'
18
+ require 'fluent/plugin/parser_regexp'
18
19
 
19
20
  module Fluent
20
21
  module Plugin