fluentd 0.14.3 → 0.14.4

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.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +59 -1131
  3. data/Rakefile +15 -0
  4. data/appveyor.yml +2 -2
  5. data/example/multi_filters.conf +61 -0
  6. data/fluentd.gemspec +19 -16
  7. data/lib/fluent/agent.rb +3 -0
  8. data/lib/fluent/command/debug.rb +4 -4
  9. data/lib/fluent/compat/handle_tag_and_time_mixin.rb +2 -0
  10. data/lib/fluent/compat/output.rb +5 -2
  11. data/lib/fluent/config/configure_proxy.rb +26 -5
  12. data/lib/fluent/config/error.rb +3 -0
  13. data/lib/fluent/config/section.rb +15 -0
  14. data/lib/fluent/event_router.rb +77 -4
  15. data/lib/fluent/plugin/base.rb +12 -3
  16. data/lib/fluent/plugin/filter.rb +48 -6
  17. data/lib/fluent/plugin/filter_record_transformer.rb +3 -1
  18. data/lib/fluent/plugin/filter_stdout.rb +0 -4
  19. data/lib/fluent/plugin/in_debug_agent.rb +5 -5
  20. data/lib/fluent/plugin/in_dummy.rb +9 -1
  21. data/lib/fluent/plugin/in_forward.rb +32 -14
  22. data/lib/fluent/plugin/in_monitor_agent.rb +31 -77
  23. data/lib/fluent/plugin/in_tail.rb +37 -9
  24. data/lib/fluent/plugin/out_forward.rb +2 -13
  25. data/lib/fluent/plugin/output.rb +16 -1
  26. data/lib/fluent/plugin/storage_local.rb +16 -0
  27. data/lib/fluent/plugin_helper/timer.rb +6 -1
  28. data/lib/fluent/root_agent.rb +3 -0
  29. data/lib/fluent/supervisor.rb +62 -9
  30. data/lib/fluent/test/base.rb +3 -0
  31. data/lib/fluent/test/driver/base.rb +5 -0
  32. data/lib/fluent/test/formatter_test.rb +2 -0
  33. data/lib/fluent/test/parser_test.rb +2 -0
  34. data/lib/fluent/version.rb +1 -1
  35. data/lib/fluent/winsvc.rb +1 -2
  36. data/test/compat/test_calls_super.rb +2 -0
  37. data/test/config/test_configurable.rb +88 -0
  38. data/test/config/test_types.rb +7 -3
  39. data/test/plugin/test_filter.rb +121 -23
  40. data/test/plugin/test_filter_record_transformer.rb +22 -6
  41. data/test/plugin/test_in_debug_agent.rb +2 -2
  42. data/test/plugin/test_in_forward.rb +54 -6
  43. data/test/plugin/test_in_monitor_agent.rb +329 -0
  44. data/test/plugin/test_in_tail.rb +73 -0
  45. data/test/plugin/test_out_forward.rb +1 -0
  46. data/test/plugin/test_output.rb +53 -0
  47. data/test/plugin/test_output_as_buffered.rb +13 -0
  48. data/test/plugin/test_output_as_buffered_overflow.rb +3 -0
  49. data/test/plugin/test_output_as_buffered_retries.rb +11 -0
  50. data/test/plugin/test_output_as_buffered_secondary.rb +12 -0
  51. data/test/plugin/test_output_as_standard.rb +12 -0
  52. data/test/plugin_helper/test_compat_parameters.rb +2 -0
  53. data/test/plugin_helper/test_timer.rb +31 -0
  54. data/test/test_event_router.rb +87 -0
  55. data/test/test_filter.rb +48 -6
  56. data/test/test_log.rb +5 -2
  57. data/test/test_output.rb +41 -1
  58. data/test/test_plugin_classes.rb +17 -9
  59. data/test/test_root_agent.rb +146 -0
  60. metadata +51 -67
data/Rakefile CHANGED
@@ -7,6 +7,21 @@ require 'rake/clean'
7
7
 
8
8
  task test: [:base_test]
9
9
 
10
+ # 1. update ChangeLog and lib/fluent/version.rb
11
+ # 2. bundle && bundle exec rake build:all
12
+ # 3. release 3 packages built on pkg/ directory
13
+ namespace :build do
14
+ desc 'Build gems for all platforms'
15
+ task :all do
16
+ Bundler.with_clean_env do
17
+ %w[ruby x86-mingw32 x64-mingw32].each do |name|
18
+ ENV['GEM_BUILD_FAKE_PLATFORM'] = name
19
+ Rake::Task["build"].execute
20
+ end
21
+ end
22
+ end
23
+ end
24
+
10
25
  desc 'Run test_unit based test'
11
26
  Rake::TestTask.new(:base_test) do |t|
12
27
  # To run test for only one file (or file path pattern)
@@ -28,11 +28,11 @@ environment:
28
28
  devkit: C:\Ruby23\DevKit
29
29
  - ruby_version: "22-x64"
30
30
  devkit: C:\Ruby23-x64\DevKit
31
+ - ruby_version: "21-x64"
32
+ devkit: C:\Ruby23-x64\DevKit
31
33
  - ruby_version: "22"
32
34
  devkit: C:\Ruby23\DevKit
33
35
  WIN_RAPID: true
34
- - ruby_version: "21-x64"
35
- devkit: C:\Ruby23-x64\DevKit
36
36
  - ruby_version: "21"
37
37
  devkit: C:\Ruby23\DevKit
38
38
  WIN_RAPID: true
@@ -0,0 +1,61 @@
1
+ # This example is to measure optimized filter pipeline performance.
2
+
3
+ <source>
4
+ @type dummy
5
+ tag test
6
+ size 1000
7
+ </source>
8
+
9
+ <filter test>
10
+ @type grep
11
+ exclude1 hello .
12
+ </filter>
13
+
14
+ <filter test>
15
+ @type grep
16
+ exclude1 hello .
17
+ </filter>
18
+
19
+ <filter test>
20
+ @type grep
21
+ exclude1 hello .
22
+ </filter>
23
+
24
+ <filter test>
25
+ @type grep
26
+ exclude1 hello .
27
+ </filter>
28
+
29
+ <filter test>
30
+ @type grep
31
+ exclude1 hello .
32
+ </filter>
33
+
34
+ <filter test>
35
+ @type grep
36
+ exclude1 hello .
37
+ </filter>
38
+
39
+ <filter test>
40
+ @type grep
41
+ exclude1 hello .
42
+ </filter>
43
+
44
+ <filter test>
45
+ @type grep
46
+ exclude1 hello .
47
+ </filter>
48
+
49
+ <filter test>
50
+ @type grep
51
+ exclude1 hello .
52
+ </filter>
53
+
54
+ <filter test>
55
+ @type grep
56
+ exclude1 hello .
57
+ </filter>
58
+
59
+ <match test>
60
+ @type buffered_null
61
+ </match>
@@ -19,30 +19,33 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.required_ruby_version = '>= 2.1'
21
21
 
22
- gem.add_runtime_dependency("msgpack", [">= 0.7.0"])
23
- gem.add_runtime_dependency("json", [">= 1.4.3"])
22
+ gem.add_runtime_dependency("msgpack", [">= 0.7.0", "< 2.0.0"])
24
23
  gem.add_runtime_dependency("yajl-ruby", ["~> 1.0"])
25
- gem.add_runtime_dependency("cool.io", [">= 1.4.3", "< 2.0.0"])
26
- gem.add_runtime_dependency("serverengine", [">= 1.6.4", "< 2.0.0"])
24
+ gem.add_runtime_dependency("cool.io", ["~> 1.4.5"])
25
+ gem.add_runtime_dependency("serverengine", ["~> 2.0"])
27
26
  gem.add_runtime_dependency("http_parser.rb", [">= 0.5.1", "< 0.7.0"])
28
27
  gem.add_runtime_dependency("sigdump", ["~> 0.2.2"])
29
- gem.add_runtime_dependency("tzinfo", [">= 1.0.0"])
30
- gem.add_runtime_dependency("tzinfo-data", [">= 1.0.0"])
31
- if /mswin|mingw/ =~ RUBY_PLATFORM
28
+ gem.add_runtime_dependency("tzinfo", ["~> 1.0"])
29
+ gem.add_runtime_dependency("tzinfo-data", ["~> 1.0"])
30
+ gem.add_runtime_dependency("strptime", ["~> 0.1.7"])
31
+
32
+ # build gem for a certain platform. see also Rakefile
33
+ fake_platform = ENV['GEM_BUILD_FAKE_PLATFORM'].to_s
34
+ gem.platform = fake_platform unless fake_platform.empty?
35
+ if /mswin|mingw/ =~ fake_platform || (/mswin|mingw/ =~ RUBY_PLATFORM && fake_platform.empty?)
32
36
  gem.add_runtime_dependency("win32-service", ["~> 0.8.3"])
33
37
  gem.add_runtime_dependency("win32-ipc", ["~> 0.6.1"])
34
38
  gem.add_runtime_dependency("win32-event", ["~> 0.6.1"])
35
39
  gem.add_runtime_dependency("windows-pr", ["~> 1.2.5"])
36
40
  end
37
- gem.add_runtime_dependency("strptime", [">= 0.1.7"])
38
41
 
39
- gem.add_development_dependency("rake", [">= 0.9.2"])
40
- gem.add_development_dependency("flexmock", ["~> 2.0.5"])
41
- gem.add_development_dependency("parallel_tests", [">= 0.15.3"])
42
- gem.add_development_dependency("simplecov", ["~> 0.6.4"])
43
- gem.add_development_dependency("rr", [">= 1.0.0"])
44
- gem.add_development_dependency("timecop", [">= 0.3.0"])
45
- gem.add_development_dependency("test-unit", ["~> 3.1.4"])
46
- gem.add_development_dependency("test-unit-rr", ["~> 1.0.3"])
42
+ gem.add_development_dependency("rake", ["~> 11.0"])
43
+ gem.add_development_dependency("flexmock", ["~> 2.0"])
44
+ gem.add_development_dependency("parallel_tests", ["~> 0.15.3"])
45
+ gem.add_development_dependency("simplecov", ["~> 0.7"])
46
+ gem.add_development_dependency("rr", ["~> 1.0"])
47
+ gem.add_development_dependency("timecop", ["~> 0.3"])
48
+ gem.add_development_dependency("test-unit", ["~> 3.2"])
49
+ gem.add_development_dependency("test-unit-rr", ["~> 1.0"])
47
50
  gem.add_development_dependency("oj", ["~> 2.14"])
48
51
  end
@@ -134,6 +134,9 @@ module Fluent
134
134
  output.router = @event_router if output.respond_to?(:router=)
135
135
  output.configure(conf)
136
136
  @outputs << output
137
+ if output.respond_to?(:outputs) && (output.is_a?(Fluent::Plugin::MultiOutput) || output.is_a?(Fluent::MultiOutput))
138
+ @outputs.push(*output.outputs)
139
+ end
137
140
  @event_router.add_rule(pattern, output)
138
141
 
139
142
  output
@@ -63,6 +63,7 @@ end
63
63
  require 'fluent/log'
64
64
  require 'fluent/engine'
65
65
  require 'fluent/system_config'
66
+ require 'serverengine'
66
67
 
67
68
  include Fluent::SystemConfig::Mixin
68
69
 
@@ -90,13 +91,12 @@ include Fluent
90
91
 
91
92
  puts "Connected to #{uri}."
92
93
  puts "Usage:"
93
- puts " Engine.match('some.tag').output : get an output plugin instance"
94
- puts " Engine.sources[i] : get input plugin instances"
95
- puts " Plugin.load_plugin(type,name) : load plugin class (use this if you get DRb::DRbUnknown)"
94
+ puts " Fluent::Engine.match('some.tag').output : get an output plugin instance"
95
+ puts " Fluent::Engine.sources[i] : get input plugin instances"
96
+ puts " Fluent::Plugin.load_plugin(type,name) : load plugin class (use this if you get DRb::DRbUnknown)"
96
97
  puts ""
97
98
 
98
99
  Encoding.default_internal = nil if Encoding.respond_to?(:default_internal)
99
100
 
100
101
  require 'irb'
101
102
  IRB.start
102
-
@@ -14,6 +14,8 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
+ require 'fluent/time' # TimeFormatter
18
+
17
19
  module Fluent
18
20
  module Compat
19
21
  module HandleTagAndTimeMixin
@@ -19,8 +19,10 @@ require 'fluent/plugin/output'
19
19
  require 'fluent/plugin/bare_output'
20
20
  require 'fluent/compat/call_super_mixin'
21
21
  require 'fluent/compat/formatter_utils'
22
+ require 'fluent/compat/handle_tag_and_time_mixin'
22
23
  require 'fluent/compat/parser_utils'
23
24
  require 'fluent/compat/propagate_default'
25
+ require 'fluent/compat/record_filter_mixin'
24
26
  require 'fluent/compat/output_chain'
25
27
  require 'fluent/timezone'
26
28
  require 'fluent/mixin'
@@ -265,7 +267,7 @@ module Fluent
265
267
  conf.elements << Fluent::Config::Element.new('buffer', '', buf_params, [])
266
268
  end
267
269
 
268
- @includes_record_filter = self.class.ancestors.include?(Fluent::RecordFilterMixin) # TODO rename Compat::RecordFilterMixin
270
+ @includes_record_filter = self.class.ancestors.include?(Fluent::Compat::RecordFilterMixin)
269
271
 
270
272
  methods_of_plugin = self.class.instance_methods(false)
271
273
  @overrides_emit = methods_of_plugin.include?(:emit)
@@ -361,11 +363,12 @@ module Fluent
361
363
  end
362
364
 
363
365
  meta = metadata(nil, nil, nil)
366
+ size = es.size
364
367
  data = es.map{|time,record| format(tag, time, record) }
365
368
  write_guard do
366
369
  @buffer.write({meta => data}, enqueue: enqueue)
367
370
  end
368
- @counters_monitor.synchronize{ @emit_records += es_size }
371
+ @counters_monitor.synchronize{ @emit_records += size }
369
372
  [meta]
370
373
  end
371
374
 
@@ -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