logstash-output-elasticsearch 11.14.1-java → 11.15.1-java

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: c6405648edffa1a591049d280196f4e7d0e4812f029daf782346e76e202f40b0
4
- data.tar.gz: 2a8c1ae4c5cf07839aba4a7416305bae027b5461602c8518770f716683643e42
3
+ metadata.gz: 6ad6b80e4c6db7a54c8b7a830f6a922a7057b2e7585820db8a6c093b57db3800
4
+ data.tar.gz: 82cd893394fc7ac08ae7a79b2cd953f80fbf258ec2faad225300a2ce516ab208
5
5
  SHA512:
6
- metadata.gz: 9d5f80600ff713cd5429b7c1fe3dde0c665918e1ff1dbf69e8ca2e5a71a6c5e083031ad8951eeb561c0007e305bf2e808884ffdc97e9cd13aaa068df8cdd3e77
7
- data.tar.gz: 1f5e4fe699a2c7189d84215a5631a42b20f608600ad10a97e464e19429586b5949d0f1570d67535e748e2f2e24a43bd323418b4fa114b8896eb568894ee35f82
6
+ metadata.gz: b861d195377c3eeadf4489d21780be6627597aa0b93992bd7378b7cf680f6f99ac120ae342a4b48739ee6ef2652aa9238ee9fc08838cbed0f6dae0c887b06daa
7
+ data.tar.gz: 16091be406132dbb590ad76a0ba2e83cb0729717d8229b410bccbcabc660a7a26146fd2c7aaae6976f954bd17f1f763c6353552699ffd67173efb9917b913658
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 11.15.1
2
+ - Move async finish_register to bottom of register to avoid race condition [#1125](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1125)
3
+
4
+ ## 11.15.0
5
+ - Added the ability to negatively acknowledge the batch under processing if the plugin is blocked in a retry-error-loop and a shutdown is requested. [#1119](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1119)
6
+
1
7
  ## 11.14.1
2
8
  - [DOC] Fixed incorrect pull request link on the CHANGELOG `11.14.0` entry [#1122](https://github.com/logstash-plugins/logstash-output-elasticsearch/pull/1122)
3
9
 
@@ -313,6 +313,27 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
313
313
  data_stream_enabled = data_stream_config?
314
314
 
315
315
  setup_template_manager_defaults(data_stream_enabled)
316
+ # To support BWC, we check if DLQ exists in core (< 5.4). If it doesn't, we use nil to resort to previous behavior.
317
+ @dlq_writer = dlq_enabled? ? execution_context.dlq_writer : nil
318
+
319
+ @dlq_codes = DOC_DLQ_CODES.to_set
320
+
321
+ if dlq_enabled?
322
+ check_dlq_custom_codes
323
+ @dlq_codes.merge(dlq_custom_codes)
324
+ else
325
+ raise LogStash::ConfigurationError, "DLQ feature (dlq_custom_codes) is configured while DLQ is not enabled" unless dlq_custom_codes.empty?
326
+ end
327
+
328
+ setup_mapper_and_target(data_stream_enabled)
329
+
330
+ @bulk_request_metrics = metric.namespace(:bulk_requests)
331
+ @document_level_metrics = metric.namespace(:documents)
332
+
333
+ if ecs_compatibility == :v8
334
+ @logger.warn("Elasticsearch Output configured with `ecs_compatibility => v8`, which resolved to an UNRELEASED preview of version 8.0.0 of the Elastic Common Schema. " +
335
+ "Once ECS v8 and an updated release of this plugin are publicly available, you will need to update this plugin to resolve this warning.")
336
+ end
316
337
 
317
338
  @after_successful_connection_thread = after_successful_connection do
318
339
  begin
@@ -326,18 +347,9 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
326
347
  end
327
348
  end
328
349
 
329
- # To support BWC, we check if DLQ exists in core (< 5.4). If it doesn't, we use nil to resort to previous behavior.
330
- @dlq_writer = dlq_enabled? ? execution_context.dlq_writer : nil
331
-
332
- @dlq_codes = DOC_DLQ_CODES.to_set
333
-
334
- if dlq_enabled?
335
- check_dlq_custom_codes
336
- @dlq_codes.merge(dlq_custom_codes)
337
- else
338
- raise LogStash::ConfigurationError, "DLQ feature (dlq_custom_codes) is configured while DLQ is not enabled" unless dlq_custom_codes.empty?
339
- end
350
+ end
340
351
 
352
+ def setup_mapper_and_target(data_stream_enabled)
341
353
  if data_stream_enabled
342
354
  @event_mapper = -> (e) { data_stream_event_action_tuple(e) }
343
355
  @event_target = -> (e) { data_stream_name(e) }
@@ -346,14 +358,6 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
346
358
  @event_mapper = -> (e) { event_action_tuple(e) }
347
359
  @event_target = -> (e) { e.sprintf(@index) }
348
360
  end
349
-
350
- @bulk_request_metrics = metric.namespace(:bulk_requests)
351
- @document_level_metrics = metric.namespace(:documents)
352
-
353
- if ecs_compatibility == :v8
354
- @logger.warn("Elasticsearch Output configured with `ecs_compatibility => v8`, which resolved to an UNRELEASED preview of version 8.0.0 of the Elastic Common Schema. " +
355
- "Once ECS v8 and an updated release of this plugin are publicly available, you will need to update this plugin to resolve this warning.")
356
- end
357
361
  end
358
362
 
359
363
  # @override post-register when ES connection established
@@ -431,7 +435,12 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
431
435
  def wait_for_successful_connection
432
436
  after_successful_connection_done = @after_successful_connection_done
433
437
  return unless after_successful_connection_done
434
- stoppable_sleep 1 until after_successful_connection_done.true?
438
+ stoppable_sleep 1 until (after_successful_connection_done.true? || pipeline_shutdown_requested?)
439
+
440
+ if pipeline_shutdown_requested?
441
+ logger.info "Aborting the batch due to shutdown request while waiting for connections to become live"
442
+ abort_batch_if_available!
443
+ end
435
444
 
436
445
  status = @after_successful_connection_thread && @after_successful_connection_thread.value
437
446
  if status.is_a?(Exception) # check if thread 'halted' with an error
@@ -159,6 +159,8 @@ module LogStash; module PluginMixins; module ElasticSearch
159
159
  def after_successful_connection(&block)
160
160
  Thread.new do
161
161
  sleep_interval = @retry_initial_interval
162
+ # in case of a pipeline's shutdown_requested?, the method #close shutdown also this thread
163
+ # so no need to explicitly handle it here and return an AbortedBatchException.
162
164
  until successful_connection? || @stopping.true?
163
165
  @logger.debug("Waiting for connectivity to Elasticsearch cluster, retrying in #{sleep_interval}s")
164
166
  sleep_interval = sleep_for_interval(sleep_interval)
@@ -191,8 +193,14 @@ module LogStash; module PluginMixins; module ElasticSearch
191
193
  @logger.info("Retrying individual bulk actions that failed or were rejected by the previous bulk request", count: submit_actions.size)
192
194
  end
193
195
  rescue => e
194
- @logger.error("Encountered an unexpected error submitting a bulk request, will retry",
195
- message: e.message, exception: e.class, backtrace: e.backtrace)
196
+ if abort_batch_present? && e.instance_of?(org.logstash.execution.AbortedBatchException)
197
+ # if Logstash support abort of a batch and the batch is aborting,
198
+ # bubble up the exception so that the pipeline can handle it
199
+ raise e
200
+ else
201
+ @logger.error("Encountered an unexpected error submitting a bulk request, will retry",
202
+ message: e.message, exception: e.class, backtrace: e.backtrace)
203
+ end
196
204
  end
197
205
 
198
206
  # Everything was a success!
@@ -331,6 +339,11 @@ module LogStash; module PluginMixins; module ElasticSearch
331
339
 
332
340
  sleep_interval = sleep_for_interval(sleep_interval)
333
341
  @bulk_request_metrics.increment(:failures)
342
+ if pipeline_shutdown_requested?
343
+ # when any connection is available and a shutdown is requested
344
+ # the batch can be aborted, eventually for future retry.
345
+ abort_batch_if_available!
346
+ end
334
347
  retry unless @stopping.true?
335
348
  rescue ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError => e
336
349
  @bulk_request_metrics.increment(:failures)
@@ -349,6 +362,11 @@ module LogStash; module PluginMixins; module ElasticSearch
349
362
  end
350
363
 
351
364
  sleep_interval = sleep_for_interval(sleep_interval)
365
+ if pipeline_shutdown_requested?
366
+ # In case ES side changes access credentials and a pipeline reload is triggered
367
+ # this error becomes a retry on restart
368
+ abort_batch_if_available!
369
+ end
352
370
  retry
353
371
  rescue => e # Stuff that should never happen - print out full connection issues
354
372
  @logger.error(
@@ -363,6 +381,19 @@ module LogStash; module PluginMixins; module ElasticSearch
363
381
  end
364
382
  end
365
383
 
384
+ def pipeline_shutdown_requested?
385
+ return super if defined?(super) # since LS 8.1.0
386
+ execution_context&.pipeline&.shutdown_requested
387
+ end
388
+
389
+ def abort_batch_if_available!
390
+ raise org.logstash.execution.AbortedBatchException.new if abort_batch_present?
391
+ end
392
+
393
+ def abort_batch_present?
394
+ ::Gem::Version.create(LOGSTASH_VERSION) >= ::Gem::Version.create('8.8.0')
395
+ end
396
+
366
397
  def dlq_enabled?
367
398
  # TODO there should be a better way to query if DLQ is enabled
368
399
  # See more in: https://github.com/elastic/logstash/issues/8064
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-elasticsearch'
3
- s.version = '11.14.1'
3
+ s.version = '11.15.1'
4
4
  s.licenses = ['apache-2.0']
5
5
  s.summary = "Stores logs in Elasticsearch"
6
6
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -50,6 +50,104 @@ describe LogStash::Outputs::ElasticSearch do
50
50
  subject.close
51
51
  end
52
52
 
53
+ context "check aborting of a batch" do
54
+ context "on an unreachable ES instance" do
55
+ let(:events) { [ ::LogStash::Event.new("foo" => "bar1"), ::LogStash::Event.new("foo" => "bar2") ] }
56
+
57
+ let(:shutdown_value) { true }
58
+
59
+ let(:logger) { double("logger") }
60
+
61
+ before(:each) do
62
+ allow(subject).to receive(:logger).and_return(logger)
63
+ allow(logger).to receive(:info)
64
+
65
+ allow(subject).to receive(:pipeline_shutdown_requested?) do
66
+ shutdown_value
67
+ end
68
+ end
69
+
70
+ it "the #multi_receive abort while waiting on unreachable and a shutdown is requested" do
71
+ expect { subject.multi_receive(events) }.to raise_error(org.logstash.execution.AbortedBatchException)
72
+ expect(logger).to have_received(:info).with(/Aborting the batch due to shutdown request while waiting for connections to become live/i)
73
+ end
74
+ end
75
+
76
+ context "when a connected ES becomes unreachable" do
77
+ # let(:error) do
78
+ # ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError.new(
79
+ # 429, double("url").as_null_object, request_body, double("response body")
80
+ # )
81
+ # end
82
+
83
+ shared_examples 'raise an abort error' do
84
+ let(:options) {
85
+ {
86
+ "index" => "my-index",
87
+ "hosts" => ["localhost","localhost:9202"],
88
+ "path" => "some-path",
89
+ "manage_template" => false
90
+ }
91
+ }
92
+
93
+ let(:manticore_urls) { subject.client.pool.urls }
94
+ let(:manticore_url) { manticore_urls.first }
95
+
96
+ let(:stub_http_client_pool!) do
97
+ [:start_resurrectionist, :start_sniffer, :healthcheck!].each do |method|
98
+ allow_any_instance_of(LogStash::Outputs::ElasticSearch::HttpClient::Pool).to receive(method)
99
+ end
100
+ end
101
+
102
+ let(:event) { ::LogStash::Event.new("foo" => "bar") }
103
+
104
+ let(:logger) { double("logger").as_null_object }
105
+ let(:response) { { :errors => [], :items => [] } }
106
+
107
+ let(:request_body) { double(:request_body, :bytesize => 1023) }
108
+
109
+ before(:each) do
110
+ bulk_param = [["index", anything, event.to_hash]]
111
+
112
+ allow(subject).to receive(:logger).and_return(logger)
113
+
114
+ # fail consistently for ever
115
+ allow(subject.client).to receive(:bulk).with(bulk_param).and_raise(error)
116
+ end
117
+
118
+ it "should exit the retry with an abort exception if shutdown is requested" do
119
+ # execute in another thread because it blocks in a retry loop until the shutdown is triggered
120
+ th = Thread.new do
121
+ subject.multi_receive([event])
122
+ rescue org.logstash.execution.AbortedBatchException => e
123
+ # return exception's class so that it can be verified when retrieving the thread's value
124
+ e.class
125
+ end
126
+
127
+ # trigger the shutdown signal
128
+ allow(subject).to receive(:pipeline_shutdown_requested?) { true }
129
+
130
+ expect(th.value).to eq(org.logstash.execution.AbortedBatchException)
131
+ end
132
+ end
133
+
134
+ context "with 429 error" do
135
+ let(:error) do
136
+ ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError.new(
137
+ 429, double("url").as_null_object, request_body, double("response body")
138
+ )
139
+ end
140
+
141
+ it_behaves_like 'raise an abort error'
142
+ end
143
+
144
+ context "with 'no connections' error" do
145
+ let(:error) { ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::NoConnectionAvailableError.new }
146
+
147
+ it_behaves_like 'raise an abort error'
148
+ end
149
+ end
150
+ end if LOGSTASH_VERSION >= '8.8'
53
151
 
54
152
  context "with an active instance" do
55
153
  let(:options) {
@@ -1358,6 +1456,42 @@ describe LogStash::Outputs::ElasticSearch do
1358
1456
  end
1359
1457
 
1360
1458
  end
1459
+
1460
+ context 'during register/finish_register' do
1461
+
1462
+ let(:options) { { 'hosts' => '127.0.0.1:9999', 'data_stream' => 'true' } }
1463
+ let(:es_version) { '8.7.0' } # DS default on LS 8.x
1464
+
1465
+ before do
1466
+ allow(subject).to receive(:discover_cluster_uuid)
1467
+ allow(subject).to receive(:maybe_create_rollover_alias)
1468
+ allow(subject).to receive(:maybe_create_ilm_policy)
1469
+ allow(subject).to receive(:build_client)
1470
+ end
1471
+
1472
+ # this test could not have been done using latches as the fix to the race
1473
+ # condition alters the order of the instructions in elasticsearch.rb
1474
+ #
1475
+ # the race condition happened when the @index was set to the datastream
1476
+ # after `ilm_in_use?` is called but before `setup_ilm`
1477
+ it 'doesn\'t have a race condition leading to resetting back to ILM' do
1478
+ ilm_in_use = subject.method(:ilm_in_use?)
1479
+ expect(subject).to receive(:ilm_in_use?) do |params|
1480
+ ret = ilm_in_use.call
1481
+ sleep 3
1482
+ ret
1483
+ end
1484
+ setup_mapper_and_target = subject.method(:setup_mapper_and_target)
1485
+ expect(subject).to receive(:setup_mapper_and_target).once do |params|
1486
+ sleep 1
1487
+ setup_mapper_and_target.call(params)
1488
+ end
1489
+ subject.register
1490
+ sleep 6
1491
+ expect(subject.index).to eq("logs-generic-default")
1492
+ end
1493
+
1494
+ end
1361
1495
  end
1362
1496
 
1363
1497
  @private
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 11.14.1
4
+ version: 11.15.1
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-22 00:00:00.000000000 Z
11
+ date: 2023-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -356,7 +356,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
356
356
  - !ruby/object:Gem::Version
357
357
  version: '0'
358
358
  requirements: []
359
- rubygems_version: 3.1.6
359
+ rubygems_version: 3.2.29
360
360
  signing_key:
361
361
  specification_version: 4
362
362
  summary: Stores logs in Elasticsearch