fluentd 1.8.1-x86-mingw32 → 1.9.0-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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +14 -58
  3. data/.travis.yml +2 -17
  4. data/CHANGELOG.md +39 -0
  5. data/Gemfile +1 -4
  6. data/README.md +2 -6
  7. data/fluentd.gemspec +6 -6
  8. data/lib/fluent/command/cat.rb +1 -3
  9. data/lib/fluent/command/plugin_generator.rb +2 -1
  10. data/lib/fluent/config.rb +19 -0
  11. data/lib/fluent/config/literal_parser.rb +13 -8
  12. data/lib/fluent/config/v1_parser.rb +5 -3
  13. data/lib/fluent/engine.rb +60 -9
  14. data/lib/fluent/ext_monitor_require.rb +28 -0
  15. data/lib/fluent/load.rb +1 -1
  16. data/lib/fluent/msgpack_factory.rb +16 -4
  17. data/lib/fluent/plugin/base.rb +5 -0
  18. data/lib/fluent/plugin/buf_file.rb +10 -6
  19. data/lib/fluent/plugin/buf_file_single.rb +10 -6
  20. data/lib/fluent/plugin/buffer.rb +40 -22
  21. data/lib/fluent/plugin/buffer/chunk.rb +1 -1
  22. data/lib/fluent/plugin/in_http.rb +9 -9
  23. data/lib/fluent/plugin/in_tail.rb +8 -6
  24. data/lib/fluent/plugin/out_http.rb +2 -2
  25. data/lib/fluent/plugin/output.rb +2 -2
  26. data/lib/fluent/plugin/parser.rb +6 -0
  27. data/lib/fluent/plugin_helper/http_server.rb +0 -1
  28. data/lib/fluent/plugin_helper/record_accessor.rb +0 -8
  29. data/lib/fluent/plugin_helper/server.rb +6 -21
  30. data/lib/fluent/plugin_id.rb +9 -4
  31. data/lib/fluent/static_config_analysis.rb +194 -0
  32. data/lib/fluent/supervisor.rb +103 -28
  33. data/lib/fluent/system_config.rb +2 -1
  34. data/lib/fluent/test/driver/base.rb +4 -3
  35. data/lib/fluent/variable_store.rb +40 -0
  36. data/lib/fluent/version.rb +1 -1
  37. data/test/config/test_config_parser.rb +19 -16
  38. data/test/config/test_system_config.rb +6 -4
  39. data/test/plugin/test_in_exec.rb +9 -9
  40. data/test/plugin/test_in_forward.rb +10 -11
  41. data/test/plugin/test_in_http.rb +35 -3
  42. data/test/plugin/test_in_object_space.rb +3 -7
  43. data/test/plugin/test_out_exec_filter.rb +28 -45
  44. data/test/plugin/test_out_forward.rb +2 -2
  45. data/test/plugin/test_out_http.rb +8 -2
  46. data/test/plugin/test_output.rb +3 -3
  47. data/test/plugin/test_output_as_buffered.rb +1 -1
  48. data/test/plugin/test_output_as_buffered_overflow.rb +1 -1
  49. data/test/plugin/test_output_as_buffered_secondary.rb +2 -2
  50. data/test/plugin_helper/test_child_process.rb +45 -56
  51. data/test/plugin_helper/test_server.rb +13 -0
  52. data/test/plugin_helper/test_timer.rb +11 -13
  53. data/test/test_config.rb +27 -5
  54. data/test/test_engine.rb +203 -0
  55. data/test/test_output.rb +2 -2
  56. data/test/test_static_config_analysis.rb +177 -0
  57. data/test/test_supervisor.rb +18 -80
  58. data/test/test_test_drivers.rb +4 -3
  59. data/test/test_variable_store.rb +65 -0
  60. metadata +40 -27
  61. data/.gitlab/cicd-template.yaml +0 -10
  62. data/Vagrantfile +0 -17
@@ -0,0 +1,28 @@
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
+ # To avoid duplicated requirements, extract this logic as file.
18
+
19
+ if Gem::Version.create(RUBY_VERSION) >= Gem::Version.create('2.7.0')
20
+ require 'monitor'
21
+ else
22
+ begin
23
+ # monitor_ext is bundled since ruby 2.7.0
24
+ require 'ext_monitor'
25
+ rescue LoadError => _
26
+ require 'monitor'
27
+ end
28
+ end
@@ -2,7 +2,6 @@ require 'thread'
2
2
  require 'socket'
3
3
  require 'fcntl'
4
4
  require 'time'
5
- require 'monitor'
6
5
  require 'stringio'
7
6
  require 'fileutils'
8
7
  require 'json'
@@ -33,3 +32,4 @@ require 'fluent/input'
33
32
  require 'fluent/output'
34
33
  require 'fluent/filter'
35
34
  require 'fluent/match'
35
+ require 'fluent/ext_monitor_require'
@@ -44,8 +44,8 @@ module Fluent
44
44
  end
45
45
  end
46
46
 
47
- def self.engine_factory
48
- @@engine_factory || factory
47
+ def self.engine_factory(enable_time_support: false)
48
+ @@engine_factory || factory(enable_time_support: enable_time_support)
49
49
  end
50
50
 
51
51
  def self.msgpack_packer(*args)
@@ -56,9 +56,15 @@ module Fluent
56
56
  engine_factory.unpacker(*args)
57
57
  end
58
58
 
59
- def self.factory
59
+ def self.factory(enable_time_support: false)
60
60
  factory = MessagePack::Factory.new
61
61
  factory.register_type(Fluent::EventTime::TYPE, Fluent::EventTime)
62
+ if enable_time_support
63
+ factory.register_type(
64
+ MessagePack::Timestamp::TYPE, Time,
65
+ packer: MessagePack::Time::Packer,
66
+ unpacker: MessagePack::Time::Unpacker)
67
+ end
62
68
  factory
63
69
  end
64
70
 
@@ -70,9 +76,15 @@ module Fluent
70
76
  factory.unpacker(*args)
71
77
  end
72
78
 
73
- def self.init
79
+ def self.init(enable_time_support: false)
74
80
  factory = MessagePack::Factory.new
75
81
  factory.register_type(Fluent::EventTime::TYPE, Fluent::EventTime)
82
+ if enable_time_support
83
+ factory.register_type(
84
+ MessagePack::Timestamp::TYPE, Time,
85
+ packer: MessagePack::Time::Packer,
86
+ unpacker: MessagePack::Time::Unpacker)
87
+ end
76
88
  @@engine_factory = factory
77
89
  end
78
90
 
@@ -187,6 +187,11 @@ module Fluent
187
187
  # https://github.com/ruby/ruby/blob/trunk/gc.c#L788
188
188
  "#<%s:%014x>" % [self.class.name, '0x%014x' % (__id__ << 1)]
189
189
  end
190
+
191
+ def reloadable_plugin?
192
+ # Engine can't capture all class variables. so it's forbbiden to use class variables in each plugins if enabling reload.
193
+ self.class.class_variables.empty?
194
+ end
190
195
  end
191
196
  end
192
197
  end
@@ -19,6 +19,7 @@ require 'fileutils'
19
19
  require 'fluent/plugin/buffer'
20
20
  require 'fluent/plugin/buffer/file_chunk'
21
21
  require 'fluent/system_config'
22
+ require 'fluent/variable_store'
22
23
 
23
24
  module Fluent
24
25
  module Plugin
@@ -43,19 +44,20 @@ module Fluent
43
44
  config_param :file_permission, :string, default: nil # '0644'
44
45
  config_param :dir_permission, :string, default: nil # '0755'
45
46
 
46
- @@buffer_paths = {}
47
-
48
47
  def initialize
49
48
  super
50
49
  @symlink_path = nil
51
50
  @multi_workers_available = false
52
51
  @additional_resume_path = nil
53
52
  @buffer_path = nil
53
+ @variable_store = nil
54
54
  end
55
55
 
56
56
  def configure(conf)
57
57
  super
58
58
 
59
+ @variable_store = Fluent::VariableStore.fetch_or_build(:buf_file)
60
+
59
61
  multi_workers_configured = owner.system_config.workers > 1 ? true : false
60
62
 
61
63
  using_plugin_root_dir = false
@@ -69,13 +71,13 @@ module Fluent
69
71
  end
70
72
 
71
73
  type_of_owner = Plugin.lookup_type_from_class(@_owner.class)
72
- if @@buffer_paths.has_key?(@path) && !called_in_test?
73
- type_using_this_path = @@buffer_paths[@path]
74
+ if @variable_store.has_key?(@path) && !called_in_test?
75
+ type_using_this_path = @variable_store[@path]
74
76
  raise ConfigError, "Other '#{type_using_this_path}' plugin already use same buffer path: type = #{type_of_owner}, buffer path = #{@path}"
75
77
  end
76
78
 
77
79
  @buffer_path = @path
78
- @@buffer_paths[@buffer_path] = type_of_owner
80
+ @variable_store[@buffer_path] = type_of_owner
79
81
 
80
82
  specified_directory_exists = File.exist?(@path) && File.directory?(@path)
81
83
  unexisting_path_for_directory = !File.exist?(@path) && !@path.include?('.*')
@@ -125,7 +127,9 @@ module Fluent
125
127
  end
126
128
 
127
129
  def stop
128
- @@buffer_paths.delete(@buffer_path)
130
+ if @variable_store
131
+ @variable_store.delete(@buffer_path)
132
+ end
129
133
 
130
134
  super
131
135
  end
@@ -19,6 +19,7 @@ require 'fileutils'
19
19
  require 'fluent/plugin/buffer'
20
20
  require 'fluent/plugin/buffer/file_single_chunk'
21
21
  require 'fluent/system_config'
22
+ require 'fluent/variable_store'
22
23
 
23
24
  module Fluent
24
25
  module Plugin
@@ -48,18 +49,19 @@ module Fluent
48
49
  desc 'The permission of chunk directory. If no specified, <system> setting or 0755 is used'
49
50
  config_param :dir_permission, :string, default: nil
50
51
 
51
- @@buffer_paths = {}
52
-
53
52
  def initialize
54
53
  super
55
54
 
56
55
  @multi_workers_available = false
57
56
  @additional_resume_path = nil
57
+ @variable_store = nil
58
58
  end
59
59
 
60
60
  def configure(conf)
61
61
  super
62
62
 
63
+ @variable_store = Fluent::VariableStore.fetch_or_build(:buf_file_single)
64
+
63
65
  if @chunk_format == :auto
64
66
  @chunk_format = owner.formatted_to_msgpack_binary? ? :msgpack : :text
65
67
  end
@@ -117,12 +119,12 @@ module Fluent
117
119
  end
118
120
 
119
121
  type_of_owner = Plugin.lookup_type_from_class(@_owner.class)
120
- if @@buffer_paths.has_key?(@path) && !called_in_test?
121
- type_using_this_path = @@buffer_paths[@path]
122
+ if @variable_store.has_key?(@path) && !called_in_test?
123
+ type_using_this_path = @variable_store[@path]
122
124
  raise Fluent::ConfigError, "Other '#{type_using_this_path}' plugin already uses same buffer path: type = #{type_of_owner}, buffer path = #{@path}"
123
125
  end
124
126
 
125
- @@buffer_paths[@path] = type_of_owner
127
+ @variable_store[@path] = type_of_owner
126
128
  @dir_permission = if @dir_permission
127
129
  @dir_permission.to_i(8)
128
130
  else
@@ -145,7 +147,9 @@ module Fluent
145
147
  end
146
148
 
147
149
  def stop
148
- @@buffer_paths.delete(@path)
150
+ if @variable_store
151
+ @variable_store.delete(@path)
152
+ end
149
153
 
150
154
  super
151
155
  end
@@ -17,8 +17,7 @@
17
17
  require 'fluent/plugin/base'
18
18
  require 'fluent/plugin/owned_by_mixin'
19
19
  require 'fluent/unique_id'
20
-
21
- require 'monitor'
20
+ require 'fluent/ext_monitor_require'
22
21
 
23
22
  module Fluent
24
23
  module Plugin
@@ -139,9 +138,12 @@ module Fluent
139
138
  # Actually this overhead is very small but this class is generated *per chunk* (and used in hash object).
140
139
  # This means that this class is one of the most called object in Fluentd.
141
140
  # See https://github.com/fluent/fluentd/pull/2560
141
+ # But, this optimization has a side effect on Windows due to differing object_id.
142
+ # This difference causes flood of buffer files.
143
+ # So, this optimization should be enabled on non-Windows platform.
142
144
  def hash
143
145
  timekey.object_id
144
- end
146
+ end unless Fluent.windows?
145
147
  end
146
148
 
147
149
  # for tests
@@ -266,10 +268,10 @@ module Fluent
266
268
 
267
269
  log.on_trace { log.trace "writing events into buffer", instance: self.object_id, metadata_size: metadata_and_data.size }
268
270
 
269
- staged_bytesize = 0
270
271
  operated_chunks = []
271
272
  unstaged_chunks = {} # metadata => [chunk, chunk, ...]
272
273
  chunks_to_enqueue = []
274
+ staged_bytesizes_by_chunk = {}
273
275
 
274
276
  begin
275
277
  # sort metadata to get lock of chunks in same order with other threads
@@ -279,7 +281,13 @@ module Fluent
279
281
  chunk.mon_enter # add lock to prevent to be committed/rollbacked from other threads
280
282
  operated_chunks << chunk
281
283
  if chunk.staged?
282
- staged_bytesize += adding_bytesize
284
+ #
285
+ # https://github.com/fluent/fluentd/issues/2712
286
+ # write_once is supposed to write to a chunk only once
287
+ # but this block **may** run multiple times from write_step_by_step and previous write may be rollbacked
288
+ # So we should be counting the stage_size only for the last successful write
289
+ #
290
+ staged_bytesizes_by_chunk[chunk] = adding_bytesize
283
291
  elsif chunk.unstaged?
284
292
  unstaged_chunks[metadata] ||= []
285
293
  unstaged_chunks[metadata] << chunk
@@ -326,27 +334,37 @@ module Fluent
326
334
 
327
335
  # All locks about chunks are released.
328
336
 
329
- synchronize do
330
- # At here, staged chunks may be enqueued by other threads.
331
- @stage_size += staged_bytesize
332
-
333
- chunks_to_enqueue.each do |c|
334
- if c.staged? && (enqueue || chunk_size_full?(c))
335
- m = c.metadata
336
- enqueue_chunk(m)
337
- if unstaged_chunks[m]
338
- u = unstaged_chunks[m].pop
337
+ #
338
+ # Now update the stage, stage_size with proper locking
339
+ # FIX FOR stage_size miscomputation - https://github.com/fluent/fluentd/issues/2712
340
+ #
341
+ staged_bytesizes_by_chunk.each do |chunk, bytesize|
342
+ chunk.synchronize do
343
+ synchronize { @stage_size += bytesize }
344
+ log.on_trace { log.trace { "chunk #{chunk.path} size_added: #{bytesize} new_size: #{chunk.bytesize}" } }
345
+ end
346
+ end
347
+
348
+ chunks_to_enqueue.each do |c|
349
+ if c.staged? && (enqueue || chunk_size_full?(c))
350
+ m = c.metadata
351
+ enqueue_chunk(m)
352
+ if unstaged_chunks[m]
353
+ u = unstaged_chunks[m].pop
354
+ u.synchronize do
339
355
  if u.unstaged? && !chunk_size_full?(u)
340
- @stage[m] = u.staged!
341
- @stage_size += u.bytesize
356
+ synchronize {
357
+ @stage[m] = u.staged!
358
+ @stage_size += u.bytesize
359
+ }
342
360
  end
343
361
  end
344
- elsif c.unstaged?
345
- enqueue_unstaged_chunk(c)
346
- else
347
- # previously staged chunk is already enqueued, closed or purged.
348
- # no problem.
349
362
  end
363
+ elsif c.unstaged?
364
+ enqueue_unstaged_chunk(c)
365
+ else
366
+ # previously staged chunk is already enqueued, closed or purged.
367
+ # no problem.
350
368
  end
351
369
  end
352
370
 
@@ -18,8 +18,8 @@ require 'fluent/plugin/buffer'
18
18
  require 'fluent/plugin/compressable'
19
19
  require 'fluent/unique_id'
20
20
  require 'fluent/event'
21
+ require 'fluent/ext_monitor_require'
21
22
 
22
- require 'monitor'
23
23
  require 'tempfile'
24
24
  require 'zlib'
25
25
 
@@ -331,29 +331,29 @@ module Fluent::Plugin
331
331
  headers.each_pair {|k,v|
332
332
  @env["HTTP_#{k.gsub('-','_').upcase}"] = v
333
333
  case k
334
- when /Expect/i
334
+ when /\AExpect\z/i
335
335
  expect = v
336
- when /Content-Length/i
336
+ when /\AContent-Length\Z/i
337
337
  size = v.to_i
338
- when /Content-Type/i
338
+ when /\AContent-Type\Z/i
339
339
  @content_type = v
340
- when /Content-Encoding/i
340
+ when /\AContent-Encoding\Z/i
341
341
  @content_encoding = v
342
- when /Connection/i
342
+ when /\AConnection\Z/i
343
343
  if v =~ /close/i
344
344
  @keep_alive = false
345
345
  elsif v =~ /Keep-alive/i
346
346
  @keep_alive = true
347
347
  end
348
- when /Origin/i
348
+ when /\AOrigin\Z/i
349
349
  @origin = v
350
- when /X-Forwarded-For/i
350
+ when /\AX-Forwarded-For\Z/i
351
351
  # For multiple X-Forwarded-For headers. Use first header value.
352
352
  v = v.first if v.is_a?(Array)
353
353
  @remote_addr = v.split(",").first
354
- when /Access-Control-Request-Method/i
354
+ when /\AAccess-Control-Request-Method\Z/i
355
355
  @access_control_request_method = v
356
- when /Access-Control-Request-Headers/i
356
+ when /\AAccess-Control-Request-Headers\Z/i
357
357
  @access_control_request_headers = v
358
358
  end
359
359
  }
@@ -21,6 +21,7 @@ require 'fluent/config/error'
21
21
  require 'fluent/event'
22
22
  require 'fluent/plugin/buffer'
23
23
  require 'fluent/plugin/parser_multiline'
24
+ require 'fluent/variable_store'
24
25
 
25
26
  if Fluent.windows?
26
27
  require_relative 'file_wrapper'
@@ -105,9 +106,8 @@ module Fluent::Plugin
105
106
 
106
107
  attr_reader :paths
107
108
 
108
- @@pos_file_paths = {}
109
-
110
109
  def configure(conf)
110
+ @variable_store = Fluent::VariableStore.fetch_or_build(:in_tail)
111
111
  compat_parameters_convert(conf, :parser)
112
112
  parser_config = conf.elements('parse').first
113
113
  unless parser_config
@@ -139,11 +139,11 @@ module Fluent::Plugin
139
139
 
140
140
  # TODO: Use plugin_root_dir and storage plugin to store positions if available
141
141
  if @pos_file
142
- if @@pos_file_paths.has_key?(@pos_file) && !called_in_test?
143
- plugin_id_using_this_path = @@pos_file_paths[@pos_file]
142
+ if @variable_store.key?(@pos_file) && !called_in_test?
143
+ plugin_id_using_this_path = @variable_store[@pos_file]
144
144
  raise Fluent::ConfigError, "Other 'in_tail' plugin already use same pos_file path: plugin_id = #{plugin_id_using_this_path}, pos_file path = #{@pos_file}"
145
145
  end
146
- @@pos_file_paths[@pos_file] = self.plugin_id
146
+ @variable_store[@pos_file] = self.plugin_id
147
147
  else
148
148
  $log.warn "'pos_file PATH' parameter is not set to a 'tail' source."
149
149
  $log.warn "this parameter is highly recommended to save the position to resume tailing."
@@ -212,7 +212,9 @@ module Fluent::Plugin
212
212
  end
213
213
 
214
214
  def stop
215
- @@pos_file_paths.delete(@pos_file)
215
+ if @variable_store
216
+ @variable_store.delete(@pos_file)
217
+ end
216
218
 
217
219
  super
218
220
  end
@@ -212,9 +212,9 @@ module Fluent::Plugin
212
212
  end
213
213
 
214
214
  if res.is_a?(Net::HTTPSuccess)
215
- log.debug { "#{res.code} #{res.message}#{res.body}" }
215
+ log.debug { "#{res.code} #{res.message.rstrip}#{res.body.lstrip}" }
216
216
  else
217
- msg = "#{res.code} #{res.message}#{res.body}"
217
+ msg = "#{res.code} #{res.message.rstrip} #{res.body.lstrip}"
218
218
 
219
219
  if @retryable_response_codes.include?(res.code.to_i)
220
220
  raise RetryableResponse, msg
@@ -25,9 +25,9 @@ require 'fluent/plugin_helper'
25
25
  require 'fluent/timezone'
26
26
  require 'fluent/unique_id'
27
27
  require 'fluent/clock'
28
+ require 'fluent/ext_monitor_require'
28
29
 
29
30
  require 'time'
30
- require 'monitor'
31
31
 
32
32
  module Fluent
33
33
  module Plugin
@@ -387,7 +387,7 @@ module Fluent
387
387
  @secondary.acts_as_secondary(self)
388
388
  @secondary.configure(secondary_conf)
389
389
  if (self.class != @secondary.class) && (@custom_format || @secondary.implement?(:custom_format))
390
- log.warn "secondary type should be same with primary one", primary: self.class.to_s, secondary: @secondary.class.to_s
390
+ log.warn "Use different plugin for secondary. Check the plugin works with primary like secondary_file", primary: self.class.to_s, secondary: @secondary.class.to_s
391
391
  end
392
392
  else
393
393
  @secondary = nil
@@ -105,6 +105,12 @@ module Fluent
105
105
  :text_per_line
106
106
  end
107
107
 
108
+ def initialize
109
+ super
110
+
111
+ @timeout_checker = nil
112
+ end
113
+
108
114
  def configure(conf)
109
115
  super
110
116