fluent-plugin-input-opensearch 1.1.9 → 1.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52ccf524b6427d6a8191410da0ed878ed988ac91881ad741d1b9464356ebdb0a
4
- data.tar.gz: 0da3d50a8c427537fd307fabc5400775d4c26bb0e8eda131fd7eb4b89174c249
3
+ metadata.gz: 54b8f74f2ddc4993a1d2324bcd8fec593e3958df7bd7d943db6b824e5b905300
4
+ data.tar.gz: ee5883d73b68960ccf5222aff8ac2d11d1a14d39a90c8c969f72931c8063316d
5
5
  SHA512:
6
- metadata.gz: 849df809ddd94adc13b5a66ee21302c9fa59e7a4bf732678c15ca0a8acbb2d2e57e52c54f03f76a4537e2a363b5f6eb1a13ebc41a741dfc625ef12b5ce449641
7
- data.tar.gz: 7b4172bfa6cdeb847e8a595f64086d2f26171aca71ed762acc3f746d5af1be19e5b06df400118a9bd35ed57e73d0ad8460871b8b1244571cd252a4345b5a1a60
6
+ metadata.gz: 7f98160ecf531574253f0eb31ff13c17ac17e7c59a50e6af93158a4b4ef8220f7af37ce5d065ba894b520a3dd16b374cba0df9464c0472738329d1ee67c26e42
7
+ data.tar.gz: 1bfed6d610e861f525ef3b0a36cde68e4bf6fb25c1e5c02c4bc96caaf8d300c2b59bafbf87ef3db7765079524b07e76e7e2c819ccb8da50a96069e02e5af987b
@@ -24,7 +24,16 @@
24
24
  + [docinfo_fields](#docinfo_fields)
25
25
  + [docinfo_target](#docinfo_target)
26
26
  + [docinfo](#docinfo)
27
- + [infinite_check_connection](#infinite_check_connection)
27
+ + [check_connection](#check_connection)
28
+ + [retry_forever](#retry_forever)
29
+ + [retry_timeout](#retry_timeout)
30
+ + [retry_max_times](#retry_max_times)
31
+ + [retry_type](#retry_type)
32
+ + [retry_wait](#retry_wait)
33
+ + [retry_exponential_backoff_base](#retry_exponential_backoff_base)
34
+ + [retry_max_interval](#retry_max_interval)
35
+ + [retry_randomize](#retry_randomize)
36
+
28
37
  * [Advanced Usage](#advanced-usage)
29
38
 
30
39
  ## Usage
@@ -275,14 +284,87 @@ This parameter specifies whether docinfo information including or not. The defau
275
284
  docinfo false
276
285
  ```
277
286
 
278
- ### infinite_check_connection
287
+ ### check_connection
288
+
289
+ The parameter for checking on connection availability with Elasticsearch or Opensearch hosts. The default value is `true`.
290
+
291
+ ```
292
+ check_connection true
293
+ ```
294
+ ### retry_forever
295
+
296
+ The parameter If true, plugin will ignore retry_timeout and retry_max_times options and retry forever. The default value is `true`.
297
+
298
+ ```
299
+ retry_forever true
300
+ ```
301
+
302
+ ### retry_timeout
303
+
304
+ The parameter maximum time (seconds) to retry again the failed try, until the plugin discards the retry.
305
+ If the next retry is going to exceed this time limit, the last retry will be made at exactly this time limit..
306
+ The default value is `72h`.
307
+ 72hours == 17 times with exponential backoff (not to change default behavior)
308
+
309
+ ```
310
+ retry_timeout 72 * 60 * 60
311
+ ```
312
+
313
+ ### retry_max_times
314
+
315
+ The parameter maximum number of times to retry the failed try. The default value is `5`
316
+
317
+ ```
318
+ retry_max_times 5
319
+ ```
320
+
321
+ ### retry_type
279
322
 
280
- The parameter infinite checking on connection availability with Elasticsearch or opensearch hosts, every request_timeout (default 5) seconds. The default value is `true,`. But if value is `false` then checking of connection will be only 3 times
323
+ The parameter needs for how long need to wait (time in seconds) to retry again:
324
+ `exponential_backoff`: wait in seconds will become large exponentially per failure,
325
+ `periodic`: plugin will retry periodically with fixed intervals (configured via retry_wait). The default value is `:exponential_backoff`
326
+ Periodic -> fixed :retry_wait
327
+ Exponential backoff: k is number of retry times
328
+ c: constant factor, @retry_wait
329
+ b: base factor, @retry_exponential_backoff_base
330
+ k: times
331
+ total retry time: c + c * b^1 + (...) + c*b^k = c*b^(k+1) - 1
281
332
 
282
333
  ```
283
- infinite_check_connection true
334
+ retry_type exponential_backoff
284
335
  ```
285
336
 
337
+ ### retry_wait
338
+
339
+ The parameter needs for wait in seconds before the next retry to again or constant factor of exponential backoff. The default value is `5`
340
+
341
+ ```
342
+ retry_wait 5
343
+ ```
344
+
345
+ ### retry_exponential_backoff_base
346
+
347
+ The parameter The base number of exponential backoff for retries. The default value is `2`
348
+
349
+ ```
350
+ retry_exponential_backoff_base 2
351
+ ```
352
+
353
+ ### retry_max_interval
354
+
355
+ The parameter maximum interval (seconds) for exponential backoff between retries while failing. The default value is `nil`
356
+
357
+ ```
358
+ retry_max_interval nil
359
+ ```
360
+
361
+ ### retry_randomize
362
+
363
+ The parameter If true, the plugin will retry after randomized interval not to do burst retries. The default value is `false`
364
+
365
+ ```
366
+ retry_randomize false
367
+ ```
286
368
 
287
369
  ## Advanced Usage
288
370
 
@@ -3,7 +3,7 @@ $:.push File.expand_path('../lib', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'fluent-plugin-input-opensearch'
6
- s.version = '1.1.9'
6
+ s.version = '1.2.1'
7
7
  s.authors = ['imcotop']
8
8
  s.email = ['imcotop@icloud.com']
9
9
  s.description = %q{Opensearch output plugin for Fluent event collector}
@@ -29,6 +29,7 @@ require 'opensearch'
29
29
  require 'faraday/excon'
30
30
  require 'fluent/log-ext'
31
31
  require 'fluent/plugin/input'
32
+ require 'fluent/plugin_helper'
32
33
  require_relative 'opensearch_constants'
33
34
 
34
35
  module Fluent::Plugin
@@ -39,7 +40,7 @@ module Fluent::Plugin
39
40
  DEFAULT_STORAGE_TYPE = 'local'
40
41
  METADATA = "@metadata".freeze
41
42
 
42
- helpers :timer, :thread
43
+ helpers :timer, :thread, :retry_state
43
44
 
44
45
  Fluent::Plugin.register_input('opensearch', self)
45
46
 
@@ -80,7 +81,23 @@ module Fluent::Plugin
80
81
  config_param :docinfo_fields, :array, :default => ['_index', '_type', '_id']
81
82
  config_param :docinfo_target, :string, :default => METADATA
82
83
  config_param :docinfo, :bool, :default => false
83
- config_param :infinite_check_connection, :bool, :default => true
84
+ config_param :check_connection, :bool, :default => true
85
+ config_param :retry_forever, :bool, default: true, desc: 'If true, plugin will ignore retry_timeout and retry_max_times options and retry forever.'
86
+ config_param :retry_timeout, :time, default: 72 * 60 * 60, desc: 'The maximum seconds to retry'
87
+ # 72hours == 17 times with exponential backoff (not to change default behavior)
88
+ config_param :retry_max_times, :integer, default: 5, desc: 'The maximum number of times to retry'
89
+ # exponential backoff sequence will be initialized at the time of this threshold
90
+ config_param :retry_type, :enum, list: [:exponential_backoff, :periodic], default: :exponential_backoff
91
+ ### Periodic -> fixed :retry_wait
92
+ ### Exponential backoff: k is number of retry times
93
+ # c: constant factor, @retry_wait
94
+ # b: base factor, @retry_exponential_backoff_base
95
+ # k: times
96
+ # total retry time: c + c * b^1 + (...) + c*b^k = c*b^(k+1) - 1
97
+ config_param :retry_wait, :time, default: 5, desc: 'Seconds to wait before next retry , or constant factor of exponential backoff.'
98
+ config_param :retry_exponential_backoff_base, :float, default: 2, desc: 'The base number of exponential backoff for retries.'
99
+ config_param :retry_max_interval, :time, default: nil, desc: 'The maximum interval seconds for exponential backoff between retries while failing.'
100
+ config_param :retry_randomize, :bool, default: false, desc: 'If true, output plugin will retry after randomized interval not to do burst retries.'
84
101
 
85
102
  include Fluent::Plugin::OpenSearchConstants
86
103
 
@@ -93,6 +110,7 @@ module Fluent::Plugin
93
110
 
94
111
  @timestamp_parser = create_time_parser
95
112
  @backend_options = backend_options
113
+ @retry = nil
96
114
 
97
115
  raise Fluent::ConfigError, "`password` must be present if `user` is present" if @user && @password.nil?
98
116
 
@@ -139,6 +157,15 @@ module Fluent::Plugin
139
157
  raise Fluent::ConfigError, "You must install #{@http_backend} gem. Exception: #{ex}"
140
158
  end
141
159
 
160
+ def retry_state(randomize)
161
+ retry_state_create(
162
+ :input_retries, @retry_type, @retry_wait, @retry_timeout,
163
+ forever: @retry_forever, max_steps: @retry_max_times,
164
+ max_interval: @retry_max_interval, backoff_base: @retry_exponential_backoff_base,
165
+ randomize: randomize
166
+ )
167
+ end
168
+
142
169
  def get_escaped_userinfo(host_str)
143
170
  if m = host_str.match(/(?<scheme>.*)%{(?<user>.*)}:%{(?<password>.*)}(?<path>@.*)/)
144
171
  m["scheme"] +
@@ -177,12 +204,29 @@ module Fluent::Plugin
177
204
  host.merge!(user: @user, password: @password) if !host[:user] && @user
178
205
  host.merge!(path: @path) if !host[:path] && @path
179
206
  end
180
-
207
+ live_hosts = @check_connection ? hosts.select { |host| reachable_host?(host) } : hosts
181
208
  {
182
- hosts: get_reachable_hosts(hosts)
209
+ hosts: live_hosts
183
210
  }
184
211
  end
185
212
 
213
+ def reachable_host?(host)
214
+ client = OpenSearch::Client.new(
215
+ host: ["#{host[:scheme]}://#{host[:host]}:#{host[:port]}"],
216
+ user: host[:user],
217
+ password: host[:password],
218
+ reload_connections: @reload_connections,
219
+ request_timeout: @request_timeout,
220
+ resurrect_after: @resurrect_after,
221
+ reload_on_failure: @reload_on_failure,
222
+ transport_options: { ssl: { verify: @ssl_verify, ca_file: @ca_file, version: @ssl_version } }
223
+ )
224
+ client.ping
225
+ rescue => e
226
+ log.warn "Failed to connect to #{host[:scheme]}://#{host[:host]}:#{host[:port]}: #{e.message}"
227
+ false
228
+ end
229
+
186
230
  def emit_error_label_event(&block)
187
231
  # If `emit_error_label_event` is specified as false, error event emittions are not occurred.
188
232
  if emit_error_label_event
@@ -240,43 +284,6 @@ module Fluent::Plugin
240
284
  return Time.at(event_time).to_time
241
285
  end
242
286
 
243
- def get_reachable_hosts(hosts=nil)
244
- reachable_hosts = []
245
- attempt = 0
246
- loop do
247
- hosts.each do |host|
248
- begin
249
- if @infinite_check_connection == true
250
- check_host = OpenSearch::Client.new(
251
- host: ["#{host[:scheme]}://#{host[:host]}:#{host[:port]}"],
252
- user: host[:user],
253
- password: host[:password],
254
- reload_connections: true,
255
- resurrect_after: @resurrect_after,
256
- reload_on_failure: @reload_on_failure,
257
- transport_options: { ssl: { verify: @ssl_verify, ca_file: @ca_file, version: @ssl_version } }
258
- )
259
- response = check_host.ping #https://github.com/opensearch-project/opensearch-ruby/blob/136e1c975fc91b8cb80d7d1134e32c6dbefdb3eb/lib/opensearch/api/actions/ping.rb#L33
260
- if response == true
261
- reachable_hosts << host
262
- else
263
- log.warn "Connection to #{host[:scheme]}://#{host[:host]}:#{host[:port]} failed with status code #{response.status}"
264
- end
265
- else
266
- reachable_hosts << host
267
- end
268
- rescue => e
269
- log.warn "Failed to connect to #{host[:scheme]}://#{host[:host]}:#{host[:port]}"
270
- end
271
- end
272
- break unless reachable_hosts.empty?
273
- log.info "Attempt ##{attempt += 1} to get reachable hosts"
274
- log.info "No reachable hosts found. Retrying in #{@request_timeout} seconds..."
275
- sleep(@request_timeout)
276
- end
277
- reachable_hosts
278
- end
279
-
280
287
  def client(host = nil)
281
288
  # check here to see if we already have a client connection for the given host
282
289
  connection_options = get_connection_options(host)
@@ -330,6 +337,25 @@ module Fluent::Plugin
330
337
  return true
331
338
  end
332
339
 
340
+ def update_retry_state(error=nil)
341
+ if error
342
+ unless @retry
343
+ @retry = retry_state(@retry_randomize)
344
+ end
345
+ @retry.step
346
+ #Raise error if the retry limit has been reached
347
+ raise "Hit limit for retries. retry_times: #{@retry.steps}, error: #{error.message}" if @retry.limit?
348
+ #Retry if the limit hasn't been reached
349
+ log.warn("failed to connect or search.", retry_times: @retry.steps, next_retry_time: @retry.next_time.round, error: error.message)
350
+ sleep(@retry.next_time - Time.now)
351
+ else
352
+ unless @retry.nil?
353
+ log.debug("retry succeeded.")
354
+ @retry = nil
355
+ end
356
+ end
357
+ end
358
+
333
359
  def run
334
360
  return run_slice if @num_slices <= 1
335
361
 
@@ -340,8 +366,8 @@ module Fluent::Plugin
340
366
  run_slice(slice_id)
341
367
  end
342
368
  end
343
- rescue Faraday::ConnectionFailed => e
344
- log.warn "Connection to OpenSearch failed during search in the 'run' method: #{e.message}. Retrying..."
369
+ rescue Faraday::ConnectionFailed, OpenSearch::Transport::Transport::Error => error
370
+ update_retry_state(error)
345
371
  retry
346
372
  end
347
373
 
@@ -351,7 +377,7 @@ module Fluent::Plugin
351
377
  result = client.search(@options.merge(:body => Yajl.dump(slice_query) ))
352
378
  es = Fluent::MultiEventStream.new
353
379
 
354
- result["hits"]["hits"].each {|hit| process_events(hit, es)}
380
+ result["hits"]["hits"].each {|hit| process_events(hit, es)} unless result.nil?
355
381
  has_hits = result['hits']['hits'].any?
356
382
  scroll_id = result['_scroll_id']
357
383
 
@@ -363,6 +389,7 @@ module Fluent::Plugin
363
389
 
364
390
  router.emit_stream(@tag, es)
365
391
  clear_scroll(scroll_id)
392
+ update_retry_state
366
393
  end
367
394
 
368
395
  def clear_scroll(scroll_id)
@@ -201,6 +201,8 @@ module Fluent::Plugin
201
201
  end
202
202
  end
203
203
 
204
+ return if bulk_message.to_s.empty?
205
+
204
206
  params = {
205
207
  index: data_stream_name,
206
208
  body: bulk_message
@@ -39,7 +39,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
39
39
  CONFIG = %[
40
40
  tag raw.opensearch
41
41
  interval 2
42
- infinite_check_connection false
42
+ check_connection false
43
43
  ]
44
44
 
45
45
  def setup
@@ -191,7 +191,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
191
191
  user john
192
192
  password doe
193
193
  tag raw.opensearch
194
- infinite_check_connection false
194
+ check_connection false
195
195
  }
196
196
  instance = driver(config).instance
197
197
 
@@ -230,7 +230,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
230
230
  user john
231
231
  password doe
232
232
  tag raw.opensearch
233
- infinite_check_connection false
233
+ check_connection false
234
234
  }
235
235
  instance = driver(config).instance
236
236
 
@@ -252,7 +252,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
252
252
  user %{j+hn}
253
253
  password %{d@e}
254
254
  tag raw.opensearch
255
- infinite_check_connection false
255
+ check_connection false
256
256
  }
257
257
  instance = driver(config).instance
258
258
 
@@ -275,7 +275,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
275
275
  path /es/
276
276
  port 123
277
277
  tag raw.opensearch
278
- infinite_check_connection false
278
+ check_connection false
279
279
  }
280
280
  instance = driver(config).instance
281
281
 
@@ -300,7 +300,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
300
300
  user default_user
301
301
  password default_password
302
302
  tag raw.opensearch
303
- infinite_check_connection false
303
+ check_connection false
304
304
  }
305
305
  instance = driver(config).instance
306
306
 
@@ -329,7 +329,7 @@ class OpenSearchInputTest < Test::Unit::TestCase
329
329
  user default_user
330
330
  password default_password
331
331
  tag raw.opensearch
332
- infinite_check_connection false
332
+ check_connection false
333
333
  }
334
334
  instance = driver(config).instance
335
335
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-input-opensearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.9
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - imcotop
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-15 00:00:00.000000000 Z
11
+ date: 2024-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd