logstash-output-elasticsearch 10.8.6-java → 11.0.3-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/docs/index.asciidoc +132 -22
  4. data/lib/logstash/outputs/elasticsearch.rb +125 -64
  5. data/lib/logstash/outputs/elasticsearch/data_stream_support.rb +233 -0
  6. data/lib/logstash/outputs/elasticsearch/http_client.rb +9 -7
  7. data/lib/logstash/outputs/elasticsearch/http_client/pool.rb +49 -62
  8. data/lib/logstash/outputs/elasticsearch/ilm.rb +13 -45
  9. data/lib/logstash/outputs/elasticsearch/license_checker.rb +26 -23
  10. data/lib/logstash/outputs/elasticsearch/template_manager.rb +4 -6
  11. data/lib/logstash/outputs/elasticsearch/templates/ecs-v1/elasticsearch-8x.json +1 -0
  12. data/lib/logstash/plugin_mixins/elasticsearch/api_configs.rb +157 -153
  13. data/lib/logstash/plugin_mixins/elasticsearch/common.rb +71 -58
  14. data/logstash-output-elasticsearch.gemspec +3 -3
  15. data/spec/es_spec_helper.rb +7 -12
  16. data/spec/fixtures/_nodes/{5x_6x.json → 6x.json} +5 -5
  17. data/spec/integration/outputs/compressed_indexing_spec.rb +47 -46
  18. data/spec/integration/outputs/data_stream_spec.rb +61 -0
  19. data/spec/integration/outputs/delete_spec.rb +49 -51
  20. data/spec/integration/outputs/ilm_spec.rb +236 -248
  21. data/spec/integration/outputs/index_spec.rb +5 -2
  22. data/spec/integration/outputs/index_version_spec.rb +78 -82
  23. data/spec/integration/outputs/ingest_pipeline_spec.rb +58 -58
  24. data/spec/integration/outputs/painless_update_spec.rb +74 -164
  25. data/spec/integration/outputs/parent_spec.rb +67 -75
  26. data/spec/integration/outputs/retry_spec.rb +6 -6
  27. data/spec/integration/outputs/sniffer_spec.rb +15 -54
  28. data/spec/integration/outputs/templates_spec.rb +79 -81
  29. data/spec/integration/outputs/update_spec.rb +99 -101
  30. data/spec/spec_helper.rb +10 -0
  31. data/spec/unit/outputs/elasticsearch/data_stream_support_spec.rb +528 -0
  32. data/spec/unit/outputs/elasticsearch/http_client/manticore_adapter_spec.rb +1 -0
  33. data/spec/unit/outputs/elasticsearch/http_client/pool_spec.rb +36 -29
  34. data/spec/unit/outputs/elasticsearch/http_client_spec.rb +2 -3
  35. data/spec/unit/outputs/elasticsearch/template_manager_spec.rb +10 -12
  36. data/spec/unit/outputs/elasticsearch_proxy_spec.rb +1 -2
  37. data/spec/unit/outputs/elasticsearch_spec.rb +176 -41
  38. data/spec/unit/outputs/elasticsearch_ssl_spec.rb +1 -2
  39. data/spec/unit/outputs/error_whitelist_spec.rb +3 -2
  40. data/spec/unit/outputs/license_check_spec.rb +0 -16
  41. metadata +29 -36
  42. data/lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-2x.json +0 -95
  43. data/lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-5x.json +0 -46
  44. data/spec/fixtures/_nodes/2x_1x.json +0 -27
  45. data/spec/fixtures/scripts/groovy/scripted_update.groovy +0 -2
  46. data/spec/fixtures/scripts/groovy/scripted_update_nested.groovy +0 -2
  47. data/spec/fixtures/scripts/groovy/scripted_upsert.groovy +0 -2
  48. data/spec/integration/outputs/groovy_update_spec.rb +0 -150
  49. data/spec/integration/outputs/templates_5x_spec.rb +0 -98
@@ -1,5 +1,6 @@
1
1
  require "logstash/devutils/rspec/spec_helper"
2
2
  require "logstash/outputs/elasticsearch/http_client"
3
+ require 'cabin'
3
4
 
4
5
  describe LogStash::Outputs::ElasticSearch::HttpClient::ManticoreAdapter do
5
6
  let(:logger) { Cabin::Channel.get }
@@ -1,6 +1,6 @@
1
1
  require "logstash/devutils/rspec/spec_helper"
2
2
  require "logstash/outputs/elasticsearch/http_client"
3
- require "json"
3
+ require 'cabin'
4
4
 
5
5
  describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
6
6
  let(:logger) { Cabin::Channel.get }
@@ -8,15 +8,12 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
8
8
  let(:initial_urls) { [::LogStash::Util::SafeURI.new("http://localhost:9200")] }
9
9
  let(:options) { {:resurrect_delay => 2, :url_normalizer => proc {|u| u}} } # Shorten the delay a bit to speed up tests
10
10
  let(:es_node_versions) { [ "0.0.0" ] }
11
- let(:oss) { true }
12
- let(:valid_license) { true }
11
+ let(:license_status) { 'active' }
13
12
 
14
13
  subject { described_class.new(logger, adapter, initial_urls, options) }
15
14
 
16
15
  let(:manticore_double) { double("manticore a") }
17
16
  before(:each) do
18
- stub_const('LogStash::OSS', oss)
19
-
20
17
  response_double = double("manticore response").as_null_object
21
18
  # Allow healtchecks
22
19
  allow(manticore_double).to receive(:head).with(any_args).and_return(response_double)
@@ -26,8 +23,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
26
23
  allow(::Manticore::Client).to receive(:new).and_return(manticore_double)
27
24
 
28
25
  allow(subject).to receive(:get_es_version).with(any_args).and_return(*es_node_versions)
29
- allow(subject.license_checker).to receive(:oss?).and_return(oss)
30
- allow(subject.license_checker).to receive(:valid_es_license?).and_return(valid_license)
26
+ allow(subject.license_checker).to receive(:license_status).and_return(license_status)
31
27
  end
32
28
 
33
29
  after do
@@ -279,35 +275,46 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
279
275
  allow(subject).to receive(:health_check_request)
280
276
  end
281
277
 
282
- context "when using default logstash distribution" do
283
- let(:oss) { false }
278
+ context "if ES doesn't return a valid license" do
279
+ let(:license_status) { nil }
284
280
 
285
- context "if ES doesn't return a valid license" do
286
- let(:valid_license) { false }
281
+ it "marks the url as dead" do
282
+ subject.update_initial_urls
283
+ expect(subject.alive_urls_count).to eq(0)
284
+ end
287
285
 
288
- it "marks the url as active" do
289
- subject.update_initial_urls
290
- expect(subject.alive_urls_count).to eq(1)
291
- end
286
+ it "logs a warning" do
287
+ expect(subject.license_checker).to receive(:warn_no_license).once.and_call_original
288
+ subject.update_initial_urls
289
+ end
290
+ end
292
291
 
293
- it "logs a warning" do
294
- expect(subject.license_checker).to receive(:log_license_deprecation_warn).once
295
- subject.update_initial_urls
296
- end
292
+ context "if ES returns a valid license" do
293
+ let(:license_status) { 'active' }
294
+
295
+ it "marks the url as active" do
296
+ subject.update_initial_urls
297
+ expect(subject.alive_urls_count).to eq(1)
297
298
  end
298
299
 
299
- context "if ES returns a valid license" do
300
- let(:valid_license) { true }
300
+ it "does not log a warning" do
301
+ expect(subject.license_checker).to_not receive(:warn_no_license)
302
+ expect(subject.license_checker).to_not receive(:warn_invalid_license)
303
+ subject.update_initial_urls
304
+ end
305
+ end
301
306
 
302
- it "marks the url as active" do
303
- subject.update_initial_urls
304
- expect(subject.alive_urls_count).to eq(1)
305
- end
307
+ context "if ES returns an invalid license" do
308
+ let(:license_status) { 'invalid' }
306
309
 
307
- it "does not log a warning" do
308
- expect(subject.license_checker).to_not receive(:log_license_deprecation_warn)
309
- subject.update_initial_urls
310
- end
310
+ it "marks the url as active" do
311
+ subject.update_initial_urls
312
+ expect(subject.alive_urls_count).to eq(1)
313
+ end
314
+
315
+ it "logs a warning" do
316
+ expect(subject.license_checker).to receive(:warn_invalid_license).and_call_original
317
+ subject.update_initial_urls
311
318
  end
312
319
  end
313
320
  end
@@ -1,7 +1,6 @@
1
- require_relative "../../../../spec/es_spec_helper"
2
- require "logstash/devutils/rspec/spec_helper"
1
+ require_relative "../../../../spec/spec_helper"
3
2
  require "logstash/outputs/elasticsearch/http_client"
4
- require "java"
3
+ require "cabin"
5
4
 
6
5
  describe LogStash::Outputs::ElasticSearch::HttpClient do
7
6
  let(:ssl) { nil }
@@ -1,24 +1,22 @@
1
1
  require "logstash/devutils/rspec/spec_helper"
2
- require "logstash/outputs/elasticsearch/http_client"
3
- require "java"
4
- require "json"
2
+ require "logstash/outputs/elasticsearch/template_manager"
5
3
 
6
4
  describe LogStash::Outputs::ElasticSearch::TemplateManager do
7
5
 
8
6
  describe ".default_template_path" do
9
- context "elasticsearch 1.x" do
10
- it "chooses the 2x template" do
11
- expect(described_class.default_template_path(1)).to end_with("/templates/ecs-disabled/elasticsearch-2x.json")
7
+ context "elasticsearch 6.x" do
8
+ it "chooses the 6x template" do
9
+ expect(described_class.default_template_path(6)).to end_with("/templates/ecs-disabled/elasticsearch-6x.json")
12
10
  end
13
11
  end
14
- context "elasticsearch 2.x" do
15
- it "chooses the 2x template" do
16
- expect(described_class.default_template_path(2)).to end_with("/templates/ecs-disabled/elasticsearch-2x.json")
12
+ context "elasticsearch 7.x" do
13
+ it "chooses the 7x template" do
14
+ expect(described_class.default_template_path(7)).to end_with("/templates/ecs-disabled/elasticsearch-7x.json")
17
15
  end
18
16
  end
19
- context "elasticsearch 5.x" do
20
- it "chooses the 5x template" do
21
- expect(described_class.default_template_path(5)).to end_with("/templates/ecs-disabled/elasticsearch-5x.json")
17
+ context "elasticsearch 8.x" do
18
+ it "chooses the 8x template" do
19
+ expect(described_class.default_template_path(8)).to end_with("/templates/ecs-disabled/elasticsearch-8x.json")
22
20
  end
23
21
  end
24
22
  end
@@ -1,6 +1,5 @@
1
- require_relative "../../../spec/es_spec_helper"
1
+ require_relative "../../../spec/spec_helper"
2
2
  require 'stud/temporary'
3
- require "logstash/outputs/elasticsearch"
4
3
  require 'manticore/client'
5
4
 
6
5
  describe "Proxy option" do
@@ -1,27 +1,40 @@
1
- require_relative "../../../spec/es_spec_helper"
1
+ require_relative "../../../spec/spec_helper"
2
2
  require "base64"
3
3
  require "flores/random"
4
+ require 'concurrent/atomic/count_down_latch'
4
5
  require "logstash/outputs/elasticsearch"
5
6
 
6
7
  describe LogStash::Outputs::ElasticSearch do
7
8
  subject(:elasticsearch_output_instance) { described_class.new(options) }
8
9
  let(:options) { {} }
9
- let(:maximum_seen_major_version) { [1,2,5,6,7,8].sample }
10
+ let(:maximum_seen_major_version) { [6,7,8].sample }
10
11
 
11
12
  let(:do_register) { true }
12
13
 
14
+ let(:stub_http_client_pool!) do
15
+ allow_any_instance_of(LogStash::Outputs::ElasticSearch::HttpClient::Pool).to receive(:start)
16
+ end
17
+
18
+ let(:after_successful_connection_thread_mock) do
19
+ double('after_successful_connection_thread', value: true)
20
+ end
21
+
13
22
  before(:each) do
14
23
  if do_register
15
- # Build the client and set mocks before calling register to avoid races.
16
- subject.build_client
24
+ stub_http_client_pool!
25
+
26
+ allow(subject).to receive(:finish_register) # stub-out thread completion (to avoid error log entries)
27
+
28
+ # emulate 'successful' ES connection on the same thread
29
+ allow(subject).to receive(:after_successful_connection) { |&block| block.call }.
30
+ and_return after_successful_connection_thread_mock
31
+ allow(subject).to receive(:stop_after_successful_connection_thread)
32
+
33
+ subject.register
17
34
 
18
- # Rspec mocks can't handle background threads, so... we can't use any
19
- allow(subject.client.pool).to receive(:start_resurrectionist)
20
- allow(subject.client.pool).to receive(:start_sniffer)
21
- allow(subject.client.pool).to receive(:healthcheck!)
22
35
  allow(subject.client).to receive(:maximum_seen_major_version).at_least(:once).and_return(maximum_seen_major_version)
23
36
  allow(subject.client).to receive(:get_xpack_info)
24
- subject.register
37
+
25
38
  subject.client.pool.adapter.manticore.respond_with(:body => "{}")
26
39
  end
27
40
  end
@@ -44,6 +57,12 @@ describe LogStash::Outputs::ElasticSearch do
44
57
  let(:manticore_urls) { subject.client.pool.urls }
45
58
  let(:manticore_url) { manticore_urls.first }
46
59
 
60
+ let(:stub_http_client_pool!) do
61
+ [:start_resurrectionist, :start_sniffer, :healthcheck!].each do |method|
62
+ allow_any_instance_of(LogStash::Outputs::ElasticSearch::HttpClient::Pool).to receive(method)
63
+ end
64
+ end
65
+
47
66
  describe "getting a document type" do
48
67
  context "if document_type isn't set" do
49
68
  let(:options) { super().merge("document_type" => nil)}
@@ -60,13 +79,6 @@ describe LogStash::Outputs::ElasticSearch do
60
79
  expect(subject.send(:get_event_type, LogStash::Event.new("type" => "foo"))).to eql("doc")
61
80
  end
62
81
  end
63
-
64
- context "for < 6.0 elasticsearch clusters" do
65
- let(:maximum_seen_major_version) { 5 }
66
- it "should get the type from the event" do
67
- expect(subject.send(:get_event_type, LogStash::Event.new("type" => "foo"))).to eql("foo")
68
- end
69
- end
70
82
  end
71
83
 
72
84
  context "with 'document type set'" do
@@ -253,8 +265,7 @@ describe LogStash::Outputs::ElasticSearch do
253
265
  before do
254
266
  allow(subject).to receive(:retrying_submit).with(anything)
255
267
  events.each_with_index do |e,i|
256
- et = events_tuples[i]
257
- allow(subject).to receive(:event_action_tuple).with(e).and_return(et)
268
+ allow(subject).to receive(:event_action_tuple).with(e).and_return(events_tuples[i])
258
269
  end
259
270
  subject.multi_receive(events)
260
271
  end
@@ -325,7 +336,7 @@ describe LogStash::Outputs::ElasticSearch do
325
336
  }
326
337
  }]
327
338
  }
328
- end
339
+ end
329
340
 
330
341
  before(:each) do
331
342
  allow(subject.client).to receive(:bulk_send).with(instance_of(StringIO), instance_of(Array)) do |stream, actions|
@@ -345,7 +356,7 @@ describe LogStash::Outputs::ElasticSearch do
345
356
 
346
357
  it "should log specific error message" do
347
358
  expect(subject.logger).to receive(:error).with(/Encountered an unexpected error/i,
348
- hash_including(:error_message => 'Sent 2 documents but Elasticsearch returned 3 responses (likely a bug with _bulk endpoint)'))
359
+ hash_including(:message => 'Sent 2 documents but Elasticsearch returned 3 responses (likely a bug with _bulk endpoint)'))
349
360
 
350
361
  subject.multi_receive(events)
351
362
  end
@@ -402,7 +413,7 @@ describe LogStash::Outputs::ElasticSearch do
402
413
 
403
414
  before do
404
415
  # Expect a timeout to be logged.
405
- expect(subject.logger).to receive(:error).with(/Attempted to send a bulk request to Elasticsearch/i, anything).at_least(:once)
416
+ expect(subject.logger).to receive(:error).with(/Attempted to send a bulk request/i, anything).at_least(:once)
406
417
  expect(subject.client).to receive(:bulk).at_least(:twice).and_call_original
407
418
  end
408
419
 
@@ -416,13 +427,14 @@ describe LogStash::Outputs::ElasticSearch do
416
427
  end
417
428
 
418
429
  describe "the action option" do
430
+
419
431
  context "with a sprintf action" do
420
432
  let(:options) { {"action" => "%{myactionfield}" } }
421
433
 
422
434
  let(:event) { LogStash::Event.new("myactionfield" => "update", "message" => "blah") }
423
435
 
424
436
  it "should interpolate the requested action value when creating an event_action_tuple" do
425
- expect(subject.event_action_tuple(event).first).to eql("update")
437
+ expect(subject.send(:event_action_tuple, event).first).to eql("update")
426
438
  end
427
439
  end
428
440
 
@@ -432,7 +444,7 @@ describe LogStash::Outputs::ElasticSearch do
432
444
  let(:event) { LogStash::Event.new("myactionfield" => "update", "message" => "blah") }
433
445
 
434
446
  it "should obtain specific action's params from event_action_tuple" do
435
- expect(subject.event_action_tuple(event)[1]).to include(:_upsert)
447
+ expect(subject.send(:event_action_tuple, event)[1]).to include(:_upsert)
436
448
  end
437
449
  end
438
450
 
@@ -440,6 +452,8 @@ describe LogStash::Outputs::ElasticSearch do
440
452
  let(:options) { {"action" => "SOME Garbaaage"} }
441
453
  let(:do_register) { false } # this is what we want to test, so we disable the before(:each) call
442
454
 
455
+ before { allow(subject).to receive(:finish_register) }
456
+
443
457
  it "should raise a configuration error" do
444
458
  expect { subject.register }.to raise_error(LogStash::ConfigurationError)
445
459
  end
@@ -447,13 +461,14 @@ describe LogStash::Outputs::ElasticSearch do
447
461
  end
448
462
 
449
463
  describe "the pipeline option" do
464
+
450
465
  context "with a sprintf and set pipeline" do
451
466
  let(:options) { {"pipeline" => "%{pipeline}" } }
452
467
 
453
468
  let(:event) { LogStash::Event.new("pipeline" => "my-ingest-pipeline") }
454
469
 
455
470
  it "should interpolate the pipeline value and set it" do
456
- expect(subject.event_action_tuple(event)[1]).to include(:pipeline => "my-ingest-pipeline")
471
+ expect(subject.send(:event_action_tuple, event)[1]).to include(:pipeline => "my-ingest-pipeline")
457
472
  end
458
473
  end
459
474
 
@@ -463,7 +478,7 @@ describe LogStash::Outputs::ElasticSearch do
463
478
  let(:event) { LogStash::Event.new("pipeline" => "") }
464
479
 
465
480
  it "should interpolate the pipeline value but not set it because it is empty" do
466
- expect(subject.event_action_tuple(event)[1]).not_to include(:pipeline)
481
+ expect(subject.send(:event_action_tuple, event)[1]).not_to include(:pipeline)
467
482
  end
468
483
  end
469
484
  end
@@ -505,8 +520,8 @@ describe LogStash::Outputs::ElasticSearch do
505
520
 
506
521
  it "should not set the retry_on_conflict parameter when creating an event_action_tuple" do
507
522
  allow(subject.client).to receive(:maximum_seen_major_version).and_return(maximum_seen_major_version)
508
- action, params, event_data = subject.event_action_tuple(event)
509
- expect(params).not_to include({subject.retry_on_conflict_action_name => num_retries})
523
+ action, params, event_data = subject.send(:event_action_tuple, event)
524
+ expect(params).not_to include({subject.send(:retry_on_conflict_action_name) => num_retries})
510
525
  end
511
526
  end
512
527
 
@@ -514,8 +529,8 @@ describe LogStash::Outputs::ElasticSearch do
514
529
  let(:options) { super().merge("action" => "update", "retry_on_conflict" => num_retries, "document_id" => 1) }
515
530
 
516
531
  it "should set the retry_on_conflict parameter when creating an event_action_tuple" do
517
- action, params, event_data = subject.event_action_tuple(event)
518
- expect(params).to include({subject.retry_on_conflict_action_name => num_retries})
532
+ action, params, event_data = subject.send(:event_action_tuple, event)
533
+ expect(params).to include({subject.send(:retry_on_conflict_action_name) => num_retries})
519
534
  end
520
535
  end
521
536
 
@@ -523,8 +538,8 @@ describe LogStash::Outputs::ElasticSearch do
523
538
  let(:options) { super().merge("action" => "%{myactionfield}", "retry_on_conflict" => num_retries, "document_id" => 1) }
524
539
 
525
540
  it "should set the retry_on_conflict parameter when creating an event_action_tuple" do
526
- action, params, event_data = subject.event_action_tuple(event)
527
- expect(params).to include({subject.retry_on_conflict_action_name => num_retries})
541
+ action, params, event_data = subject.send(:event_action_tuple, event)
542
+ expect(params).to include({subject.send(:retry_on_conflict_action_name) => num_retries})
528
543
  expect(action).to eq("update")
529
544
  end
530
545
  end
@@ -554,6 +569,8 @@ describe LogStash::Outputs::ElasticSearch do
554
569
  let(:do_register) { false }
555
570
 
556
571
  before :each do
572
+ allow(subject).to receive(:finish_register)
573
+
557
574
  allow(::Manticore::Client).to receive(:new).with(any_args).and_call_original
558
575
  end
559
576
 
@@ -577,6 +594,12 @@ describe LogStash::Outputs::ElasticSearch do
577
594
  let(:custom_parameters_hash) { { "id" => 1, "name" => "logstash" } }
578
595
  let(:custom_parameters_query) { custom_parameters_hash.map {|k,v| "#{k}=#{v}" }.join("&") }
579
596
 
597
+ let(:stub_http_client_pool!) do
598
+ [:start_resurrectionist, :start_sniffer, :healthcheck!].each do |method|
599
+ allow_any_instance_of(LogStash::Outputs::ElasticSearch::HttpClient::Pool).to receive(method)
600
+ end
601
+ end
602
+
580
603
  context "using non-url hosts" do
581
604
 
582
605
  let(:options) {
@@ -741,9 +764,9 @@ describe LogStash::Outputs::ElasticSearch do
741
764
 
742
765
  context 'when getting any other exception' do
743
766
  it 'should log at WARN level' do
744
- dlog = double_logger = double("logger").as_null_object
745
- subject.instance_variable_set(:@logger, dlog)
746
- expect(dlog).to receive(:warn).with(/Could not index/, hash_including(:status, :action, :response))
767
+ logger = double("logger").as_null_object
768
+ subject.instance_variable_set(:@logger, logger)
769
+ expect(logger).to receive(:warn).with(/Could not index/, hash_including(:status, :action, :response))
747
770
  mock_response = { 'index' => { 'error' => { 'type' => 'illegal_argument_exception' } } }
748
771
  subject.handle_dlq_status("Could not index event to Elasticsearch.",
749
772
  [:action, :params, :event], :some_status, mock_response)
@@ -752,9 +775,9 @@ describe LogStash::Outputs::ElasticSearch do
752
775
 
753
776
  context 'when the response does not include [error]' do
754
777
  it 'should not fail, but just log a warning' do
755
- dlog = double_logger = double("logger").as_null_object
756
- subject.instance_variable_set(:@logger, dlog)
757
- expect(dlog).to receive(:warn).with(/Could not index/, hash_including(:status, :action, :response))
778
+ logger = double("logger").as_null_object
779
+ subject.instance_variable_set(:@logger, logger)
780
+ expect(logger).to receive(:warn).with(/Could not index/, hash_including(:status, :action, :response))
758
781
  mock_response = { 'index' => {} }
759
782
  expect do
760
783
  subject.handle_dlq_status("Could not index event to Elasticsearch.",
@@ -774,16 +797,59 @@ describe LogStash::Outputs::ElasticSearch do
774
797
  # We should still log when sending to the DLQ.
775
798
  # This shall be solved by another issue, however: logstash-output-elasticsearch#772
776
799
  it 'should send the event to the DLQ instead, and not log' do
777
- expect(dlq_writer).to receive(:write).once.with(:event, /Could not index/)
800
+ event = LogStash::Event.new("foo" => "bar")
801
+ expect(dlq_writer).to receive(:write).once.with(event, /Could not index/)
778
802
  mock_response = { 'index' => { 'error' => { 'type' => 'illegal_argument_exception' } } }
779
- subject.handle_dlq_status("Could not index event to Elasticsearch.",
780
- [:action, :params, :event], :some_status, mock_response)
803
+ action = LogStash::Outputs::ElasticSearch::EventActionTuple.new(:action, :params, event)
804
+ subject.handle_dlq_status("Could not index event to Elasticsearch.", action, 404, mock_response)
781
805
  end
782
806
  end
807
+
808
+ context 'with response status 400' do
809
+
810
+ let(:options) { super().merge 'document_id' => '%{foo}' }
811
+
812
+ let(:events) { [ LogStash::Event.new("foo" => "bar") ] }
813
+
814
+ let(:dlq_writer) { subject.instance_variable_get(:@dlq_writer) }
815
+
816
+ let(:bulk_response) do
817
+ {
818
+ "took"=>1, "ingest_took"=>11, "errors"=>true, "items"=>
819
+ [{
820
+ "index"=>{"_index"=>"bar", "_type"=>"_doc", "_id"=>'bar', "status"=>400,
821
+ "error"=>{"type" => "illegal_argument_exception", "reason" => "TEST" }
822
+ }
823
+ }]
824
+ }
825
+ end
826
+
827
+ before(:each) do
828
+ allow(subject.client).to receive(:bulk_send).and_return(bulk_response)
829
+ end
830
+
831
+ it "should write event to DLQ" do
832
+ expect(dlq_writer).to receive(:write).and_wrap_original do |method, *args|
833
+ expect( args.size ).to eql 2
834
+
835
+ event, reason = *args
836
+ expect( event ).to be_a LogStash::Event
837
+ expect( event ).to be events.first
838
+ expect( reason ).to start_with 'Could not index event to Elasticsearch. status: 400, action: ["index"'
839
+ expect( reason ).to match /_id=>"bar".*"foo"=>"bar".*response:.*"reason"=>"TEST"/
840
+
841
+ method.call(*args) # won't hurt to call LogStash::Util::DummyDeadLetterQueueWriter
842
+ end.once
843
+
844
+ event_action_tuples = subject.map_events(events)
845
+ subject.send(:submit, event_action_tuples)
846
+ end
847
+
848
+ end if LOGSTASH_VERSION > '7.0'
783
849
  end
784
850
 
785
851
  describe "custom headers" do
786
- let(:manticore_options) { subject.client.pool.adapter.manticore.instance_variable_get(:@options) }
852
+ let(:manticore_options) { subject.client.pool.adapter.manticore.instance_variable_get(:@options) }
787
853
 
788
854
  context "when set" do
789
855
  let(:headers) { { "X-Thing" => "Test" } }
@@ -856,6 +922,75 @@ describe LogStash::Outputs::ElasticSearch do
856
922
  end
857
923
  end
858
924
 
925
+ describe "post-register ES setup" do
926
+ let(:do_register) { false }
927
+ let(:es_version) { '7.10.0' } # DS default on LS 8.x
928
+ let(:options) { { 'hosts' => '127.0.0.1:9999' } }
929
+ let(:logger) { subject.logger }
930
+
931
+ before do
932
+ allow(logger).to receive(:error) # expect tracking
933
+
934
+ allow(subject).to receive(:last_es_version).and_return es_version
935
+ # make successful_connection? return true:
936
+ allow(subject).to receive(:maximum_seen_major_version).and_return Integer(es_version.split('.').first)
937
+ allow(subject).to receive(:stop_after_successful_connection_thread)
938
+ end
939
+
940
+ it "logs inability to retrieve uuid" do
941
+ allow(subject).to receive(:install_template)
942
+ allow(subject).to receive(:ilm_in_use?).and_return nil
943
+ subject.register
944
+ subject.send :wait_for_successful_connection
945
+
946
+ expect(logger).to have_received(:error).with(/Unable to retrieve Elasticsearch cluster uuid/i, anything)
947
+ end if LOGSTASH_VERSION >= '7.0.0'
948
+
949
+ it "logs template install failure" do
950
+ allow(subject).to receive(:discover_cluster_uuid)
951
+ allow(subject).to receive(:ilm_in_use?).and_return nil
952
+ subject.register
953
+ subject.send :wait_for_successful_connection
954
+
955
+ expect(logger).to have_received(:error).with(/Failed to install template/i, anything)
956
+ end
957
+
958
+ context 'error raised' do
959
+
960
+ let(:es_version) { '7.8.0' }
961
+ let(:options) { super().merge('data_stream' => 'true') }
962
+ let(:latch) { Concurrent::CountDownLatch.new }
963
+
964
+ before do
965
+ allow(subject).to receive(:install_template)
966
+ allow(subject).to receive(:discover_cluster_uuid)
967
+ allow(subject).to receive(:ilm_in_use?).and_return nil
968
+ # executes from the after_successful_connection thread :
969
+ allow(subject).to receive(:finish_register) { latch.wait }.and_call_original
970
+ subject.register
971
+ end
972
+
973
+ it 'keeps logging on multi_receive' do
974
+ allow(subject).to receive(:retrying_submit)
975
+ latch.count_down; sleep(1.0)
976
+
977
+ expect_logged_error = lambda do |count|
978
+ expect(logger).to have_received(:error).with(
979
+ /Elasticsearch setup did not complete normally, please review previously logged errors/i,
980
+ hash_including(message: 'A data_stream configuration is only supported since Elasticsearch 7.9.0 (detected version 7.8.0), please upgrade your cluster')
981
+ ).exactly(count).times
982
+ end
983
+
984
+ subject.multi_receive [ LogStash::Event.new('foo' => 1) ]
985
+ expect_logged_error.call(1)
986
+
987
+ subject.multi_receive [ LogStash::Event.new('foo' => 2) ]
988
+ expect_logged_error.call(2)
989
+ end
990
+
991
+ end
992
+ end
993
+
859
994
  @private
860
995
 
861
996
  def stub_manticore_client!(manticore_double = nil)