logstash-input-elasticsearch 4.9.3 → 4.10.0

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: 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