fluentd 1.17.1-x64-mingw-ucrt → 1.18.0-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
@@ -39,7 +39,8 @@ module Fluent
39
39
  scheme = tls_context ? 'https' : 'http'
40
40
  @uri = URI("#{scheme}://#{@addr}:#{@port}").to_s
41
41
  @router = Router.new(default_app)
42
- @reactor = Async::Reactor.new(nil, logger: Fluent::Log::ConsoleAdapter.wrap(@logger))
42
+ @server_task = nil
43
+ Console.logger = Fluent::Log::ConsoleAdapter.wrap(@logger)
43
44
 
44
45
  opts = if tls_context
45
46
  { ssl_context: tls_context }
@@ -54,24 +55,35 @@ module Fluent
54
55
  end
55
56
 
56
57
  def start(notify = nil)
58
+ Console.logger = Fluent::Log::ConsoleAdapter.wrap(@logger)
57
59
  @logger.debug("Start async HTTP server listening #{@uri}")
58
- task = @reactor.run do
59
- @server.run
60
60
 
61
+ Async do |task|
62
+ Console.logger = Fluent::Log::ConsoleAdapter.wrap(@logger)
63
+ @server_task = task.async do
64
+ Console.logger = Fluent::Log::ConsoleAdapter.wrap(@logger)
65
+ @server.run
66
+ end
61
67
  if notify
62
68
  notify.push(:ready)
63
69
  end
70
+
71
+ if async_v2?
72
+ @server_task_queue = ::Thread::Queue.new
73
+ @server_task_queue.pop
74
+ @server_task&.stop
75
+ end
64
76
  end
65
77
 
66
- task.stop
67
78
  @logger.debug('Finished HTTP server')
68
79
  end
69
80
 
70
81
  def stop
71
82
  @logger.debug('closing HTTP server')
72
-
73
- if @reactor
74
- @reactor.stop
83
+ if async_v2?
84
+ @server_task_queue&.push(:stop)
85
+ else
86
+ @server_task&.stop
75
87
  end
76
88
  end
77
89
 
@@ -88,6 +100,10 @@ module Fluent
88
100
  @router.mount(name, path, app || block)
89
101
  end
90
102
  end
103
+
104
+ private def async_v2?
105
+ Gem::Version.new(Async::VERSION) >= Gem::Version.new('2.0')
106
+ end
91
107
  end
92
108
  end
93
109
  end
@@ -84,6 +84,8 @@ module Fluent
84
84
  socket_options[:linger_timeout] ||= @transport_config&.linger_timeout || 0
85
85
  end
86
86
 
87
+ socket_options[:receive_buffer_size] ||= @transport_config&.receive_buffer_size
88
+
87
89
  socket_option_validate!(proto, **socket_options)
88
90
  socket_option_setter = ->(sock){ socket_option_set(sock, **socket_options) }
89
91
 
@@ -136,6 +138,8 @@ module Fluent
136
138
  socket_options[:linger_timeout] ||= @transport_config&.linger_timeout || 0
137
139
  end
138
140
 
141
+ socket_options[:receive_buffer_size] ||= @transport_config&.receive_buffer_size
142
+
139
143
  unless socket
140
144
  socket_option_validate!(proto, **socket_options)
141
145
  socket_option_setter = ->(sock){ socket_option_set(sock, **socket_options) }
@@ -247,6 +251,7 @@ module Fluent
247
251
  :generate_cert_country, :generate_cert_state, :generate_cert_state,
248
252
  :generate_cert_locality, :generate_cert_common_name,
249
253
  :generate_cert_expiration, :generate_cert_digest,
254
+ :ensure_fips,
250
255
  ]
251
256
 
252
257
  def server_create_transport_section_object(opts)
@@ -266,6 +271,9 @@ module Fluent
266
271
 
267
272
  ### Socket Params ###
268
273
 
274
+ desc "The max size of socket receive buffer. SO_RCVBUF"
275
+ config_param :receive_buffer_size, :size, default: nil
276
+
269
277
  # SO_LINGER 0 to send RST rather than FIN to avoid lots of connections sitting in TIME_WAIT at src.
270
278
  # Set positive value if needing to send FIN on closing on non-Windows.
271
279
  # (On Windows, Fluentd can send FIN with zero `linger_timeout` since Fluentd doesn't set 0 to SO_LINGER on Windows.
@@ -287,6 +295,7 @@ module Fluent
287
295
  config_param :max_version, :enum, list: Fluent::TLS::SUPPORTED_VERSIONS, default: nil
288
296
  config_param :ciphers, :string, default: Fluent::TLS::CIPHERS_DEFAULT
289
297
  config_param :insecure, :bool, default: false
298
+ config_param :ensure_fips, :bool, default: false
290
299
 
291
300
  # Cert signed by public CA
292
301
  config_param :ca_path, :string, default: nil
@@ -22,6 +22,7 @@ require 'fluent/label'
22
22
  require 'fluent/plugin'
23
23
  require 'fluent/system_config'
24
24
  require 'fluent/time'
25
+ require 'fluent/source_only_buffer_agent'
25
26
 
26
27
  module Fluent
27
28
  #
@@ -47,24 +48,57 @@ module Fluent
47
48
  class RootAgent < Agent
48
49
  ERROR_LABEL = "@ERROR".freeze # @ERROR is built-in error label
49
50
 
50
- def initialize(log:, system_config: SystemConfig.new)
51
+ class SourceOnlyMode
52
+ DISABLED = 0
53
+ NORMAL = 1
54
+ ONLY_ZERO_DOWNTIME_RESTART_READY = 2
55
+
56
+ def initialize(with_source_only, start_in_parallel)
57
+ if start_in_parallel
58
+ @mode = ONLY_ZERO_DOWNTIME_RESTART_READY
59
+ elsif with_source_only
60
+ @mode = NORMAL
61
+ else
62
+ @mode = DISABLED
63
+ end
64
+ end
65
+
66
+ def enabled?
67
+ @mode != DISABLED
68
+ end
69
+
70
+ def only_zero_downtime_restart_ready?
71
+ @mode == ONLY_ZERO_DOWNTIME_RESTART_READY
72
+ end
73
+
74
+ def disable!
75
+ @mode = DISABLED
76
+ end
77
+ end
78
+
79
+ def initialize(log:, system_config: SystemConfig.new, start_in_parallel: false)
51
80
  super(log: log)
52
81
 
53
82
  @labels = {}
54
83
  @inputs = []
55
84
  @suppress_emit_error_log_interval = 0
56
85
  @next_emit_error_log_time = nil
57
- @without_source = false
58
- @enable_input_metrics = false
86
+ @without_source = system_config.without_source || false
87
+ @source_only_mode = SourceOnlyMode.new(system_config.with_source_only, start_in_parallel)
88
+ @source_only_buffer_agent = nil
89
+ @enable_input_metrics = system_config.enable_input_metrics || false
59
90
 
60
91
  suppress_interval(system_config.emit_error_log_interval) unless system_config.emit_error_log_interval.nil?
61
- @without_source = system_config.without_source unless system_config.without_source.nil?
62
- @enable_input_metrics = !!system_config.enable_input_metrics
63
92
  end
64
93
 
65
94
  attr_reader :inputs
66
95
  attr_reader :labels
67
96
 
97
+ def source_only_router
98
+ raise "[BUG] 'RootAgent#source_only_router' should not be called when 'with_source_only' is false" unless @source_only_mode.enabled?
99
+ @source_only_buffer_agent.event_router
100
+ end
101
+
68
102
  def configure(conf)
69
103
  used_worker_ids = []
70
104
  available_worker_ids = (0..Fluent::Engine.system_config.workers - 1).to_a
@@ -148,6 +182,8 @@ module Fluent
148
182
 
149
183
  super
150
184
 
185
+ setup_source_only_buffer_agent if @source_only_mode.enabled?
186
+
151
187
  # initialize <source> elements
152
188
  if @without_source
153
189
  log.info :worker0, "'--without-source' is applied. Ignore <source> sections"
@@ -169,16 +205,36 @@ module Fluent
169
205
  @error_collector = error_label.event_router
170
206
  end
171
207
 
172
- def lifecycle(desc: false, kind_callback: nil)
173
- kind_or_label_list = if desc
174
- [:output, :filter, @labels.values.reverse, :output_with_router, :input].flatten
175
- else
176
- [:input, :output_with_router, @labels.values, :filter, :output].flatten
177
- end
178
- kind_or_label_list.each do |kind|
208
+ def setup_source_only_buffer_agent(flush: false)
209
+ @source_only_buffer_agent = SourceOnlyBufferAgent.new(log: log, system_config: Fluent::Engine.system_config)
210
+ @source_only_buffer_agent.configure(flush: flush)
211
+ end
212
+
213
+ def cleanup_source_only_buffer_agent
214
+ @source_only_buffer_agent&.cleanup
215
+ end
216
+
217
+ def lifecycle(desc: false, kind_callback: nil, kind_or_agent_list: nil)
218
+ only_zero_downtime_restart_ready = false
219
+
220
+ unless kind_or_agent_list
221
+ if @source_only_mode.enabled?
222
+ kind_or_agent_list = [:input, @source_only_buffer_agent]
223
+ only_zero_downtime_restart_ready = @source_only_mode.only_zero_downtime_restart_ready?
224
+ elsif @source_only_buffer_agent
225
+ # source_only_buffer_agent can re-reroute events, so the priority is equal to output_with_router.
226
+ kind_or_agent_list = [:input, :output_with_router, @source_only_buffer_agent, @labels.values, :filter, :output].flatten
227
+ else
228
+ kind_or_agent_list = [:input, :output_with_router, @labels.values, :filter, :output].flatten
229
+ end
230
+
231
+ kind_or_agent_list.reverse! if desc
232
+ end
233
+
234
+ kind_or_agent_list.each do |kind|
179
235
  if kind.respond_to?(:lifecycle)
180
- label = kind
181
- label.lifecycle(desc: desc) do |plugin, display_kind|
236
+ agent = kind
237
+ agent.lifecycle(desc: desc) do |plugin, display_kind|
182
238
  yield plugin, display_kind
183
239
  end
184
240
  else
@@ -189,6 +245,9 @@ module Fluent
189
245
  end
190
246
  display_kind = (kind == :output_with_router ? :output : kind)
191
247
  list.each do |instance|
248
+ if only_zero_downtime_restart_ready
249
+ next unless instance.respond_to?(:zero_downtime_restart_ready?) and instance.zero_downtime_restart_ready?
250
+ end
192
251
  yield instance, display_kind
193
252
  end
194
253
  end
@@ -198,8 +257,8 @@ module Fluent
198
257
  end
199
258
  end
200
259
 
201
- def start
202
- lifecycle(desc: true) do |i| # instance
260
+ def start(kind_or_agent_list: nil)
261
+ lifecycle(desc: true, kind_or_agent_list: kind_or_agent_list) do |i| # instance
203
262
  i.start unless i.started?
204
263
  # Input#start sometimes emits lots of events with in_tail/`read_from_head true` case
205
264
  # and it causes deadlock for small buffer/queue output. To avoid such problem,
@@ -231,13 +290,46 @@ module Fluent
231
290
  flushing_threads.each{|t| t.join }
232
291
  end
233
292
 
234
- def shutdown # Fluentd's shutdown sequence is stop, before_shutdown, shutdown, after_shutdown, close, terminate for plugins
293
+ def cancel_source_only!
294
+ unless @source_only_mode.enabled?
295
+ log.info "do nothing for canceling with-source-only because the current mode is not with-source-only."
296
+ return
297
+ end
298
+
299
+ log.info "cancel with-source-only mode and start the other plugins"
300
+ all_plugins = [:input, :output_with_router, @labels.values, :filter, :output].flatten.reverse
301
+ start(kind_or_agent_list: all_plugins)
302
+
303
+ lifecycle_control_list[:input].each(&:event_emitter_cancel_source_only)
304
+
305
+ # Want to make sure that the source_only_router finishes all process before
306
+ # shutting down the agent.
307
+ # Strictly speaking, it would be necessary to have exclusive lock between
308
+ # EventRouter and the shutting down process of this agent.
309
+ # However, adding lock to EventRouter would worsen its performance, and
310
+ # the entire shutting down process does not care about it either.
311
+ # So, sleep here just in case.
312
+ sleep 1
313
+
314
+ shutdown(kind_or_agent_list: [@source_only_buffer_agent])
315
+ @source_only_buffer_agent = nil
316
+
317
+ # This agent can stop after flushing its all buffer, but it is not implemented for now.
318
+ log.info "starts the loading agent for with-source-only"
319
+ setup_source_only_buffer_agent(flush: true)
320
+ start(kind_or_agent_list: [@source_only_buffer_agent])
321
+
322
+ @source_only_mode.disable!
323
+ end
324
+
325
+ def shutdown(kind_or_agent_list: nil)
326
+ # Fluentd's shutdown sequence is stop, before_shutdown, shutdown, after_shutdown, close, terminate for plugins
235
327
  # These method callers does `rescue Exception` to call methods of shutdown sequence as far as possible
236
328
  # if plugin methods does something like infinite recursive call, `exit`, unregistering signal handlers or others.
237
329
  # Plugins should be separated and be in sandbox to protect data in each plugins/buffers.
238
330
 
239
331
  lifecycle_safe_sequence = ->(method, checker) {
240
- lifecycle do |instance, kind|
332
+ lifecycle(kind_or_agent_list: kind_or_agent_list) do |instance, kind|
241
333
  begin
242
334
  log.debug "calling #{method} on #{kind} plugin", type: Plugin.lookup_type_from_class(instance.class), plugin_id: instance.plugin_id
243
335
  instance.__send__(method) unless instance.__send__(checker)
@@ -260,7 +352,7 @@ module Fluent
260
352
  operation_threads.each{|t| t.join }
261
353
  operation_threads.clear
262
354
  }
263
- lifecycle(kind_callback: callback) do |instance, kind|
355
+ lifecycle(kind_callback: callback, kind_or_agent_list: kind_or_agent_list) do |instance, kind|
264
356
  t = Thread.new do
265
357
  Thread.current.abort_on_exception = true
266
358
  begin
@@ -301,6 +393,8 @@ module Fluent
301
393
  lifecycle_unsafe_sequence.call(:close, :closed?)
302
394
 
303
395
  lifecycle_safe_sequence.call(:terminate, :terminated?)
396
+
397
+ cleanup_source_only_buffer_agent unless kind_or_agent_list
304
398
  end
305
399
 
306
400
  def suppress_interval(interval_time)
@@ -318,6 +412,7 @@ module Fluent
318
412
  # See also 'fluentd/plugin/input.rb'
319
413
  input.context_router = @event_router
320
414
  input.configure(conf)
415
+ input.event_emitter_apply_source_only if @source_only_mode.enabled?
321
416
  if @enable_input_metrics
322
417
  @event_router.add_metric_callbacks(input.plugin_id, Proc.new {|es| input.metric_callback(es) })
323
418
  end
@@ -0,0 +1,102 @@
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
+ require 'fluent/agent'
18
+ require 'fluent/system_config'
19
+
20
+ module Fluent
21
+ class SourceOnlyBufferAgent < Agent
22
+ # Use INSTANCE_ID to use the same base dir as the other workers.
23
+ # This will make recovery easier.
24
+ BUFFER_DIR_NAME = Fluent::INSTANCE_ID
25
+
26
+ def initialize(log:, system_config:)
27
+ super(log: log)
28
+
29
+ @default_buffer_path = File.join(system_config.root_dir || DEFAULT_BACKUP_DIR, 'source-only-buffer', BUFFER_DIR_NAME)
30
+ @optional_buffer_config = system_config.source_only_buffer.to_h.transform_keys(&:to_s)
31
+ @base_buffer_dir = nil
32
+ @actual_buffer_dir = nil
33
+ end
34
+
35
+ def configure(flush: false)
36
+ buffer_config = @optional_buffer_config.compact
37
+ buffer_config['flush_at_shutdown'] = flush ? 'true' : 'false'
38
+ buffer_config['flush_thread_count'] = 0 unless flush
39
+ buffer_config['path'] ||= @default_buffer_path
40
+
41
+ super(
42
+ Config::Element.new('SOURCE_ONLY_BUFFER', '', {}, [
43
+ Config::Element.new('match', '**', {'@type' => 'buffer', '@label' => '@ROOT'}, [
44
+ Config::Element.new('buffer', '', buffer_config, [])
45
+ ])
46
+ ])
47
+ )
48
+
49
+ @base_buffer_dir = buffer_config['path']
50
+ # It can be "#{@base_buffer_dir}/worker#{fluentd_worker_id}/" when using multiple workers
51
+ @actual_buffer_dir = File.dirname(outputs[0].buffer.path)
52
+
53
+ unless flush
54
+ log.info "with-source-only: the emitted data will be stored in the buffer files under" +
55
+ " #{@base_buffer_dir}. You can send SIGWINCH to the supervisor process to cancel" +
56
+ " with-source-only mode and process data."
57
+ end
58
+ end
59
+
60
+ def cleanup
61
+ unless (Dir.empty?(@actual_buffer_dir) rescue true)
62
+ log.warn "some buffer files remain in #{@base_buffer_dir}." +
63
+ " Please consider recovering or saving the buffer files in the directory." +
64
+ " To recover them, you can set the buffer path manually to system config and" +
65
+ " retry, i.e., restart Fluentd with with-source-only mode and send SIGWINCH again." +
66
+ " Config Example:\n#{config_example_to_recover(@base_buffer_dir)}"
67
+ return
68
+ end
69
+
70
+ begin
71
+ FileUtils.remove_dir(@base_buffer_dir)
72
+ rescue Errno::ENOENT
73
+ # This worker doesn't need to do anything. Another worker may remove the dir first.
74
+ rescue => e
75
+ log.warn "failed to remove the buffer directory: #{@base_buffer_dir}", error: e
76
+ end
77
+ end
78
+
79
+ def emit_error_event(tag, time, record, error)
80
+ error_info = {error: error, location: (error.backtrace ? error.backtrace.first : nil), tag: tag, time: time, record: record}
81
+ log.warn "SourceOnlyBufferAgent: dump an error event:", error_info
82
+ end
83
+
84
+ def handle_emits_error(tag, es, error)
85
+ error_info = {error: error, location: (error.backtrace ? error.backtrace.first : nil), tag: tag}
86
+ log.warn "SourceOnlyBufferAgent: emit transaction failed:", error_info
87
+ log.warn_backtrace
88
+ end
89
+
90
+ private
91
+
92
+ def config_example_to_recover(path)
93
+ <<~EOC
94
+ <system>
95
+ <source_only_buffer>
96
+ path #{path}
97
+ </source_only_buffer>
98
+ </system>
99
+ EOC
100
+ end
101
+ end
102
+ end