logstash-output-elasticsearch 11.2.1-java → 11.3.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.
@@ -94,6 +94,7 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
94
94
  require "logstash/outputs/elasticsearch/ilm"
95
95
  require "logstash/outputs/elasticsearch/data_stream_support"
96
96
  require 'logstash/plugin_mixins/ecs_compatibility_support'
97
+ require 'logstash/plugin_mixins/deprecation_logger_support'
97
98
 
98
99
  # Protocol agnostic methods
99
100
  include(LogStash::PluginMixins::ElasticSearch::Common)
@@ -102,7 +103,10 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
102
103
  include(LogStash::Outputs::ElasticSearch::Ilm)
103
104
 
104
105
  # ecs_compatibility option, provided by Logstash core or the support adapter.
105
- include(LogStash::PluginMixins::ECSCompatibilitySupport)
106
+ include(LogStash::PluginMixins::ECSCompatibilitySupport(:disabled, :v1, :v8))
107
+
108
+ # deprecation logger adapter for older Logstashes
109
+ include(LogStash::PluginMixins::DeprecationLoggerSupport)
106
110
 
107
111
  # Generic/API config options that any document indexer output needs
108
112
  include(LogStash::PluginMixins::ElasticSearch::APIConfigs)
@@ -300,6 +304,11 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
300
304
 
301
305
  @bulk_request_metrics = metric.namespace(:bulk_requests)
302
306
  @document_level_metrics = metric.namespace(:documents)
307
+
308
+ if ecs_compatibility == :v8
309
+ @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. " +
310
+ "Once ECS v8 and an updated release of this plugin are publicly available, you will need to update this plugin to resolve this warning.")
311
+ end
303
312
  end
304
313
 
305
314
  # @override post-register when ES connection established
@@ -493,7 +502,7 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
493
502
  @default_index = "logstash-%{+yyyy.MM.dd}"
494
503
  @default_ilm_rollover_alias = "logstash"
495
504
  @default_template_name = 'logstash'
496
- when :v1
505
+ when :v1, :v8
497
506
  @default_index = "ecs-logstash-%{+yyyy.MM.dd}"
498
507
  @default_ilm_rollover_alias = "ecs-logstash"
499
508
  @default_template_name = 'ecs-logstash'
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-elasticsearch'
3
- s.version = '11.2.1'
3
+ s.version = '11.3.1'
4
4
 
5
5
  s.licenses = ['apache-2.0']
6
6
  s.summary = "Stores logs in Elasticsearch"
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_runtime_dependency 'stud', ['>= 0.0.17', '~> 0.0']
26
26
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
27
27
  s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~>1.0'
28
+ s.add_runtime_dependency 'logstash-mixin-deprecation_logger_support', '~>1.0'
28
29
 
29
30
  s.add_development_dependency 'logstash-codec-plain'
30
31
  s.add_development_dependency 'logstash-devutils'
@@ -12,6 +12,13 @@ describe "data streams", :integration => true do
12
12
 
13
13
  subject { LogStash::Outputs::ElasticSearch.new(options) }
14
14
 
15
+ # All data-streams features require that the plugin be run in a non-disabled ECS compatibility mode.
16
+ # We run the plugin in ECS by default, and add test scenarios specifically for it being disabled.
17
+ let(:ecs_compatibility) { :v1 }
18
+ before(:each) do
19
+ allow( subject ).to receive(:ecs_compatibility).and_return(ecs_compatibility)
20
+ end
21
+
15
22
  before :each do
16
23
  @es = get_client
17
24
  @es.delete_by_query(index: ".ds-#{ds_name}-*", expand_wildcards: :all, body: { query: { match_all: {} } }) rescue nil
@@ -1,8 +1,12 @@
1
1
  require_relative "../../../spec/es_spec_helper"
2
2
 
3
3
  describe "index template expected behavior", :integration => true do
4
+ let(:ecs_compatibility) { fail('spec group does not define `ecs_compatibility`!') }
5
+
4
6
  subject! do
5
7
  require "logstash/outputs/elasticsearch"
8
+ allow_any_instance_of(LogStash::Outputs::ElasticSearch).to receive(:ecs_compatibility).and_return(ecs_compatibility)
9
+
6
10
  settings = {
7
11
  "manage_template" => true,
8
12
  "template_overwrite" => true,
@@ -11,86 +15,117 @@ describe "index template expected behavior", :integration => true do
11
15
  next LogStash::Outputs::ElasticSearch.new(settings)
12
16
  end
13
17
 
14
- before :each do
15
- # Delete all templates first.
16
- require "elasticsearch"
18
+ let(:elasticsearch_client) { get_client }
17
19
 
18
- # Clean ES of data before we start.
19
- @es = get_client
20
- @es.indices.delete_template(:name => "*")
20
+ before(:each) do
21
+ # delete indices and templates
22
+ require "elasticsearch"
21
23
 
24
+ elasticsearch_client.indices.delete_template(:name => '*')
22
25
  # This can fail if there are no indexes, ignore failure.
23
- @es.indices.delete(:index => "*") rescue nil
24
-
25
- subject.register
26
-
27
- subject.multi_receive([
28
- LogStash::Event.new("message" => "sample message here"),
29
- LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
30
- LogStash::Event.new("somevalue" => 100),
31
- LogStash::Event.new("somevalue" => 10),
32
- LogStash::Event.new("somevalue" => 1),
33
- LogStash::Event.new("country" => "us"),
34
- LogStash::Event.new("country" => "at"),
35
- LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
36
- ])
37
-
38
- @es.indices.refresh
39
-
40
- # Wait or fail until everything's indexed.
41
- Stud::try(20.times) do
42
- r = @es.search(index: 'logstash-*')
43
- expect(r).to have_hits(8)
44
- end
26
+ elasticsearch_client.indices.delete(:index => '*') rescue nil
45
27
  end
46
28
 
47
- it "permits phrase searching on string fields" do
48
- results = @es.search(:q => "message:\"sample message\"")
49
- expect(results).to have_hits(1)
50
- expect(results["hits"]["hits"][0]["_source"]["message"]).to eq("sample message here")
51
- end
29
+ context 'with ecs_compatibility => disabled' do
30
+ let(:ecs_compatibility) { :disabled }
31
+ before :each do
32
+ @es = elasticsearch_client # cache as ivar for tests...
33
+
34
+ subject.register
35
+
36
+ subject.multi_receive([
37
+ LogStash::Event.new("message" => "sample message here"),
38
+ LogStash::Event.new("somemessage" => { "message" => "sample nested message here" }),
39
+ LogStash::Event.new("somevalue" => 100),
40
+ LogStash::Event.new("somevalue" => 10),
41
+ LogStash::Event.new("somevalue" => 1),
42
+ LogStash::Event.new("country" => "us"),
43
+ LogStash::Event.new("country" => "at"),
44
+ LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0 ] })
45
+ ])
46
+
47
+ @es.indices.refresh
48
+
49
+ # Wait or fail until everything's indexed.
50
+ Stud::try(20.times) do
51
+ r = @es.search(index: 'logstash-*')
52
+ expect(r).to have_hits(8)
53
+ end
54
+ end
52
55
 
53
- it "numbers dynamically map to a numeric type and permit range queries" do
54
- results = @es.search(:q => "somevalue:[5 TO 105]")
55
- expect(results).to have_hits(2)
56
+ it "permits phrase searching on string fields" do
57
+ results = @es.search(:q => "message:\"sample message\"")
58
+ expect(results).to have_hits(1)
59
+ expect(results["hits"]["hits"][0]["_source"]["message"]).to eq("sample message here")
60
+ end
56
61
 
57
- values = results["hits"]["hits"].collect { |r| r["_source"]["somevalue"] }
58
- expect(values).to include(10)
59
- expect(values).to include(100)
60
- expect(values).to_not include(1)
61
- end
62
+ it "numbers dynamically map to a numeric type and permit range queries" do
63
+ results = @es.search(:q => "somevalue:[5 TO 105]")
64
+ expect(results).to have_hits(2)
62
65
 
63
- it "does not create .keyword field for top-level message field" do
64
- results = @es.search(:q => "message.keyword:\"sample message here\"")
65
- expect(results).to have_hits(0)
66
- end
66
+ values = results["hits"]["hits"].collect { |r| r["_source"]["somevalue"] }
67
+ expect(values).to include(10)
68
+ expect(values).to include(100)
69
+ expect(values).to_not include(1)
70
+ end
67
71
 
68
- it "creates .keyword field for nested message fields" do
69
- results = @es.search(:q => "somemessage.message.keyword:\"sample nested message here\"")
70
- expect(results).to have_hits(1)
71
- end
72
+ it "does not create .keyword field for top-level message field" do
73
+ results = @es.search(:q => "message.keyword:\"sample message here\"")
74
+ expect(results).to have_hits(0)
75
+ end
72
76
 
73
- it "creates .keyword field from any string field which is not_analyzed" do
74
- results = @es.search(:q => "country.keyword:\"us\"")
75
- expect(results).to have_hits(1)
76
- expect(results["hits"]["hits"][0]["_source"]["country"]).to eq("us")
77
+ it "creates .keyword field for nested message fields" do
78
+ results = @es.search(:q => "somemessage.message.keyword:\"sample nested message here\"")
79
+ expect(results).to have_hits(1)
80
+ end
77
81
 
78
- # partial or terms should not work.
79
- results = @es.search(:q => "country.keyword:\"u\"")
80
- expect(results).to have_hits(0)
81
- end
82
+ it "creates .keyword field from any string field which is not_analyzed" do
83
+ results = @es.search(:q => "country.keyword:\"us\"")
84
+ expect(results).to have_hits(1)
85
+ expect(results["hits"]["hits"][0]["_source"]["country"]).to eq("us")
86
+
87
+ # partial or terms should not work.
88
+ results = @es.search(:q => "country.keyword:\"u\"")
89
+ expect(results).to have_hits(0)
90
+ end
91
+
92
+ it "make [geoip][location] a geo_point" do
93
+ expect(field_properties_from_template("logstash", "geoip")["location"]["type"]).to eq("geo_point")
94
+ end
95
+
96
+ it "aggregate .keyword results correctly " do
97
+ results = @es.search(:body => { "aggregations" => { "my_agg" => { "terms" => { "field" => "country.keyword" } } } })["aggregations"]["my_agg"]
98
+ terms = results["buckets"].collect { |b| b["key"] }
82
99
 
83
- it "make [geoip][location] a geo_point" do
84
- expect(field_properties_from_template("logstash", "geoip")["location"]["type"]).to eq("geo_point")
100
+ expect(terms).to include("us")
101
+
102
+ # 'at' is a stopword, make sure stopwords are not ignored.
103
+ expect(terms).to include("at")
104
+ end
85
105
  end
86
106
 
87
- it "aggregate .keyword results correctly " do
88
- results = @es.search(:body => { "aggregations" => { "my_agg" => { "terms" => { "field" => "country.keyword" } } } })["aggregations"]["my_agg"]
89
- terms = results["buckets"].collect { |b| b["key"] }
107
+ context 'with ECS enabled' do
108
+ let(:ecs_compatibility) { :v1 }
109
+
110
+ before(:each) do
111
+ subject.register # should load template?
112
+ subject.multi_receive([LogStash::Event.new("message" => "sample message here")])
113
+ end
90
114
 
91
- expect(terms).to include("us")
115
+ let(:elasticsearch_cluster_major_version) do
116
+ elasticsearch_client.info&.dig("version", "number" )&.split('.')&.map(&:to_i)&.first
117
+ end
92
118
 
93
- # 'at' is a stopword, make sure stopwords are not ignored.
94
- expect(terms).to include("at")
119
+ it 'loads the templates' do
120
+ aggregate_failures do
121
+ if elasticsearch_cluster_major_version >= 8
122
+ # In ES 8+ we use the _index_template API
123
+ expect(elasticsearch_client.indices.exists_index_template(name: 'ecs-logstash')).to be_truthy
124
+ else
125
+ # Otherwise, we used the legacy _template API
126
+ expect(elasticsearch_client.indices.exists_template(name: 'ecs-logstash')).to be_truthy
127
+ end
128
+ end
129
+ end
95
130
  end
96
131
  end
@@ -4,9 +4,17 @@ require "logstash/outputs/elasticsearch/data_stream_support"
4
4
  describe LogStash::Outputs::ElasticSearch::DataStreamSupport do
5
5
 
6
6
  subject { LogStash::Outputs::ElasticSearch.new(options) }
7
+
7
8
  let(:options) { { 'hosts' => [ 'localhost:12345' ] } }
8
9
  let(:es_version) { '7.10.1' }
9
10
 
11
+ # All data-streams features require that the plugin be run in a non-disabled ECS compatibility mode.
12
+ # We run the plugin in ECS by default, and add test scenarios specifically for it being disabled.
13
+ let(:ecs_compatibility) { :v1 }
14
+ before(:each) do
15
+ allow_any_instance_of(LogStash::Outputs::ElasticSearch).to receive(:ecs_compatibility).and_return(ecs_compatibility)
16
+ end
17
+
10
18
  let(:do_register) { false }
11
19
  let(:stub_plugin_register!) do
12
20
  allow(subject).to receive(:last_es_version).and_return(es_version)
@@ -52,9 +60,7 @@ describe LogStash::Outputs::ElasticSearch::DataStreamSupport do
52
60
  end
53
61
 
54
62
  it "warns when configuration is data-stream compliant (LS 7.x)" do
55
- expect( subject.logger ).to receive(:warn) do |msg|
56
- expect(msg).to include "Configuration is data stream compliant but due backwards compatibility Logstash 7.x"
57
- end
63
+ expect( subject.logger ).to receive(:warn).with(a_string_including "Configuration is data stream compliant but due backwards compatibility Logstash 7.x")
58
64
  change_constant :LOGSTASH_VERSION, '7.11.0' do
59
65
  expect( subject.data_stream_config? ).to be false
60
66
  end
@@ -66,6 +72,25 @@ describe LogStash::Outputs::ElasticSearch::DataStreamSupport do
66
72
  end
67
73
  end
68
74
 
75
+ context 'ecs_compatibility disabled' do
76
+ let(:ecs_compatibility) { :disabled }
77
+
78
+ {
79
+ '7.x (pre-DS)' => '7.9.0',
80
+ '7.x (with DS)' => '7.11.0',
81
+ '8.0' => '8.0.0',
82
+ '8.x' => '8.1.2',
83
+ }.each do |ls_version_desc, ls_version|
84
+ context "on LS #{ls_version_desc}" do
85
+ around(:each) { |example| change_constant(:LOGSTASH_VERSION, ls_version, &example) }
86
+ it "does not use data-streams" do
87
+ expect( subject.logger ).to receive(:debug).with(a_string_including "ecs_compatibility is not enabled")
88
+ expect( subject.data_stream_config? ).to be false
89
+ end
90
+ end
91
+ end
92
+ end
93
+
69
94
  context 'non-compatible ES' do
70
95
 
71
96
  let(:es_version) { '7.8.0' }
@@ -95,6 +120,7 @@ describe LogStash::Outputs::ElasticSearch::DataStreamSupport do
95
120
  before { allow(subject).to receive(:last_es_version).and_return(es_version) }
96
121
 
97
122
  it "does not use data-streams on LS 7.x" do
123
+ expect( subject.logger ).to receive(:warn).with(a_string_including "Logstash 7.x will not assume writing to a data-stream")
98
124
  change_constant :LOGSTASH_VERSION, '7.10.0' do
99
125
  expect( subject.data_stream_config? ).to be false
100
126
  end
@@ -197,12 +223,34 @@ describe LogStash::Outputs::ElasticSearch::DataStreamSupport do
197
223
  end
198
224
  end
199
225
 
200
- it "does use data-streams on LS 8.0" do
226
+ it "does use data-streams on LS 8.x" do
201
227
  change_constant :LOGSTASH_VERSION, '8.1.0' do
202
228
  expect( subject.data_stream_config? ).to be true
203
229
  end
204
230
  end
205
231
 
232
+ context 'with ecs_compatibility disabled' do
233
+ let(:ecs_compatibility) { :disabled }
234
+
235
+ context 'when running on LS 7.x' do
236
+ around(:each) { |example| change_constant(:LOGSTASH_VERSION, '7.15.1', &example) }
237
+
238
+ it "emits a deprecation warning and uses data streams anway" do
239
+ expect( subject.deprecation_logger ).to receive(:deprecated).with(a_string_including "`data_stream => true` will require the plugin to be run in ECS compatibility mode")
240
+ expect( subject.data_stream_config? ).to be true
241
+ end
242
+ end
243
+
244
+ context 'when running on LS 8.x' do
245
+ around(:each) { |example| change_constant(:LOGSTASH_VERSION, '8.0.0', &example) }
246
+
247
+ it "errors helpfully" do
248
+ expect{ subject.data_stream_config? }.to raise_error(LogStash::ConfigurationError, a_string_including("Invalid data stream configuration: `ecs_compatibility => disabled`"))
249
+ end
250
+ end
251
+
252
+ end
253
+
206
254
  context 'non-compatible ES' do
207
255
 
208
256
  let(:es_version) { '6.8.11' }
@@ -27,6 +27,12 @@ describe LogStash::Outputs::ElasticSearch::TemplateManager do
27
27
  end
28
28
  end
29
29
 
30
+ context 'when ECS v8 is requested' do
31
+ it 'resolves' do
32
+ expect(described_class.default_template_path(7, :v8)).to end_with("/templates/ecs-v8/elasticsearch-7x.json")
33
+ end
34
+ end
35
+
30
36
  describe "index template with ilm settings" do
31
37
  let(:plugin_settings) { {"manage_template" => true, "template_overwrite" => true} }
32
38
  let(:plugin) { LogStash::Outputs::ElasticSearch.new(plugin_settings) }
@@ -4,6 +4,8 @@ require "flores/random"
4
4
  require 'concurrent/atomic/count_down_latch'
5
5
  require "logstash/outputs/elasticsearch"
6
6
 
7
+ require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
8
+
7
9
  describe LogStash::Outputs::ElasticSearch do
8
10
  subject(:elasticsearch_output_instance) { described_class.new(options) }
9
11
  let(:options) { {} }
@@ -922,6 +924,25 @@ describe LogStash::Outputs::ElasticSearch do
922
924
  end
923
925
  end
924
926
 
927
+ describe 'ECS Compatibility Support', :ecs_compatibility_support do
928
+ [
929
+ :disabled,
930
+ :v1,
931
+ :v8,
932
+ ].each do |ecs_compatibility|
933
+ context "When initialized with `ecs_compatibility => #{ecs_compatibility}`" do
934
+ let(:options) { Hash.new }
935
+ subject(:output) { described_class.new(options.merge("ecs_compatibility" => "#{ecs_compatibility}")) }
936
+ context 'when registered' do
937
+ before(:each) { output.register }
938
+ it 'has the correct effective ECS compatibility setting' do
939
+ expect(output.ecs_compatibility).to eq(ecs_compatibility)
940
+ end
941
+ end
942
+ end
943
+ end
944
+ end
945
+
925
946
  describe "post-register ES setup" do
926
947
  let(:do_register) { false }
927
948
  let(:es_version) { '7.10.0' } # DS default on LS 8.x
@@ -959,7 +980,7 @@ describe LogStash::Outputs::ElasticSearch do
959
980
  context 'error raised' do
960
981
 
961
982
  let(:es_version) { '7.8.0' }
962
- let(:options) { super().merge('data_stream' => 'true') }
983
+ let(:options) { super().merge('data_stream' => 'true', 'ecs_compatibility' => 'v1') }
963
984
  let(:latch) { Concurrent::CountDownLatch.new }
964
985
 
965
986
  before do
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.2.1
4
+ version: 11.3.1
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-14 00:00:00.000000000 Z
11
+ date: 2021-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -84,6 +84,20 @@ dependencies:
84
84
  - - "~>"
85
85
  - !ruby/object:Gem::Version
86
86
  version: '1.0'
87
+ - !ruby/object:Gem::Dependency
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: '1.0'
93
+ name: logstash-mixin-deprecation_logger_support
94
+ prerelease: false
95
+ type: :runtime
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '1.0'
87
101
  - !ruby/object:Gem::Dependency
88
102
  requirement: !ruby/object:Gem::Requirement
89
103
  requirements:
@@ -212,6 +226,9 @@ files:
212
226
  - lib/logstash/outputs/elasticsearch/templates/ecs-disabled/elasticsearch-8x.json
213
227
  - lib/logstash/outputs/elasticsearch/templates/ecs-v1/elasticsearch-6x.json
214
228
  - lib/logstash/outputs/elasticsearch/templates/ecs-v1/elasticsearch-7x.json
229
+ - lib/logstash/outputs/elasticsearch/templates/ecs-v1/elasticsearch-8x.json
230
+ - lib/logstash/outputs/elasticsearch/templates/ecs-v8/elasticsearch-7x.json
231
+ - lib/logstash/outputs/elasticsearch/templates/ecs-v8/elasticsearch-8x.json
215
232
  - lib/logstash/plugin_mixins/elasticsearch/api_configs.rb
216
233
  - lib/logstash/plugin_mixins/elasticsearch/common.rb
217
234
  - lib/logstash/plugin_mixins/elasticsearch/noop_license_checker.rb