logstash-input-elasticsearch 4.2.0 → 4.3.3

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: c800b8e0032e2d43897b1c4e0dab3cf4d6d22c14919fcdefe7b7df8ec4a64ffa
4
- data.tar.gz: 063e672f41db0c0711c7d2229fd05b5dbef0d28fed9f34afe5c2c2ad57ff1dc2
3
+ metadata.gz: 72f28226e8297df8d4eda501ef9a99a67c11bab0574711f553797c678cd5e9a8
4
+ data.tar.gz: d141edd1c0664b1f77f4ddc757cda564781aeaa2ada1ebee828ac2f76268c1de
5
5
  SHA512:
6
- metadata.gz: 63503ac4073666f88eca84c6af52d2598ba425b4ca7b16ec6c77bcb97def7083119943ea7f940536bd49a8cad581d2afb502634a00e336a223f2abff9842038d
7
- data.tar.gz: 5d2ec1e87c76a79f590d3f93dc8e2667597b74aba4f1503282f75de34ce98e6c6cac4d49ddcc86668669eb7706dc97a312fb93f7bad3b88fa2ff98608cd9bc94
6
+ metadata.gz: 468f91f896d037895c7479e7ae377cee60c4b0c22b05918695f35b6e56bdfa405524fd04d03440133ac40a71fa4ed00251ad27e38792f7c30a8b736ffaa186c9
7
+ data.tar.gz: 5ba240ae691f622ab6bf410b7603ebbb959ee5c50cddc90748dd26a1a349fcc36057e9147a15d0501ea1e4f0bbc2861f3042c0addc070568ec805cdd6668d999
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 4.3.3
2
+ - Loosen restrictions on Elasticsearch gem [#110](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/110)
3
+
4
+ ## 4.3.2
5
+ - Fixed broken link to Elasticsearch Reference [#106](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/106)
6
+
7
+ ## 4.3.1
8
+ - Fixed deeplink to Elasticsearch Reference [#103](https://github.com/logstash-plugins/logstash-input-elasticsearch/pull/103)
9
+
10
+ ## 4.3.0
11
+ - Added managed slice scrolling with `slices` option
12
+
13
+ ## 4.2.1
14
+ - Docs: Set the default_codec doc attribute.
15
+
1
16
  ## 4.2.0
2
17
  - Docs: Deprecate `document_type`
3
18
  - Add support for scheduling periodic execution of the query #81
data/docs/index.asciidoc CHANGED
@@ -1,5 +1,6 @@
1
1
  :plugin: elasticsearch
2
2
  :type: input
3
+ :default_codec: json
3
4
 
4
5
  ///////////////////////////////////////////
5
6
  START - GENERATED VARIABLES, DO NOT EDIT!
@@ -96,6 +97,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
96
97
  | <<plugins-{type}s-{plugin}-schedule>> |<<string,string>>|No
97
98
  | <<plugins-{type}s-{plugin}-scroll>> |<<string,string>>|No
98
99
  | <<plugins-{type}s-{plugin}-size>> |<<number,number>>|No
100
+ | <<plugins-{type}s-{plugin}-slices>> |<<number,number>>|No
99
101
  | <<plugins-{type}s-{plugin}-ssl>> |<<boolean,boolean>>|No
100
102
  | <<plugins-{type}s-{plugin}-user>> |<<string,string>>|No
101
103
  |=======================================================================
@@ -161,11 +163,10 @@ It will be removed in the next major version of Logstash.
161
163
  * Value type is <<array,array>>
162
164
  * Default value is `["_index", "_type", "_id"]`
163
165
 
164
- If document metadata storage is requested by enabling the `docinfo`
165
- option, this option lists the metadata fields to save in the current
166
- event. See
167
- http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/_document_metadata.html[Document Metadata]
168
- in the Elasticsearch documentation for more information.
166
+ If document metadata storage is requested by enabling the `docinfo` option, this
167
+ option lists the metadata fields to save in the current event. See
168
+ {ref}/mapping-fields.html[Meta-Fields] in the Elasticsearch documentation for
169
+ more information.
169
170
 
170
171
  [id="plugins-{type}s-{plugin}-docinfo_target"]
171
172
  ===== `docinfo_target`
@@ -193,7 +194,11 @@ can be either IP, HOST, IP:port, or HOST:port. The port defaults to
193
194
  * Value type is <<string,string>>
194
195
  * Default value is `"logstash-*"`
195
196
 
196
- The index or alias to search.
197
+ The index or alias to search. See
198
+ https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-index.html[Multi Indices documentation]
199
+ in the Elasticsearch documentation for more information on how to reference
200
+ multiple indices.
201
+
197
202
 
198
203
  [id="plugins-{type}s-{plugin}-password"]
199
204
  ===== `password`
@@ -245,6 +250,30 @@ round trip (i.e. between the previous scroll request, to the next).
245
250
 
246
251
  This allows you to set the maximum number of hits returned per scroll.
247
252
 
253
+ [id="plugins-{type}s-{plugin}-slices"]
254
+ ===== `slices`
255
+
256
+ * Value type is <<number,number>>
257
+ * There is no default value.
258
+ * Sensible values range from 2 to about 8.
259
+
260
+ In some cases, it is possible to improve overall throughput by consuming multiple
261
+ distinct slices of a query simultaneously using the
262
+ https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html#sliced-scroll[Sliced Scroll API],
263
+ especially if the pipeline is spending significant time waiting on Elasticsearch
264
+ to provide results.
265
+
266
+ If set, the `slices` parameter tells the plugin how many slices to divide the work
267
+ into, and will produce events from the slices in parallel until all of them are done
268
+ scrolling.
269
+
270
+ NOTE: The Elasticsearch manual indicates that there can be _negative_ performance
271
+ implications to both the query and the Elasticsearch cluster when a scrolling
272
+ query uses more slices than shards in the index.
273
+
274
+ If the `slices` parameter is left unset, the plugin will _not_ inject slice
275
+ instructions into the query.
276
+
248
277
  [id="plugins-{type}s-{plugin}-ssl"]
249
278
  ===== `ssl`
250
279
 
@@ -268,3 +297,5 @@ empty string authentication will be disabled.
268
297
 
269
298
  [id="plugins-{type}s-{plugin}-common-options"]
270
299
  include::{include_path}/{type}.asciidoc[]
300
+
301
+ :default_codec!:
@@ -1,6 +1,7 @@
1
1
  # encoding: utf-8
2
2
  require "logstash/inputs/base"
3
3
  require "logstash/namespace"
4
+ require "logstash/json"
4
5
  require "base64"
5
6
 
6
7
  # .Compatibility Note
@@ -83,6 +84,10 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
83
84
  # round trip (i.e. between the previous scroll request, to the next).
84
85
  config :scroll, :validate => :string, :default => "1m"
85
86
 
87
+ # This parameter controls the number of parallel slices to be consumed simultaneously
88
+ # by this pipeline input.
89
+ config :slices, :validate => :number
90
+
86
91
  # If set, include Elasticsearch document information such as index, type, and
87
92
  # the id in the event.
88
93
  #
@@ -147,10 +152,14 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
147
152
 
148
153
  @options = {
149
154
  :index => @index,
150
- :body => @query,
151
155
  :scroll => @scroll,
152
156
  :size => @size
153
157
  }
158
+ @base_query = LogStash::Json.load(@query)
159
+ if @slices
160
+ @base_query.include?('slice') && fail(LogStash::ConfigurationError, "Elasticsearch Input Plugin's `query` option cannot specify specific `slice` when configured to manage parallel slices with `slices` option")
161
+ @slices < 1 && fail(LogStash::ConfigurationError, "Elasticsearch Input Plugin's `slices` option must be greater than zero, got `#{@slices}`")
162
+ end
154
163
 
155
164
  transport_options = {}
156
165
 
@@ -196,16 +205,39 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
196
205
  private
197
206
 
198
207
  def do_run(output_queue)
199
- # get first wave of data
200
- r = @client.search(@options)
208
+ # if configured to run a single slice, don't bother spinning up threads
209
+ return do_run_slice(output_queue) if @slices.nil? || @slices <= 1
210
+
211
+ logger.warn("managed slices for query is very large (#{@slices}); consider reducing") if @slices > 8
212
+
213
+ @slices.times.map do |slice_id|
214
+ Thread.new do
215
+ LogStash::Util::set_thread_name("#{@id}_slice_#{slice_id}")
216
+ do_run_slice(output_queue, slice_id)
217
+ end
218
+ end.map(&:join)
219
+ end
220
+
221
+ def do_run_slice(output_queue, slice_id=nil)
222
+ slice_query = @base_query
223
+ slice_query = slice_query.merge('slice' => { 'id' => slice_id, 'max' => @slices}) unless slice_id.nil?
224
+
225
+ slice_options = @options.merge(:body => LogStash::Json.dump(slice_query) )
226
+
227
+ logger.info("Slice starting", slice_id: slice_id, slices: @slices) unless slice_id.nil?
228
+ r = search_request(slice_options)
201
229
 
202
230
  r['hits']['hits'].each { |hit| push_hit(hit, output_queue) }
231
+ logger.debug("Slice progress", slice_id: slice_id, slices: @slices) unless slice_id.nil?
232
+
203
233
  has_hits = r['hits']['hits'].any?
204
234
 
205
- while has_hits && !stop?
235
+ while has_hits && r['_scroll_id'] && !stop?
206
236
  r = process_next_scroll(output_queue, r['_scroll_id'])
237
+ logger.debug("Slice progress", slice_id: slice_id, slices: @slices) unless slice_id.nil?
207
238
  has_hits = r['has_hits']
208
239
  end
240
+ logger.info("Slice complete", slice_id: slice_id, slices: @slices) unless slice_id.nil?
209
241
  end
210
242
 
211
243
  def process_next_scroll(output_queue, scroll_id)
@@ -243,4 +275,8 @@ class LogStash::Inputs::Elasticsearch < LogStash::Inputs::Base
243
275
  def scroll_request scroll_id
244
276
  @client.scroll(:body => { :scroll_id => scroll_id }, :scroll => @scroll)
245
277
  end
278
+
279
+ def search_request(options)
280
+ @client.search(options)
281
+ end
246
282
  end
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-input-elasticsearch'
4
- s.version = '4.2.0'
4
+ s.version = '4.3.3'
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"
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
22
22
  # Gem dependencies
23
23
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
24
 
25
- s.add_runtime_dependency 'elasticsearch', ['>= 5.0.3', '< 6.0.0']
25
+ s.add_runtime_dependency 'elasticsearch', '>= 5.0.3'
26
26
 
27
27
  s.add_runtime_dependency 'logstash-codec-json'
28
28
  s.add_runtime_dependency 'logstash-codec-plain'
data/spec/es_helper.rb ADDED
@@ -0,0 +1,40 @@
1
+ module ESHelper
2
+ def self.get_host_port
3
+ return "http://elasticsearch:9200" if ENV["INTEGRATION"] == "true"
4
+ raise "This setting is only used for integration tests"
5
+ end
6
+
7
+ def self.get_client
8
+ Elasticsearch::Client.new(:hosts => [get_host_port])
9
+ end
10
+
11
+ def self.doc_type
12
+ if ESHelper.es_version_satisfies?(">=8")
13
+ nil
14
+ elsif ESHelper.es_version_satisfies?(">=7")
15
+ "_doc"
16
+ else
17
+ "doc"
18
+ end
19
+ end
20
+
21
+ def self.index_doc(es, params)
22
+ type = doc_type
23
+ params[:type] = doc_type unless type.nil?
24
+ es.index(params)
25
+ end
26
+
27
+ def self.es_version
28
+ ENV['ES_VERSION'] || ENV['ELASTIC_STACK_VERSION']
29
+ end
30
+
31
+ def self.es_version_satisfies?(*requirement)
32
+ es_version = RSpec.configuration.filter[:es_version] || ENV['ES_VERSION'] || ENV['ELASTIC_STACK_VERSION']
33
+ if es_version.nil?
34
+ puts "Info: ES_VERSION, ELASTIC_STACK_VERSION or 'es_version' tag wasn't set. Returning false to all `es_version_satisfies?` call."
35
+ return false
36
+ end
37
+ es_release_version = Gem::Version.new(es_version).release
38
+ Gem::Requirement.new(requirement).satisfied_by?(es_release_version)
39
+ end
40
+ end
@@ -84,6 +84,239 @@ describe LogStash::Inputs::Elasticsearch do
84
84
  insist { event.get("message") } == [ "ohayo" ]
85
85
  end
86
86
 
87
+
88
+ # This spec is an adapter-spec, ensuring that we send the right sequence of messages to our Elasticsearch Client
89
+ # to support sliced scrolling. The underlying implementation will spawn its own threads to consume, so we must be
90
+ # careful to use thread-safe constructs.
91
+ context "with managed sliced scrolling" do
92
+ let(:config) do
93
+ {
94
+ 'query' => "#{LogStash::Json.dump(query)}",
95
+ 'slices' => slices,
96
+ 'docinfo' => true, # include ids
97
+ }
98
+ end
99
+ let(:query) do
100
+ {
101
+ "query" => {
102
+ "match" => { "city_name" => "Okinawa" }
103
+ },
104
+ "fields" => ["message"]
105
+ }
106
+ end
107
+ let(:slices) { 2 }
108
+
109
+ context 'with `slices => 0`' do
110
+ let(:slices) { 0 }
111
+ it 'fails to register' do
112
+ expect { plugin.register }.to raise_error(LogStash::ConfigurationError)
113
+ end
114
+ end
115
+
116
+ context 'with `slices => 1`' do
117
+ let(:slices) { 1 }
118
+ it 'runs just one slice' do
119
+ expect(plugin).to receive(:do_run_slice).with(duck_type(:<<))
120
+ expect(Thread).to_not receive(:new)
121
+
122
+ plugin.register
123
+ plugin.run([])
124
+ end
125
+ end
126
+
127
+ context 'without slices directive' do
128
+ let(:config) { super.tap { |h| h.delete('slices') } }
129
+ it 'runs just one slice' do
130
+ expect(plugin).to receive(:do_run_slice).with(duck_type(:<<))
131
+ expect(Thread).to_not receive(:new)
132
+
133
+ plugin.register
134
+ plugin.run([])
135
+ end
136
+ end
137
+
138
+ 2.upto(8) do |slice_count|
139
+ context "with `slices => #{slice_count}`" do
140
+ let(:slices) { slice_count }
141
+ it "runs #{slice_count} independent slices" do
142
+ expect(Thread).to receive(:new).and_call_original.exactly(slice_count).times
143
+ slice_count.times do |slice_id|
144
+ expect(plugin).to receive(:do_run_slice).with(duck_type(:<<), slice_id)
145
+ end
146
+
147
+ plugin.register
148
+ plugin.run([])
149
+ end
150
+ end
151
+ end
152
+
153
+ # This section of specs heavily mocks the Elasticsearch::Client, and ensures that the Elasticsearch Input Plugin
154
+ # behaves as expected when handling a series of sliced, scrolled requests/responses.
155
+ context 'adapter/integration' do
156
+ let(:response_template) do
157
+ {
158
+ "took" => 12,
159
+ "timed_out" => false,
160
+ "shards" => {
161
+ "total" => 6,
162
+ "successful" => 6,
163
+ "failed" => 0
164
+ }
165
+ }
166
+ end
167
+
168
+ let(:hits_template) do
169
+ {
170
+ "total" => 4,
171
+ "max_score" => 1.0,
172
+ "hits" => []
173
+ }
174
+ end
175
+
176
+ let(:hit_template) do
177
+ {
178
+ "_index" => "logstash-2018.08.23",
179
+ "_type" => "logs",
180
+ "_score" => 1.0,
181
+ "_source" => { "message" => ["hello, world"] }
182
+ }
183
+ end
184
+
185
+ # BEGIN SLICE 0: a sequence of THREE scrolled responses containing 2, 1, and 0 items
186
+ # end-of-slice is reached when slice0_response2 is empty.
187
+ begin
188
+ let(:slice0_response0) do
189
+ response_template.merge({
190
+ "_scroll_id" => slice0_scroll1,
191
+ "hits" => hits_template.merge("hits" => [
192
+ hit_template.merge('_id' => "slice0-response0-item0"),
193
+ hit_template.merge('_id' => "slice0-response0-item1")
194
+ ])
195
+ })
196
+ end
197
+ let(:slice0_scroll1) { 'slice:0,scroll:1' }
198
+ let(:slice0_response1) do
199
+ response_template.merge({
200
+ "_scroll_id" => slice0_scroll2,
201
+ "hits" => hits_template.merge("hits" => [
202
+ hit_template.merge('_id' => "slice0-response1-item0")
203
+ ])
204
+ })
205
+ end
206
+ let(:slice0_scroll2) { 'slice:0,scroll:2' }
207
+ let(:slice0_response2) do
208
+ response_template.merge(
209
+ "_scroll_id" => slice0_scroll3,
210
+ "hits" => hits_template.merge({"hits" => []})
211
+ )
212
+ end
213
+ let(:slice0_scroll3) { 'slice:0,scroll:3' }
214
+ end
215
+ # END SLICE 0
216
+
217
+ # BEGIN SLICE 1: a sequence of TWO scrolled responses containing 2 and 2 items.
218
+ # end-of-slice is reached when slice1_response1 does not contain a next scroll id
219
+ begin
220
+ let(:slice1_response0) do
221
+ response_template.merge({
222
+ "_scroll_id" => slice1_scroll1,
223
+ "hits" => hits_template.merge("hits" => [
224
+ hit_template.merge('_id' => "slice1-response0-item0"),
225
+ hit_template.merge('_id' => "slice1-response0-item1")
226
+ ])
227
+ })
228
+ end
229
+ let(:slice1_scroll1) { 'slice:1,scroll:1' }
230
+ let(:slice1_response1) do
231
+ response_template.merge({
232
+ "hits" => hits_template.merge("hits" => [
233
+ hit_template.merge('_id' => "slice1-response1-item0"),
234
+ hit_template.merge('_id' => "slice1-response1-item1")
235
+ ])
236
+ })
237
+ end
238
+ end
239
+ # END SLICE 1
240
+
241
+ let(:client) { Elasticsearch::Client.new }
242
+
243
+ # RSpec mocks validations are not threadsafe.
244
+ # Allow caller to synchronize.
245
+ def synchronize_method!(object, method_name)
246
+ original_method = object.method(method_name)
247
+ mutex = Mutex.new
248
+ allow(object).to receive(method_name).with(any_args) do |*method_args, &method_block|
249
+ mutex.synchronize do
250
+ original_method.call(*method_args,&method_block)
251
+ end
252
+ end
253
+ end
254
+
255
+ before(:each) do
256
+ expect(Elasticsearch::Client).to receive(:new).with(any_args).and_return(client)
257
+ plugin.register
258
+
259
+ # SLICE0 is a three-page scroll in which the last page is empty
260
+ slice0_query = LogStash::Json.dump(query.merge('slice' => { 'id' => 0, 'max' => 2}))
261
+ expect(client).to receive(:search).with(hash_including(:body => slice0_query)).and_return(slice0_response0)
262
+ expect(client).to receive(:scroll).with(hash_including(:body => { :scroll_id => slice0_scroll1 })).and_return(slice0_response1)
263
+ expect(client).to receive(:scroll).with(hash_including(:body => { :scroll_id => slice0_scroll2 })).and_return(slice0_response2)
264
+
265
+ # SLICE1 is a two-page scroll in which the last page has no next scroll id
266
+ slice1_query = LogStash::Json.dump(query.merge('slice' => { 'id' => 1, 'max' => 2}))
267
+ expect(client).to receive(:search).with(hash_including(:body => slice1_query)).and_return(slice1_response0)
268
+ expect(client).to receive(:scroll).with(hash_including(:body => { :scroll_id => slice1_scroll1 })).and_return(slice1_response1)
269
+
270
+ synchronize_method!(plugin, :scroll_request)
271
+ synchronize_method!(plugin, :search_request)
272
+ end
273
+
274
+ let(:emitted_events) do
275
+ queue = Queue.new # since we are running slices in threads, we need a thread-safe queue.
276
+ plugin.run(queue)
277
+ events = []
278
+ events << queue.pop until queue.empty?
279
+ events
280
+ end
281
+
282
+ let(:emitted_event_ids) do
283
+ emitted_events.map { |event| event.get('[@metadata][_id]') }
284
+ end
285
+
286
+ it 'emits the hits on the first page of the first slice' do
287
+ expect(emitted_event_ids).to include('slice0-response0-item0')
288
+ expect(emitted_event_ids).to include('slice0-response0-item1')
289
+ end
290
+ it 'emits the hits on the second page of the first slice' do
291
+ expect(emitted_event_ids).to include('slice0-response1-item0')
292
+ end
293
+
294
+ it 'emits the hits on the first page of the second slice' do
295
+ expect(emitted_event_ids).to include('slice1-response0-item0')
296
+ expect(emitted_event_ids).to include('slice1-response0-item1')
297
+ end
298
+
299
+ it 'emits the hitson the second page of the second slice' do
300
+ expect(emitted_event_ids).to include('slice1-response1-item0')
301
+ expect(emitted_event_ids).to include('slice1-response1-item1')
302
+ end
303
+
304
+ it 'does not double-emit' do
305
+ expect(emitted_event_ids.uniq).to eq(emitted_event_ids)
306
+ end
307
+
308
+ it 'emits events with appropriate fields' do
309
+ emitted_events.each do |event|
310
+ expect(event).to be_a(LogStash::Event)
311
+ expect(event.get('message')).to eq(['hello, world'])
312
+ expect(event.get('[@metadata][_id]')).to_not be_nil
313
+ expect(event.get('[@metadata][_id]')).to_not be_empty
314
+ expect(event.get('[@metadata][_index]')).to start_with('logstash-')
315
+ end
316
+ end
317
+ end
318
+ end
319
+
87
320
  context "with Elasticsearch document information" do
88
321
  let!(:response) do
89
322
  {
@@ -142,15 +375,13 @@ describe LogStash::Inputs::Elasticsearch do
142
375
  end
143
376
 
144
377
  it 'merges the values if the `docinfo_target` already exist in the `_source` document' do
145
- metadata_field = 'metadata_with_hash'
146
-
147
378
  config_metadata_with_hash = %Q[
148
379
  input {
149
380
  elasticsearch {
150
381
  hosts => ["localhost"]
151
382
  query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
152
383
  docinfo => true
153
- docinfo_target => '#{metadata_field}'
384
+ docinfo_target => 'metadata_with_hash'
154
385
  }
155
386
  }
156
387
  ]
@@ -159,33 +390,23 @@ describe LogStash::Inputs::Elasticsearch do
159
390
  queue.pop
160
391
  end
161
392
 
162
- expect(event.get("[#{metadata_field}][_index]")).to eq('logstash-2014.10.12')
163
- expect(event.get("[#{metadata_field}][_type]")).to eq('logs')
164
- expect(event.get("[#{metadata_field}][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
165
- expect(event.get("[#{metadata_field}][awesome]")).to eq("logstash")
393
+ expect(event.get("[metadata_with_hash][_index]")).to eq('logstash-2014.10.12')
394
+ expect(event.get("[metadata_with_hash][_type]")).to eq('logs')
395
+ expect(event.get("[metadata_with_hash][_id]")).to eq('C5b2xLQwTZa76jBmHIbwHQ')
396
+ expect(event.get("[metadata_with_hash][awesome]")).to eq("logstash")
166
397
  end
167
398
 
168
- it 'thows an exception if the `docinfo_target` exist but is not of type hash' do
169
- metadata_field = 'metadata_with_string'
170
-
171
- config_metadata_with_string = %Q[
172
- input {
173
- elasticsearch {
174
- hosts => ["localhost"]
175
- query => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }'
176
- docinfo => true
177
- docinfo_target => '#{metadata_field}'
178
- }
179
- }
180
- ]
181
-
182
- pipeline = new_pipeline_from_string(config_metadata_with_string)
183
- queue = Queue.new
184
- pipeline.instance_eval do
185
- @output_func = lambda { |event| queue << event }
399
+ context 'if the `docinfo_target` exist but is not of type hash' do
400
+ let (:config) { {
401
+ "hosts" => ["localhost"],
402
+ "query" => '{ "query": { "match": { "city_name": "Okinawa" } }, "fields": ["message"] }',
403
+ "docinfo" => true,
404
+ "docinfo_target" => 'metadata_with_string'
405
+ } }
406
+ it 'thows an exception if the `docinfo_target` exist but is not of type hash' do
407
+ plugin.register
408
+ expect { plugin.run([]) }.to raise_error(Exception, /incompatible event/)
186
409
  end
187
-
188
- expect { pipeline.run }.to raise_error(Exception, /incompatible event/)
189
410
  end
190
411
 
191
412
  it "should move the document info to the @metadata field" do
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ require "logstash/devutils/rspec/spec_helper"
3
+ require "logstash/plugin"
4
+ require "logstash/inputs/elasticsearch"
5
+ require_relative "../../../spec/es_helper"
6
+
7
+ describe LogStash::Inputs::Elasticsearch, :integration => true do
8
+
9
+ let(:config) { { 'hosts' => [ESHelper.get_host_port],
10
+ 'index' => 'logs',
11
+ 'query' => '{ "query": { "match": { "message": "Not found"} }}' } }
12
+ let(:plugin) { described_class.new(config) }
13
+ let(:event) { LogStash::Event.new({}) }
14
+
15
+ before(:each) do
16
+ @es = ESHelper.get_client
17
+ # Delete all templates first.
18
+ # Clean ES of data before we start.
19
+ @es.indices.delete_template(:name => "*")
20
+ # This can fail if there are no indexes, ignore failure.
21
+ @es.indices.delete(:index => "*") rescue nil
22
+ 10.times do
23
+ ESHelper.index_doc(@es, :index => 'logs', :body => { :response => 404, :message=> 'Not Found'})
24
+ end
25
+ @es.indices.refresh
26
+ plugin.register
27
+ end
28
+
29
+ after(:each) do
30
+ @es.indices.delete_template(:name => "*")
31
+ @es.indices.delete(:index => "*") rescue nil
32
+ end
33
+
34
+ describe 'smoke test' do
35
+ it "should retrieve json event from elasticseach" do
36
+ queue = []
37
+ plugin.run(queue)
38
+ event = queue.pop
39
+ expect(event).to be_a(LogStash::Event)
40
+ expect(event.get("response")).to eql(404)
41
+ end
42
+ end
43
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.0
4
+ version: 4.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-15 00:00:00.000000000 Z
11
+ date: 2019-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -36,9 +36,6 @@ dependencies:
36
36
  - - ">="
37
37
  - !ruby/object:Gem::Version
38
38
  version: 5.0.3
39
- - - "<"
40
- - !ruby/object:Gem::Version
41
- version: 6.0.0
42
39
  name: elasticsearch
43
40
  prerelease: false
44
41
  type: :runtime
@@ -47,9 +44,6 @@ dependencies:
47
44
  - - ">="
48
45
  - !ruby/object:Gem::Version
49
46
  version: 5.0.3
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: 6.0.0
53
47
  - !ruby/object:Gem::Dependency
54
48
  requirement: !ruby/object:Gem::Requirement
55
49
  requirements:
@@ -179,7 +173,9 @@ files:
179
173
  - docs/index.asciidoc
180
174
  - lib/logstash/inputs/elasticsearch.rb
181
175
  - logstash-input-elasticsearch.gemspec
176
+ - spec/es_helper.rb
182
177
  - spec/inputs/elasticsearch_spec.rb
178
+ - spec/inputs/integration/elasticsearch_spec.rb
183
179
  homepage: http://www.elastic.co/guide/en/logstash/current/index.html
184
180
  licenses:
185
181
  - Apache License (2.0)
@@ -207,4 +203,6 @@ signing_key:
207
203
  specification_version: 4
208
204
  summary: Reads query results from an Elasticsearch cluster
209
205
  test_files:
206
+ - spec/es_helper.rb
210
207
  - spec/inputs/elasticsearch_spec.rb
208
+ - spec/inputs/integration/elasticsearch_spec.rb