logstash-input-elasticsearch 4.9.3 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc71917516d5297b151b09c3b26324272ee472fa8ae987fad6b30fa99492d382
4
- data.tar.gz: cd72359f663375ad910dbf02a70d151160e449311bff81c0f77d062c7625c597
3
+ metadata.gz: 84fb0092d51b303586c275c6cfaef3222391d7aabe910450a989291b691930c0
4
+ data.tar.gz: 955e27896dff25ec6568685f91cc7e34252bc54fbb5182133db1e4dd273efffe
5
5
  SHA512:
6
- metadata.gz: ea7bca9aa226958479061efab4172224039d10a93579ef482418ad6955c493c00a45b1372ce6bd61aaba07e6c89bc2e96d1236cfd4be2e326193b52805ca448f
7
- data.tar.gz: 0f08585317a26f8a647be73e4e70b9a421025f1c81bcfa8518c1188cb60a0efea49f131a1e80645bd920c0806bb8c54542da07ab1cab44b540313a062b8b351d
6
+ metadata.gz: 2be653a935384617b32905f441060326f2b45eadcaacbf727d1ebe5c82711e3e9f0f3a038b9ca39aad6377e67bb5caf78c8b83a625d82aa8fca267b738dc9cab
7
+ data.tar.gz: a19916b987c434dfeb396379fa9f552fd001901bc5b37ce60407e4b7df69f5bd3ff76d4122b2f71d27c5d37d983a1dd283dcdf3aa1693730e93c2875f2459a1a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 4.10.0
2
+ - Feat: added ecs_compatibility + event_factory support [#149](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/149)
3
+
1
4
  ## 4.9.3
2
5
  - Fixed SSL handshake hang indefinitely with proxy setup [#156](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/156)
3
6
 
@@ -6,6 +9,7 @@
6
9
  header isn't passed, this leads to the plugin not being able to leverage `user`/`password` credentials set by the user.
7
10
  [#153](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/153)
8
11
 
12
+
9
13
  ## 4.9.1
10
14
  - [DOC] Replaced hard-coded links with shared attributes [#143](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/143)
11
15
  - [DOC] Added missing quote to docinfo_fields example [#145](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/145)
data/docs/index.asciidoc CHANGED
@@ -83,8 +83,18 @@ Authentication to a secure Elasticsearch cluster is possible using _one_ of the
83
83
  Authorization to a secure Elasticsearch cluster requires `read` permission at index level and `monitoring` permissions at cluster level.
84
84
  The `monitoring` permission at cluster level is necessary to perform periodic connectivity checks.
85
85
 
86
+ [id="plugins-{type}s-{plugin}-ecs"]
87
+ ==== Compatibility with the Elastic Common Schema (ECS)
88
+
89
+ When ECS compatibility is disabled, `docinfo_target` uses the `"@metadata"` field as a default, with ECS enabled the plugin
90
+ uses a naming convention `"[@metadata][input][elasticsearch]"` as a default target for placing document information.
91
+
92
+ The plugin logs a warning when ECS is enabled and `target` isn't set.
93
+
94
+ TIP: Set the `target` option to avoid potential schema conflicts.
95
+
86
96
  [id="plugins-{type}s-{plugin}-options"]
87
- ==== Elasticsearch Input Configuration Options
97
+ ==== Elasticsearch Input configuration options
88
98
 
89
99
  This plugin supports the following configuration options plus the <<plugins-{type}s-{plugin}-common-options>> described later.
90
100
 
@@ -99,6 +109,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
99
109
  | <<plugins-{type}s-{plugin}-docinfo>> |<<boolean,boolean>>|No
100
110
  | <<plugins-{type}s-{plugin}-docinfo_fields>> |<<array,array>>|No
101
111
  | <<plugins-{type}s-{plugin}-docinfo_target>> |<<string,string>>|No
112
+ | <<plugins-{type}s-{plugin}-ecs_compatibility>> |<<string,string>>|No
102
113
  | <<plugins-{type}s-{plugin}-hosts>> |<<array,array>>|No
103
114
  | <<plugins-{type}s-{plugin}-index>> |<<string,string>>|No
104
115
  | <<plugins-{type}s-{plugin}-password>> |<<password,password>>|No
@@ -197,13 +208,14 @@ Example
197
208
  size => 500
198
209
  scroll => "5m"
199
210
  docinfo => true
211
+ docinfo_target => "[@metadata][doc]"
200
212
  }
201
213
  }
202
214
  output {
203
215
  elasticsearch {
204
- index => "copy-of-production.%{[@metadata][_index]}"
205
- document_type => "%{[@metadata][_type]}"
206
- document_id => "%{[@metadata][_id]}"
216
+ index => "copy-of-production.%{[@metadata][doc][_index]}"
217
+ document_type => "%{[@metadata][doc][_type]}"
218
+ document_id => "%{[@metadata][doc][_id]}"
207
219
  }
208
220
  }
209
221
 
@@ -214,8 +226,9 @@ Example
214
226
  input {
215
227
  elasticsearch {
216
228
  docinfo => true
229
+ docinfo_target => "[@metadata][doc]"
217
230
  add_field => {
218
- identifier => "%{[@metadata][_index]}:%{[@metadata][_type]}:%{[@metadata][_id]}"
231
+ identifier => "%{[@metadata][doc][_index]}:%{[@metadata][doc][_type]}:%{[@metadata][doc][_id]}"
219
232
  }
220
233
  }
221
234
  }
@@ -236,11 +249,25 @@ more information.
236
249
  ===== `docinfo_target`
237
250
 
238
251
  * Value type is <<string,string>>
239
- * Default value is `"@metadata"`
252
+ * Default value depends on whether <<plugins-{type}s-{plugin}-ecs_compatibility>> is enabled:
253
+ ** ECS Compatibility disabled: `"@metadata"`
254
+ ** ECS Compatibility enabled: `"[@metadata][input][elasticsearch]"`
255
+
256
+ If document metadata storage is requested by enabling the `docinfo` option,
257
+ this option names the field under which to store the metadata fields as subfields.
258
+
259
+ [id="plugins-{type}s-{plugin}-ecs_compatibility"]
260
+ ===== `ecs_compatibility`
261
+
262
+ * Value type is <<string,string>>
263
+ * Supported values are:
264
+ ** `disabled`: CSV data added at root level
265
+ ** `v1`,`v8`: Elastic Common Schema compliant behavior
266
+ * Default value depends on which version of Logstash is running:
267
+ ** When Logstash provides a `pipeline.ecs_compatibility` setting, its value is used as the default
268
+ ** Otherwise, the default value is `disabled`
240
269
 
241
- If document metadata storage is requested by enabling the `docinfo`
242
- option, this option names the field under which to store the metadata
243
- fields as subfields.
270
+ Controls this plugin's compatibility with the {ecs-ref}[Elastic Common Schema (ECS)].
244
271
 
245
272
  [id="plugins-{type}s-{plugin}-hosts"]
246
273
  ===== `hosts`
@@ -402,4 +429,4 @@ empty string authentication will be disabled.
402
429
  [id="plugins-{type}s-{plugin}-common-options"]
403
430
  include::{include_path}/{type}.asciidoc[]
404
431
 
405
- :default_codec!:
432
+ :no_codec!:
@@ -4,6 +4,9 @@ require "logstash/namespace"
4
4
  require "logstash/json"
5
5
  require "logstash/util/safe_uri"
6
6
  require 'logstash/plugin_mixins/validator_support/field_reference_validation_adapter'
7
+ require 'logstash/plugin_mixins/event_support/event_factory_adapter'
8
+ require 'logstash/plugin_mixins/ecs_compatibility_support'
9
+ require 'logstash/plugin_mixins/ecs_compatibility_support/target_check'
7
10
  require "base64"
8
11
 
9
12
  require "elasticsearch"
@@ -66,12 +69,16 @@ require_relative "elasticsearch/patches/_elasticsearch_transport_connections_sel
66
69
  #
67
70
  #
68
71
  class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
72
+
73
+ include LogStash::PluginMixins::ECSCompatibilitySupport(:disabled, :v1, :v8 => :v1)
74
+ include LogStash::PluginMixins::ECSCompatibilitySupport::TargetCheck
75
+
76
+ include LogStash::PluginMixins::EventSupport::EventFactoryAdapter
77
+
69
78
  extend LogStash::PluginMixins::ValidatorSupport::FieldReferenceValidationAdapter
70
79
 
71
80
  config_name "elasticsearch"
72
81
 
73
- default :codec, "json"
74
-
75
82
  # List of elasticsearch hosts to use for querying.
76
83
  # Each host can be either IP, HOST, IP:port or HOST:port.
77
84
  # Port defaults to 9200
@@ -128,8 +135,9 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
128
135
  #
129
136
  config :docinfo, :validate => :boolean, :default => false
130
137
 
131
- # Where to move the Elasticsearch document information. By default we use the @metadata field.
132
- config :docinfo_target, :validate=> :string, :default => LogStash::Event::METADATA
138
+ # Where to move the Elasticsearch document information.
139
+ # default: [@metadata][input][elasticsearch] in ECS mode, @metadata field otherwise
140
+ config :docinfo_target, :validate=> :field_reference
133
141
 
134
142
  # List of document metadata to move to the `docinfo_target` field.
135
143
  # To learn more about Elasticsearch metadata fields read
@@ -184,6 +192,14 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
184
192
  # If set, the _source of each hit will be added nested under the target instead of at the top-level
185
193
  config :target, :validate => :field_reference
186
194
 
195
+ def initialize(params={})
196
+ super(params)
197
+
198
+ if docinfo_target.nil?
199
+ @docinfo_target = ecs_select[disabled: '@metadata', v1: '[@metadata][input][elasticsearch]']
200
+ end
201
+ end
202
+
187
203
  def register
188
204
  require "rufus/scheduler"
189
205
 
@@ -297,47 +313,41 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
297
313
  [r['hits']['hits'].any?, r['_scroll_id']]
298
314
  rescue => e
299
315
  # this will typically be triggered by a scroll timeout
300
- logger.error("Scroll request error, aborting scroll", error: e.inspect)
316
+ logger.error("Scroll request error, aborting scroll", message: e.message, exception: e.class)
301
317
  # return no hits and original scroll_id so we can try to clear it
302
318
  [false, scroll_id]
303
319
  end
304
320
 
305
321
  def push_hit(hit, output_queue)
306
- if @target.nil?
307
- event = LogStash::Event.new(hit['_source'])
308
- else
309
- event = LogStash::Event.new
310
- event.set(@target, hit['_source'])
311
- end
312
-
313
- if @docinfo
314
- # do not assume event[@docinfo_target] to be in-place updatable. first get it, update it, then at the end set it in the event.
315
- docinfo_target = event.get(@docinfo_target) || {}
316
-
317
- unless docinfo_target.is_a?(Hash)
318
- @logger.error("Elasticsearch Input: Incompatible Event, incompatible type for the docinfo_target=#{@docinfo_target} field in the `_source` document, expected a hash got:", :docinfo_target_type => docinfo_target.class, :event => event)
322
+ event = targeted_event_factory.new_event hit['_source']
323
+ set_docinfo_fields(hit, event) if @docinfo
324
+ decorate(event)
325
+ output_queue << event
326
+ end
319
327
 
320
- # TODO: (colin) I am not sure raising is a good strategy here?
321
- raise Exception.new("Elasticsearch input: incompatible event")
322
- end
328
+ def set_docinfo_fields(hit, event)
329
+ # do not assume event[@docinfo_target] to be in-place updatable. first get it, update it, then at the end set it in the event.
330
+ docinfo_target = event.get(@docinfo_target) || {}
323
331
 
324
- @docinfo_fields.each do |field|
325
- docinfo_target[field] = hit[field]
326
- end
332
+ unless docinfo_target.is_a?(Hash)
333
+ @logger.error("Incompatible Event, incompatible type for the docinfo_target=#{@docinfo_target} field in the `_source` document, expected a hash got:", :docinfo_target_type => docinfo_target.class, :event => event.to_hash_with_metadata)
327
334
 
328
- event.set(@docinfo_target, docinfo_target)
335
+ # TODO: (colin) I am not sure raising is a good strategy here?
336
+ raise Exception.new("Elasticsearch input: incompatible event")
329
337
  end
330
338
 
331
- decorate(event)
339
+ @docinfo_fields.each do |field|
340
+ docinfo_target[field] = hit[field]
341
+ end
332
342
 
333
- output_queue << event
343
+ event.set(@docinfo_target, docinfo_target)
334
344
  end
335
345
 
336
346
  def clear_scroll(scroll_id)
337
347
  @client.clear_scroll(scroll_id: scroll_id) if scroll_id
338
348
  rescue => e
339
349
  # ignore & log any clear_scroll errors
340
- logger.warn("Ignoring clear_scroll exception", message: e.message)
350
+ logger.warn("Ignoring clear_scroll exception", message: e.message, exception: e.class)
341
351
  end
342
352
 
343
353
  def scroll_request scroll_id
@@ -447,6 +457,9 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
447
457
  [ cloud_auth.username, cloud_auth.password ]
448
458
  end
449
459
 
460
+ # @private used by unit specs
461
+ attr_reader :client
462
+
450
463
  module URIOrEmptyValidator
451
464
  ##
452
465
  # @override to provide :uri_or_empty validator
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-input-elasticsearch'
4
- s.version = '4.9.3'
4
+ s.version = '4.10.0'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "Reads query results from an Elasticsearch cluster"
7
7
  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"
@@ -20,17 +20,19 @@ Gem::Specification.new do |s|
20
20
  s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
21
21
 
22
22
  # Gem dependencies
23
- s.add_runtime_dependency "logstash-mixin-validator_support", '~> 1.0'
24
23
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
+ s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~> 1.3'
25
+ s.add_runtime_dependency 'logstash-mixin-event_support', '~> 1.0'
26
+ s.add_runtime_dependency "logstash-mixin-validator_support", '~> 1.0'
25
27
 
26
28
  s.add_runtime_dependency 'elasticsearch', '>= 5.0.5' # LS >= 6.7 and < 7.14 all used version 5.0.5
27
29
 
28
- s.add_runtime_dependency 'logstash-codec-json'
29
- s.add_runtime_dependency 'sequel'
30
30
  s.add_runtime_dependency 'tzinfo'
31
31
  s.add_runtime_dependency 'tzinfo-data'
32
32
  s.add_runtime_dependency 'rufus-scheduler'
33
33
  s.add_runtime_dependency 'manticore', ">= 0.7.1"
34
+
35
+ s.add_development_dependency 'logstash-codec-plain'
34
36
  s.add_development_dependency 'faraday', "~> 0.15.4"
35
37
  s.add_development_dependency 'logstash-devutils'
36
38
  s.add_development_dependency 'timecop'
@@ -0,0 +1,20 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDMTCCAhmgAwIBAgIUCJ5+zdYJIlL04EOwC0tqVbZYKQUwDQYJKoZIhvcNAQEL
3
+ BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
4
+ cmF0ZWQgQ0EwHhcNMjEwODEyMDUxNTI3WhcNMjQwODExMDUxNTI3WjANMQswCQYD
5
+ VQQDEwJsczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMFY71j9Proa
6
+ x95bWoBQOcc0ncqVvQO+Tk/Do4ynoe64pOJEf3txh1viHbnzFUGf+NF5WW6trlZ2
7
+ ErP81vy7Ds5J5ngXjjdzOOGsTs9+l7KkqPfUwXqGoldWFtr//9mkLvWpd8uPvVtO
8
+ dRnpcjQSlHHEB/HaqxkyBAvHLv1Fi1jTgIgn32NEM2mlCJ3M8OVfO9pqlO/6gjjs
9
+ Miow8zZqtczeuv0JPu7V5xPDrcX0xh0kZdpH4gSh9r314TwZXFCofNUbkZrPV+Q9
10
+ XJs64NlBjJZkd5qwKeXujZRV4eVvAOTlp+4Nh4eDqXE323s5yiPuov0StvNrbh3d
11
+ rcg+IM+RTdMCAwEAAaNiMGAwHQYDVR0OBBYEFGnXHJEJ+LGmQTqDNr50C8FE8pcF
12
+ MB8GA1UdIwQYMBaAFMgkye5+2l+TE0I6RsXRHjGBwpBGMBMGA1UdEQQMMAqCCGxv
13
+ Z3N0YXNoMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBAI08C6IeweN3LrEq
14
+ ZauDVoiE2IdA1/nN3sxl+wL2xfauv1nctxej9TYR3mNoWiacgbbfJkPMCSIYk2Vc
15
+ G396yLiGC1V96FfonnKfr3tKd0BiijTu3u5pOTgNNf5n4TZaTHTYmuKPtWoXyuLR
16
+ QbH3jdgq9aq/9bwK0E5FOmuv6LGatnKzLf56aHjzerSZCnRw7V/1J/Yj3cy6TB1l
17
+ 9Lc7IAk4dGyrgwfKCuZOSzAtCWpOA/FfqCqMSuW6lrZ1zAXnk6VI3RkmBCuLE6kj
18
+ aAjwORJHyiwBsMQbaYcQaXXjhguS+iHrnWdR0DFs9gHJSTuf6EoOeygdtMDutb2O
19
+ 4xfHWG8=
20
+ -----END CERTIFICATE-----
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpAIBAAKCAQEAwVjvWP0+uhrH3ltagFA5xzSdypW9A75OT8OjjKeh7rik4kR/
3
+ e3GHW+IdufMVQZ/40XlZbq2uVnYSs/zW/LsOzknmeBeON3M44axOz36XsqSo99TB
4
+ eoaiV1YW2v//2aQu9al3y4+9W051GelyNBKUccQH8dqrGTIEC8cu/UWLWNOAiCff
5
+ Y0QzaaUInczw5V872mqU7/qCOOwyKjDzNmq1zN66/Qk+7tXnE8OtxfTGHSRl2kfi
6
+ BKH2vfXhPBlcUKh81RuRms9X5D1cmzrg2UGMlmR3mrAp5e6NlFXh5W8A5OWn7g2H
7
+ h4OpcTfbeznKI+6i/RK282tuHd2tyD4gz5FN0wIDAQABAoIBAGLHVvC14PgfeoEl
8
+ VuU7F2moffzj5z8kWMnzf3j6o4ZcmxBmQmMEq0zMBrfbcr6mRe5u+rvKy8isZf3C
9
+ bOuNfZDyvGYaUrQNj7/r0g+78zB3Y0PKVFaOth28g8y7ATFl6f/j5qn+85TUTotA
10
+ cvIbk+9TYWO0fblPjjWeO2l1wC1ObV0pFrXVzthFTQk0oxl3Gyq54P5rPp7QPOdM
11
+ jB0lSAhvkEEA7nIZ0dF1zm3RuByahSQC45kYEp5TCC8SDwO3WCJ32Q/dhPw0y9Go
12
+ gbIEY9QBFc8Rn3HDYGTSRPVVDM3HctDqzCihWOgFQlv718yCAZYq43fdOcy+6BY/
13
+ UT3xRhECgYEA5wWcYD8bY5x0fk2ubxKJTE4Fm2HvUrexvLX00yF3sX9XqrsiBBC4
14
+ 14mB2yFEKQL+M/ZqLNV9IfJhfRmBffoRvf9lAuHhUrw4wGijERoO9xkmS3lGvzw+
15
+ hqLIMnd986wyWC8FdU+dStDg8PC97xK4bg0tKYo9jmKf3kb0Ov2UWQ0CgYEA1kCK
16
+ w30P3ZgYakXUjbwv3KoRXIVm6cIqgvm8iPh7B0GeTUCIgGBSNzJ8LVts/m6V7xtU
17
+ RJ8RKw2gqqUTiFqrRKefr0APFv0YeVgZ7zK2EGLrL2rFWNZZQqA97Mh/5CwFh+zs
18
+ 1/IYuqRUVDaLq0sAPcZA5KEoO91eChBVK/RAyl8CgYAqgVPGOZY2e6DLZEuF0ClG
19
+ yswpTJmV5IplKC1Fc1DsbXuZxBh8Gv+HWJt1z+cUjKJsuRfL6/O7/TaGp9y1av88
20
+ r/LL1vd4G31tmVL3YI4EVLJBDK1Bnjn615RyBJ496R7SLsSYUu+jxk68xe6MQCuC
21
+ xBXdILw2qFq1sORavjE/OQKBgQCJlwNGDX9t2Cn9vYCF0Q+Pjyv9FbKEdevlFsor
22
+ 0B76BvrJM6M1hiXmSqaSXj89mfjxh8RzGQ/mbSb7z20eyNNqEJes7N+D7N+Vta1Z
23
+ /mALX+sXFWNM7MJ/1fZOpGf1OQwIQW/MMi4NVlDNkAXb6BtskG/GI3R6FWw53ElG
24
+ I+Kj0wKBgQDUCfiYYSA9wYug53uvE0LirZwMQjWTbqxMO/S3H0Be8rf+BLo+YY5X
25
+ fF6L/NaKxNZzs2Uu6+xYLXhSMimiv8412t7qnjK5DLwTZfnj7EuNxd44cZ4cXDPx
26
+ JtD9GgPJ5V3js1gA2usPnKLYPw5Pp3ayZn1q4Tg9A5cextKnyOV/Fg==
27
+ -----END RSA PRIVATE KEY-----
@@ -8,13 +8,11 @@ require "stud/temporary"
8
8
  require "time"
9
9
  require "date"
10
10
 
11
- class LogStash::Inputs::TestableElasticsearch < LogStash::Inputs::Elasticsearch
12
- attr_reader :client
13
- end
11
+ require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
14
12
 
15
- describe LogStash::Inputs::TestableElasticsearch do
13
+ describe LogStash::Inputs::Elasticsearch, :ecs_compatibility_support do
16
14
 
17
- let(:plugin) { LogStash::Inputs::TestableElasticsearch.new(config) }
15
+ let(:plugin) { described_class.new(config) }
18
16
  let(:queue) { Queue.new }
19
17
 
20
18
  it_behaves_like "an interruptible input plugin" do
@@ -40,7 +38,13 @@ describe LogStash::Inputs::TestableElasticsearch do
40
38
  end
41
39
  end
42
40
 
43
- context 'creating events from Elasticsearch' do
41
+
42
+ ecs_compatibility_matrix(:disabled, :v1, :v8) do |ecs_select|
43
+
44
+ before(:each) do
45
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
46
+ end
47
+
44
48
  let(:config) do
45
49
  %q[
46
50
  input {
@@ -97,7 +101,6 @@ describe LogStash::Inputs::TestableElasticsearch do
97
101
  end
98
102
 
99
103
  expect(event).to be_a(LogStash::Event)
100
- puts event.to_hash_with_metadata
101
104
  expect(event.get("message")).to eql [ "ohayo" ]
102
105
  end
103
106
 
@@ -120,10 +123,10 @@ describe LogStash::Inputs::TestableElasticsearch do
120
123
  end
121
124
 
122
125
  expect(event).to be_a(LogStash::Event)
123
- puts event.to_hash_with_metadata
124
126
  expect(event.get("[@metadata][_source][message]")).to eql [ "ohayo" ]
125
127
  end
126
128
  end
129
+
127
130
  end
128
131
 
129
132
  # This spec is an adapter-spec, ensuring that we send the right sequence of messages to our Elasticsearch Client
@@ -135,6 +138,7 @@ describe LogStash::Inputs::TestableElasticsearch do
135
138
  'query' => "#{LogStash::Json.dump(query)}",
136
139
  'slices' => slices,
137
140
  'docinfo' => true, # include ids
141
+ 'docinfo_target' => '[@metadata]'
138
142
  }
139
143
  end
140
144
  let(:query) do
@@ -405,127 +409,140 @@ describe LogStash::Inputs::TestableElasticsearch do
405
409
  allow(client).to receive(:clear_scroll).and_return(nil)
406
410
  end
407
411
 
408
- context 'when defining docinfo' do
409
- let(:config_metadata) do
410
- %q[
411
- input {
412
- elasticsearch {
413
- hosts => ["localhost"]
414
- query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
415
- docinfo => true
416
- }
417
- }
418
- ]
419
- end
412
+ ecs_compatibility_matrix(:disabled, :v1, :v8) do |ecs_select|
420
413
 
421
- it 'merges the values if the `docinfo_target` already exist in the `_source` document' do
422
- config_metadata_with_hash = %Q[
423
- input {
424
- elasticsearch {
425
- hosts => ["localhost"]
426
- query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
427
- docinfo => true
428
- docinfo_target => 'metadata_with_hash'
414
+ before(:each) do
415
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
416
+ end
417
+
418
+ context 'with docinfo enabled' do
419
+ let(:config_metadata) do
420
+ %q[
421
+ input {
422
+ elasticsearch {
423
+ hosts => ["localhost"]
424
+ query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
425
+ docinfo => true
426
+ }
429
427
  }
430
- }
431
- ]
432
-
433
- event = input(config_metadata_with_hash) do |pipeline, queue|
434
- queue.pop
428
+ ]
435
429
  end
436
430
 
437
- expect(event.get("[metadata_with_hash][_index]")).to eq('logstash-2014.10.12')
438
- expect(event.get("[metadata_with_hash][_type]")).to eq('logs')
439
- expect(event.get("[metadata_with_hash][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
440
- expect(event.get("[metadata_with_hash][awesome]")).to eq("logstash")
441
- end
442
-
443
- context 'if the `docinfo_target` exist but is not of type hash' do
444
- let (:config) { {
445
- "hosts" => ["localhost"],
446
- "query" => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }',
447
- "docinfo" => true,
448
- "docinfo_target" => 'metadata_with_string'
449
- } }
450
- it 'thows an exception if the `docinfo_target` exist but is not of type hash' do
451
- expect(client).not_to receive(:clear_scroll)
452
- plugin.register
453
- expect { plugin.run([]) }.to raise_error(Exception, /incompatible event/)
431
+ it "provides document info under metadata" do
432
+ event = input(config_metadata) do |pipeline, queue|
433
+ queue.pop
434
+ end
435
+
436
+ if ecs_select.active_mode == :disabled
437
+ expect(event.get("[@metadata][_index]")).to eq('logstash-2014.10.12')
438
+ expect(event.get("[@metadata][_type]")).to eq('logs')
439
+ expect(event.get("[@metadata][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
440
+ else
441
+ expect(event.get("[@metadata][input][elasticsearch][_index]")).to eq('logstash-2014.10.12')
442
+ expect(event.get("[@metadata][input][elasticsearch][_type]")).to eq('logs')
443
+ expect(event.get("[@metadata][input][elasticsearch][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
444
+ end
454
445
  end
455
- end
456
446
 
457
- it "should move the document info to the @metadata field" do
458
- event = input(config_metadata) do |pipeline, queue|
459
- queue.pop
447
+ it 'merges values if the `docinfo_target` already exist in the `_source` document' do
448
+ config_metadata_with_hash = %Q[
449
+ input {
450
+ elasticsearch {
451
+ hosts => ["localhost"]
452
+ query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
453
+ docinfo => true
454
+ docinfo_target => 'metadata_with_hash'
455
+ }
456
+ }
457
+ ]
458
+
459
+ event = input(config_metadata_with_hash) do |pipeline, queue|
460
+ queue.pop
461
+ end
462
+
463
+ expect(event.get("[metadata_with_hash][_index]")).to eq('logstash-2014.10.12')
464
+ expect(event.get("[metadata_with_hash][_type]")).to eq('logs')
465
+ expect(event.get("[metadata_with_hash][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
466
+ expect(event.get("[metadata_with_hash][awesome]")).to eq("logstash")
460
467
  end
461
468
 
462
- expect(event.get("[@metadata][_index]")).to eq('logstash-2014.10.12')
463
- expect(event.get("[@metadata][_type]")).to eq('logs')
464
- expect(event.get("[@metadata][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
465
- end
469
+ context 'if the `docinfo_target` exist but is not of type hash' do
470
+ let (:config) { {
471
+ "hosts" => ["localhost"],
472
+ "query" => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }',
473
+ "docinfo" => true,
474
+ "docinfo_target" => 'metadata_with_string'
475
+ } }
476
+ it 'thows an exception if the `docinfo_target` exist but is not of type hash' do
477
+ expect(client).not_to receive(:clear_scroll)
478
+ plugin.register
479
+ expect { plugin.run([]) }.to raise_error(Exception, /incompatible event/)
480
+ end
481
+ end
466
482
 
467
- it 'should move the document information to the specified field' do
468
- config = %q[
469
- input {
470
- elasticsearch {
471
- hosts => ["localhost"]
472
- query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
473
- docinfo => true
474
- docinfo_target => 'meta'
483
+ it 'should move the document information to the specified field' do
484
+ config = %q[
485
+ input {
486
+ elasticsearch {
487
+ hosts => ["localhost"]
488
+ query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
489
+ docinfo => true
490
+ docinfo_target => 'meta'
491
+ }
475
492
  }
476
- }
477
- ]
478
- event = input(config) do |pipeline, queue|
479
- queue.pop
493
+ ]
494
+ event = input(config) do |pipeline, queue|
495
+ queue.pop
496
+ end
497
+
498
+ expect(event.get("[meta][_index]")).to eq('logstash-2014.10.12')
499
+ expect(event.get("[meta][_type]")).to eq('logs')
500
+ expect(event.get("[meta][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
480
501
  end
481
502
 
482
- expect(event.get("[meta][_index]")).to eq('logstash-2014.10.12')
483
- expect(event.get("[meta][_type]")).to eq('logs')
484
- expect(event.get("[meta][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
485
- end
503
+ it "allows to specify which fields from the document info to save to metadata" do
504
+ fields = ["_index"]
505
+ config = %Q[
506
+ input {
507
+ elasticsearch {
508
+ hosts => ["localhost"]
509
+ query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
510
+ docinfo => true
511
+ docinfo_fields => #{fields}
512
+ }
513
+ }]
514
+
515
+ event = input(config) do |pipeline, queue|
516
+ queue.pop
517
+ end
518
+
519
+ meta_base = event.get(ecs_select.active_mode == :disabled ? "@metadata" : "[@metadata][input][elasticsearch]")
520
+ expect(meta_base.keys).to eq(fields)
521
+ end
486
522
 
487
- it "should allow to specify which fields from the document info to save to the @metadata field" do
488
- fields = ["_index"]
489
- config = %Q[
523
+ it 'should be able to reference metadata fields in `add_field` decorations' do
524
+ config = %q[
490
525
  input {
491
526
  elasticsearch {
492
527
  hosts => ["localhost"]
493
528
  query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
494
529
  docinfo => true
495
- docinfo_fields => #{fields}
496
- }
497
- }]
498
-
499
- event = input(config) do |pipeline, queue|
500
- queue.pop
501
- end
502
-
503
- expect(event.get("@metadata").keys).to eq(fields)
504
- expect(event.get("[@metadata][_type]")).to eq(nil)
505
- expect(event.get("[@metadata][_index]")).to eq('logstash-2014.10.12')
506
- expect(event.get("[@metadata][_id]")).to eq(nil)
507
- end
508
-
509
- it 'should be able to reference metadata fields in `add_field` decorations' do
510
- config = %q[
511
- input {
512
- elasticsearch {
513
- hosts => ["localhost"]
514
- query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
515
- docinfo => true
516
- add_field => {
517
- 'identifier' => "foo:%{[@metadata][_type]}:%{[@metadata][_id]}"
530
+ add_field => {
531
+ 'identifier' => "foo:%{[@metadata][_type]}:%{[@metadata][_id]}"
532
+ }
518
533
  }
519
534
  }
520
- }
521
- ]
535
+ ]
522
536
 
523
- event = input(config) do |pipeline, queue|
524
- queue.pop
525
- end
537
+ event = input(config) do |pipeline, queue|
538
+ queue.pop
539
+ end
540
+
541
+ expect(event.get('identifier')).to eq('foo:logs:C5b2xLQwTZa76jBmHIbwHQ')
542
+ end if ecs_select.active_mode == :disabled
526
543
 
527
- expect(event.get('identifier')).to eq('foo:logs:C5b2xLQwTZa76jBmHIbwHQ')
528
544
  end
545
+
529
546
  end
530
547
 
531
548
  context "when not defining the docinfo" do
@@ -542,9 +559,7 @@ describe LogStash::Inputs::TestableElasticsearch do
542
559
  queue.pop
543
560
  end
544
561
 
545
- expect(event.get("[@metadata][_index]")).to eq(nil)
546
- expect(event.get("[@metadata][_type]")).to eq(nil)
547
- expect(event.get("[@metadata][_id]")).to eq(nil)
562
+ expect(event.get("[@metadata]")).to be_empty
548
563
  end
549
564
  end
550
565
  end
@@ -568,13 +583,13 @@ describe LogStash::Inputs::TestableElasticsearch do
568
583
  it "should set host(s)" do
569
584
  plugin.register
570
585
  client = plugin.send(:client)
571
- expect( client.transport.instance_variable_get(:@hosts) ).to eql [{
572
- :scheme => "https",
573
- :host => "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io",
574
- :port => 9243,
575
- :path => "",
576
- :protocol => "https"
577
- }]
586
+ expect( extract_transport(client).hosts ).to eql [{
587
+ :scheme => "https",
588
+ :host => "ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io",
589
+ :port => 9243,
590
+ :path => "",
591
+ :protocol => "https"
592
+ }]
578
593
  end
579
594
 
580
595
  context 'invalid' do
@@ -600,7 +615,7 @@ describe LogStash::Inputs::TestableElasticsearch do
600
615
  it "should set authorization" do
601
616
  plugin.register
602
617
  client = plugin.send(:client)
603
- auth_header = client.transport.instance_variable_get(:@options)[:transport_options][:headers]['Authorization']
618
+ auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
604
619
 
605
620
  expect( auth_header ).to eql "Basic #{Base64.encode64('elastic:my-passwd-00').rstrip}"
606
621
  end
@@ -637,7 +652,7 @@ describe LogStash::Inputs::TestableElasticsearch do
637
652
  it "should set authorization" do
638
653
  plugin.register
639
654
  client = plugin.send(:client)
640
- auth_header = client.transport.instance_variable_get(:@options)[:transport_options][:headers]['Authorization']
655
+ auth_header = extract_transport(client).options[:transport_options][:headers]['Authorization']
641
656
 
642
657
  expect( auth_header ).to eql "ApiKey #{Base64.strict_encode64('foo:bar')}"
643
658
  end
@@ -658,7 +673,7 @@ describe LogStash::Inputs::TestableElasticsearch do
658
673
  it "should set proxy" do
659
674
  plugin.register
660
675
  client = plugin.send(:client)
661
- proxy = client.transport.instance_variable_get(:@options)[:transport_options][:proxy]
676
+ proxy = extract_transport(client).options[:transport_options][:proxy]
662
677
 
663
678
  expect( proxy ).to eql "http://localhost:1234"
664
679
  end
@@ -670,7 +685,7 @@ describe LogStash::Inputs::TestableElasticsearch do
670
685
  plugin.register
671
686
  client = plugin.send(:client)
672
687
 
673
- expect( client.transport.instance_variable_get(:@options)[:transport_options] ).to_not include(:proxy)
688
+ expect( extract_transport(client).options[:transport_options] ).to_not include(:proxy)
674
689
  end
675
690
  end
676
691
  end
@@ -756,4 +771,10 @@ describe LogStash::Inputs::TestableElasticsearch do
756
771
  end
757
772
 
758
773
  end
774
+
775
+ # @note can be removed once we depends on elasticsearch gem >= 6.x
776
+ def extract_transport(client) # on 7.x client.transport is a ES::Transport::Client
777
+ client.transport.respond_to?(:transport) ? client.transport.transport : client.transport
778
+ end
779
+
759
780
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.3
4
+ version: 4.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-20 00:00:00.000000000 Z
11
+ date: 2021-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '1.0'
19
- name: logstash-mixin-validator_support
20
- prerelease: false
21
- type: :runtime
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  requirement: !ruby/object:Gem::Requirement
29
15
  requirements:
@@ -34,8 +20,8 @@ dependencies:
34
20
  - !ruby/object:Gem::Version
35
21
  version: '2.99'
36
22
  name: logstash-core-plugin-api
37
- prerelease: false
38
23
  type: :runtime
24
+ prerelease: false
39
25
  version_requirements: !ruby/object:Gem::Requirement
40
26
  requirements:
41
27
  - - ">="
@@ -47,45 +33,59 @@ dependencies:
47
33
  - !ruby/object:Gem::Dependency
48
34
  requirement: !ruby/object:Gem::Requirement
49
35
  requirements:
50
- - - ">="
36
+ - - "~>"
51
37
  - !ruby/object:Gem::Version
52
- version: 5.0.5
53
- name: elasticsearch
54
- prerelease: false
38
+ version: '1.3'
39
+ name: logstash-mixin-ecs_compatibility_support
55
40
  type: :runtime
41
+ prerelease: false
56
42
  version_requirements: !ruby/object:Gem::Requirement
57
43
  requirements:
58
- - - ">="
44
+ - - "~>"
59
45
  - !ruby/object:Gem::Version
60
- version: 5.0.5
46
+ version: '1.3'
61
47
  - !ruby/object:Gem::Dependency
62
48
  requirement: !ruby/object:Gem::Requirement
63
49
  requirements:
64
- - - ">="
50
+ - - "~>"
65
51
  - !ruby/object:Gem::Version
66
- version: '0'
67
- name: logstash-codec-json
52
+ version: '1.0'
53
+ name: logstash-mixin-event_support
54
+ type: :runtime
68
55
  prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.0'
61
+ - !ruby/object:Gem::Dependency
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.0'
67
+ name: logstash-mixin-validator_support
69
68
  type: :runtime
69
+ prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - ">="
72
+ - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0'
74
+ version: '1.0'
75
75
  - !ruby/object:Gem::Dependency
76
76
  requirement: !ruby/object:Gem::Requirement
77
77
  requirements:
78
78
  - - ">="
79
79
  - !ruby/object:Gem::Version
80
- version: '0'
81
- name: sequel
82
- prerelease: false
80
+ version: 5.0.5
81
+ name: elasticsearch
83
82
  type: :runtime
83
+ prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - ">="
87
87
  - !ruby/object:Gem::Version
88
- version: '0'
88
+ version: 5.0.5
89
89
  - !ruby/object:Gem::Dependency
90
90
  requirement: !ruby/object:Gem::Requirement
91
91
  requirements:
@@ -93,8 +93,8 @@ dependencies:
93
93
  - !ruby/object:Gem::Version
94
94
  version: '0'
95
95
  name: tzinfo
96
- prerelease: false
97
96
  type: :runtime
97
+ prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - ">="
@@ -107,8 +107,8 @@ dependencies:
107
107
  - !ruby/object:Gem::Version
108
108
  version: '0'
109
109
  name: tzinfo-data
110
- prerelease: false
111
110
  type: :runtime
111
+ prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - ">="
@@ -121,8 +121,8 @@ dependencies:
121
121
  - !ruby/object:Gem::Version
122
122
  version: '0'
123
123
  name: rufus-scheduler
124
- prerelease: false
125
124
  type: :runtime
125
+ prerelease: false
126
126
  version_requirements: !ruby/object:Gem::Requirement
127
127
  requirements:
128
128
  - - ">="
@@ -135,13 +135,27 @@ dependencies:
135
135
  - !ruby/object:Gem::Version
136
136
  version: 0.7.1
137
137
  name: manticore
138
- prerelease: false
139
138
  type: :runtime
139
+ prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - ">="
143
143
  - !ruby/object:Gem::Version
144
144
  version: 0.7.1
145
+ - !ruby/object:Gem::Dependency
146
+ requirement: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ name: logstash-codec-plain
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
145
159
  - !ruby/object:Gem::Dependency
146
160
  requirement: !ruby/object:Gem::Requirement
147
161
  requirements:
@@ -149,8 +163,8 @@ dependencies:
149
163
  - !ruby/object:Gem::Version
150
164
  version: 0.15.4
151
165
  name: faraday
152
- prerelease: false
153
166
  type: :development
167
+ prerelease: false
154
168
  version_requirements: !ruby/object:Gem::Requirement
155
169
  requirements:
156
170
  - - "~>"
@@ -163,8 +177,8 @@ dependencies:
163
177
  - !ruby/object:Gem::Version
164
178
  version: '0'
165
179
  name: logstash-devutils
166
- prerelease: false
167
180
  type: :development
181
+ prerelease: false
168
182
  version_requirements: !ruby/object:Gem::Requirement
169
183
  requirements:
170
184
  - - ">="
@@ -177,8 +191,8 @@ dependencies:
177
191
  - !ruby/object:Gem::Version
178
192
  version: '0'
179
193
  name: timecop
180
- prerelease: false
181
194
  type: :development
195
+ prerelease: false
182
196
  version_requirements: !ruby/object:Gem::Requirement
183
197
  requirements:
184
198
  - - ">="
@@ -206,6 +220,8 @@ files:
206
220
  - spec/es_helper.rb
207
221
  - spec/fixtures/test_certs/ca.crt
208
222
  - spec/fixtures/test_certs/ca.key
223
+ - spec/fixtures/test_certs/client/ls.crt
224
+ - spec/fixtures/test_certs/client/ls.key
209
225
  - spec/fixtures/test_certs/es.crt
210
226
  - spec/fixtures/test_certs/es.key
211
227
  - spec/inputs/elasticsearch_spec.rb
@@ -231,7 +247,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
247
  - !ruby/object:Gem::Version
232
248
  version: '0'
233
249
  requirements: []
234
- rubygems_version: 3.1.6
250
+ rubygems_version: 3.0.6
235
251
  signing_key:
236
252
  specification_version: 4
237
253
  summary: Reads query results from an Elasticsearch cluster
@@ -239,6 +255,8 @@ test_files:
239
255
  - spec/es_helper.rb
240
256
  - spec/fixtures/test_certs/ca.crt
241
257
  - spec/fixtures/test_certs/ca.key
258
+ - spec/fixtures/test_certs/client/ls.crt
259
+ - spec/fixtures/test_certs/client/ls.key
242
260
  - spec/fixtures/test_certs/es.crt
243
261
  - spec/fixtures/test_certs/es.key
244
262
  - spec/inputs/elasticsearch_spec.rb