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
@@ -208,6 +208,12 @@ module Fluent
208
208
  end
209
209
  end
210
210
 
211
+ def option_value_type!(name, opts, key, klass)
212
+ if opts.has_key?(key) && !opts[key].is_a?(klass)
213
+ raise ArgumentError, "#{name}: #{key} must be a #{klass}, but #{opts[key].class}"
214
+ end
215
+ end
216
+
211
217
  def parameter_configuration(name, type = nil, **kwargs, &block)
212
218
  name = name.to_sym
213
219
 
@@ -216,7 +222,7 @@ module Fluent
216
222
  opts.merge!(kwargs)
217
223
 
218
224
  if block && type
219
- raise ArgumentError, "#{self.name}: both of block and type cannot be specified"
225
+ raise ArgumentError, "#{name}: both of block and type cannot be specified"
220
226
  end
221
227
 
222
228
  begin
@@ -224,8 +230,19 @@ module Fluent
224
230
  block ||= @type_lookup.call(type)
225
231
  rescue ConfigError
226
232
  # override error message
227
- raise ArgumentError, "#{self.name}: unknown config_argument type `#{type}'"
233
+ raise ArgumentError, "#{name}: unknown config_argument type `#{type}'"
234
+ end
235
+
236
+ option_value_type!(name, opts, :desc, String)
237
+ option_value_type!(name, opts, :alias, Symbol)
238
+ option_value_type!(name, opts, :deprecated, String)
239
+ option_value_type!(name, opts, :obsoleted, String)
240
+ if type == :enum
241
+ if !opts.has_key?(:list) || !opts[:list].all?{|v| v.is_a?(Symbol) }
242
+ raise ArgumentError, "#{name}: enum parameter requires :list of Symbols"
243
+ end
228
244
  end
245
+ option_value_type!(name, opts, :value_type, Symbol) # hash, array
229
246
 
230
247
  if opts.has_key?(:default)
231
248
  config_set_default(name, opts[:default])
@@ -235,6 +252,10 @@ module Fluent
235
252
  config_set_desc(name, opts[:desc])
236
253
  end
237
254
 
255
+ if opts[:deprecated] && opts[:obsoleted]
256
+ raise ArgumentError, "#{name}: both of deprecated and obsoleted cannot be specified at once"
257
+ end
258
+
238
259
  [name, block, opts]
239
260
  end
240
261
 
@@ -296,7 +317,7 @@ module Fluent
296
317
 
297
318
  def config_section(name, **kwargs, &block)
298
319
  unless block_given?
299
- raise ArgumentError, "#{self.name}: config_section requires block parameter"
320
+ raise ArgumentError, "#{name}: config_section requires block parameter"
300
321
  end
301
322
  name = name.to_sym
302
323
 
@@ -305,10 +326,10 @@ module Fluent
305
326
 
306
327
  if sub_proxy.init?
307
328
  if sub_proxy.argument && !sub_proxy.defaults.has_key?(sub_proxy.argument.first)
308
- raise ArgumentError, "#{self.name}: init is specified, but default value of argument is missing"
329
+ raise ArgumentError, "#{name}: init is specified, but default value of argument is missing"
309
330
  end
310
331
  if sub_proxy.params.keys.any?{|param_name| !sub_proxy.defaults.has_key?(param_name)}
311
- raise ArgumentError, "#{self.name}: init is specified, but there're parameters without default values"
332
+ raise ArgumentError, "#{name}: init is specified, but there're parameters without default values"
312
333
  end
313
334
  end
314
335
 
@@ -20,4 +20,7 @@ module Fluent
20
20
 
21
21
  class ConfigParseError < ConfigError
22
22
  end
23
+
24
+ class ObsoletedParameterError < ConfigError
25
+ end
23
26
  end
@@ -126,6 +126,7 @@ module Fluent
126
126
  logger.error "config error in:\n#{conf}" if logger # logger should exist, but somethimes it's nil (e.g, in tests)
127
127
  raise ConfigError, "'<#{proxy.name} ARG>' section requires argument" + section_stack
128
128
  end
129
+ # argument should NOT be deprecated... (argument always has a value: '')
129
130
  end
130
131
 
131
132
  proxy.params.each_pair do |name, defval|
@@ -138,6 +139,20 @@ module Fluent
138
139
  conf[opts[:alias].to_s]
139
140
  end
140
141
  section_params[varname] = self.instance_exec(val, opts, name, &block)
142
+
143
+ # Source of definitions of deprecated/obsoleted:
144
+ # https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Deprecated_and_obsolete_features
145
+ #
146
+ # Deprecated: These deprecated features can still be used, but should be used with caution
147
+ # because they are expected to be removed entirely sometime in the future.
148
+ # Obsoleted: These obsolete features have been entirely removed from JavaScript and can no longer be used.
149
+ if opts[:deprecated]
150
+ logger.warn "'#{name}' parameter is deprecated: #{opts[:deprecated]}"
151
+ end
152
+ if opts[:obsoleted]
153
+ logger.error "config error in:\n#{conf}" if logger
154
+ raise ObsoletedParameterError, "'#{name}' parameter is already removed: #{opts[:obsoleted]}" + section_stack
155
+ end
141
156
  end
142
157
  unless section_params.has_key?(varname)
143
158
  logger.error "config error in:\n#{conf}" if logger
@@ -136,10 +136,12 @@ module Fluent
136
136
  def initialize
137
137
  @filters = []
138
138
  @output = nil
139
+ @optimizer = FilterOptimizer.new
139
140
  end
140
141
 
141
142
  def add_filter(filter)
142
143
  @filters << filter
144
+ @optimizer.filters = @filters
143
145
  end
144
146
 
145
147
  def set_output(output)
@@ -147,12 +149,83 @@ module Fluent
147
149
  end
148
150
 
149
151
  def emit_events(tag, es)
150
- processed = es
151
- @filters.each { |filter|
152
- processed = filter.filter_stream(tag, processed)
153
- }
152
+ processed = @optimizer.filter_stream(tag, es)
154
153
  @output.emit_events(tag, processed)
155
154
  end
155
+
156
+ class FilterOptimizer
157
+ def initialize(filters = [])
158
+ @filters = filters
159
+ @optimizable = nil
160
+ end
161
+
162
+ def filters=(filters)
163
+ @filters = filters
164
+ reset_optimization
165
+ end
166
+
167
+ def filter_stream(tag, es)
168
+ if optimizable?
169
+ optimized_filter_stream(tag, es)
170
+ else
171
+ @filters.reduce(es) { |acc, filter| filter.filter_stream(tag, acc) }
172
+ end
173
+ end
174
+
175
+ private
176
+
177
+ def optimized_filter_stream(tag, es)
178
+ new_es = MultiEventStream.new
179
+ es.each do |time, record|
180
+ filtered_record = record
181
+ filtered_time = time
182
+
183
+ catch :break_loop do
184
+ @filters.each do |filter|
185
+ if filter.has_filter_with_time
186
+ begin
187
+ filtered_time, filtered_record = filter.filter_with_time(tag, filtered_time, filtered_record)
188
+ throw :break_loop unless filtered_record && filtered_time
189
+ rescue => e
190
+ filter.router.emit_error_event(tag, filtered_time, filtered_record, e)
191
+ end
192
+ else
193
+ begin
194
+ filtered_record = filter.filter(tag, filtered_time, filtered_record)
195
+ throw :break_loop unless filtered_record
196
+ rescue => e
197
+ filter.router.emit_error_event(tag, filtered_time, filtered_record, e)
198
+ end
199
+ end
200
+ end
201
+
202
+ new_es.add(filtered_time, filtered_record)
203
+ end
204
+ end
205
+ new_es
206
+ end
207
+
208
+ def optimizable?
209
+ return @optimizable unless @optimizable.nil?
210
+ @optimizable = if filters_having_filter_stream.empty?
211
+ true
212
+ else
213
+ $log.info "Filtering works with worse performance, because #{filters_having_filter_stream.map(&:class)} uses `#filter_stream` method."
214
+ false
215
+ end
216
+ end
217
+
218
+ def filters_having_filter_stream
219
+ @filters_having_filter_stream ||= @filters.select do |filter|
220
+ filter.class.instance_methods(false).include?(:filter_stream)
221
+ end
222
+ end
223
+
224
+ def reset_optimization
225
+ @optimizable = nil
226
+ @filters_having_filter_stream = nil
227
+ end
228
+ end
156
229
  end
157
230
 
158
231
  def find(tag)
@@ -24,11 +24,11 @@ module Fluent
24
24
  include Configurable
25
25
  include SystemConfig::Mixin
26
26
 
27
- State = Struct.new(:configure, :start, :stop, :before_shutdown, :shutdown, :after_shutdown, :close, :terminate)
27
+ State = Struct.new(:configure, :start, :after_start, :stop, :before_shutdown, :shutdown, :after_shutdown, :close, :terminate)
28
28
 
29
29
  def initialize
30
30
  super
31
- @_state = State.new(false, false, false, false, false, false, false, false)
31
+ @_state = State.new(false, false, false, false, false, false, false, false, false)
32
32
  end
33
33
 
34
34
  def has_router?
@@ -37,7 +37,7 @@ module Fluent
37
37
 
38
38
  def configure(conf)
39
39
  super
40
- @_state ||= State.new(false, false, false, false, false, false, false, false)
40
+ @_state ||= State.new(false, false, false, false, false, false, false, false, false)
41
41
  @_state.configure = true
42
42
  self
43
43
  end
@@ -47,6 +47,11 @@ module Fluent
47
47
  self
48
48
  end
49
49
 
50
+ def after_start
51
+ @_state.after_start = true
52
+ self
53
+ end
54
+
50
55
  def stop
51
56
  @_state.stop = true
52
57
  self
@@ -85,6 +90,10 @@ module Fluent
85
90
  @_state.start
86
91
  end
87
92
 
93
+ def after_started?
94
+ @_state.after_start
95
+ end
96
+
88
97
  def stopped?
89
98
  @_state.stop
90
99
  end
@@ -55,7 +55,11 @@ module Fluent
55
55
  # if chunk size (or records) is 95% or more after #write, then that chunk will be enqueued
56
56
  config_param :chunk_full_threshold, :float, default: DEFAULT_CHUNK_FULL_THRESHOLD
57
57
 
58
- Metadata = Struct.new(:timekey, :tag, :variables)
58
+ Metadata = Struct.new(:timekey, :tag, :variables) do
59
+ def empty?
60
+ timekey.nil? && tag.nil? && variables.nil?
61
+ end
62
+ end
59
63
 
60
64
  # for tests
61
65
  attr_accessor :stage_size, :queue_size
@@ -30,22 +30,64 @@ module Fluent
30
30
 
31
31
  helpers :event_emitter
32
32
 
33
+ attr_reader :has_filter_with_time
34
+
35
+ def initialize
36
+ super
37
+ @has_filter_with_time = has_filter_with_time?
38
+ end
39
+
33
40
  def filter(tag, time, record)
34
41
  raise NotImplementedError, "BUG: filter plugins MUST implement this method"
35
42
  end
36
43
 
44
+ def filter_with_time(tag, time, record)
45
+ raise NotImplementedError, "BUG: filter plugins MUST implement this method"
46
+ end
47
+
37
48
  def filter_stream(tag, es)
38
49
  new_es = MultiEventStream.new
39
- es.each do |time, record|
40
- begin
41
- filtered_record = filter(tag, time, record)
42
- new_es.add(time, filtered_record) if filtered_record
43
- rescue => e
44
- router.emit_error_event(tag, time, record, e)
50
+ if @has_filter_with_time
51
+ es.each do |time, record|
52
+ begin
53
+ filtered_time, filtered_record = filter_with_time(tag, time, record)
54
+ new_es.add(filtered_time, filtered_record) if filtered_time && filtered_record
55
+ rescue => e
56
+ router.emit_error_event(tag, time, record, e)
57
+ end
58
+ end
59
+ else
60
+ es.each do |time, record|
61
+ begin
62
+ filtered_record = filter(tag, time, record)
63
+ new_es.add(time, filtered_record) if filtered_record
64
+ rescue => e
65
+ router.emit_error_event(tag, time, record, e)
66
+ end
45
67
  end
46
68
  end
47
69
  new_es
48
70
  end
71
+
72
+ private
73
+
74
+ def has_filter_with_time?
75
+ implmented_methods = self.class.instance_methods(false)
76
+ # Plugins that override `filter_stream` don't need check,
77
+ # because they may not call `filter` or `filter_with_time`
78
+ # for example fluentd/lib/fluent/plugin/filter_record_transformer.rb
79
+ return nil if implmented_methods.include?(:filter_stream)
80
+ case
81
+ when [:filter, :filter_with_time].all? { |e| implmented_methods.include?(e) }
82
+ raise "BUG: Filter plugins MUST be implemented either `filter` or `filter_with_time`"
83
+ when implmented_methods.include?(:filter)
84
+ false
85
+ when implmented_methods.include?(:filter_with_time)
86
+ true
87
+ else
88
+ raise NotImplementedError, "BUG: Filter plugins MUST be implmented either `filter` or `filter_with_time`"
89
+ end
90
+ end
49
91
  end
50
92
  end
51
93
  end
@@ -204,7 +204,9 @@ module Fluent::Plugin
204
204
  end
205
205
  elsif value.kind_of?(Hash) # record, etc
206
206
  value.each do |k, v|
207
- placeholders.store("${#{k}}", v) # foo
207
+ unless placeholder_values.has_key?(k) # prevent overwriting reserved keys such as tag
208
+ placeholders.store("${#{k}}", v) # foo
209
+ end
208
210
  placeholders.store(%Q[${#{key}["#{k}"]}], v) # record["foo"]
209
211
  end
210
212
  else # string, interger, float, and others?
@@ -34,11 +34,7 @@ module Fluent::Plugin
34
34
  def configure(conf)
35
35
  compat_parameters_convert(conf, :inject, :formatter)
36
36
  super
37
- end
38
-
39
- def start
40
37
  @formatter = formatter_create(conf: @config.elements('format').first, default_type: DEFAULT_FORMAT_TYPE)
41
- super
42
38
  end
43
39
 
44
40
  def filter_stream(tag, es)
@@ -14,11 +14,11 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
- require 'fluent/input'
17
+ require 'fluent/plugin/input'
18
18
 
19
- module Fluent
19
+ module Fluent::Plugin
20
20
  class DebugAgentInput < Input
21
- Plugin.register_input('debug_agent', self)
21
+ Fluent::Plugin.register_input('debug_agent', self)
22
22
 
23
23
  def initialize
24
24
  require 'drb/drb'
@@ -30,13 +30,13 @@ module Fluent
30
30
  config_param :port, :integer, default: 24230
31
31
  config_param :unix_path, :string, default: nil
32
32
  #config_param :unix_mode # TODO
33
- config_param :object, :string, default: 'Engine'
33
+ config_param :object, :string, default: 'Fluent::Engine'
34
34
 
35
35
  def configure(conf)
36
36
  super
37
37
  if @unix_path
38
38
  unless ::Fluent::FileUtil.writable?(@unix_path)
39
- raise ConfigError, "in_debug_agent: `#{@unix_path}` is not writable"
39
+ raise Fluent::ConfigError, "in_debug_agent: `#{@unix_path}` is not writable"
40
40
  end
41
41
  end
42
42
  end
@@ -30,6 +30,8 @@ module Fluent::Plugin
30
30
 
31
31
  desc "The value is the tag assigned to the generated events."
32
32
  config_param :tag, :string
33
+ desc "The number of events in event stream of each emits."
34
+ config_param :size, :integer, default: 1
33
35
  desc "It configures how many events to generate per second."
34
36
  config_param :rate, :integer, default: 1
35
37
  desc "If specified, each generated event has an auto-incremented key field."
@@ -97,7 +99,13 @@ module Fluent::Plugin
97
99
 
98
100
  def emit(num)
99
101
  begin
100
- num.times { router.emit(@tag, Fluent::Engine.now, generate()) }
102
+ if @size > 1
103
+ num.times do
104
+ router.emit_array(@tag, Array.new(@size) { [Fluent::Engine.now, generate] })
105
+ end
106
+ else
107
+ num.times { router.emit(@tag, Fluent::Engine.now, generate) }
108
+ end
101
109
  rescue => _
102
110
  # ignore all errors not to stop emits by emit errors
103
111
  end