logstash-output-elasticsearch 10.8.0-java → 10.8.6-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +1 -1
- data/docs/index.asciidoc +157 -99
- data/lib/logstash/outputs/elasticsearch.rb +3 -1
- data/lib/logstash/outputs/elasticsearch/http_client.rb +50 -14
- data/lib/logstash/outputs/elasticsearch/http_client/pool.rb +1 -1
- data/lib/logstash/plugin_mixins/elasticsearch/common.rb +10 -2
- data/logstash-output-elasticsearch.gemspec +1 -1
- data/spec/integration/outputs/ilm_spec.rb +16 -16
- data/spec/integration/outputs/retry_spec.rb +14 -2
- data/spec/unit/http_client_builder_spec.rb +9 -9
- data/spec/unit/outputs/elasticsearch/http_client/pool_spec.rb +3 -3
- data/spec/unit/outputs/elasticsearch/http_client_spec.rb +57 -38
- data/spec/unit/outputs/elasticsearch_proxy_spec.rb +3 -3
- data/spec/unit/outputs/elasticsearch_spec.rb +107 -16
- data/spec/unit/outputs/error_whitelist_spec.rb +1 -1
- metadata +2 -2
@@ -417,7 +417,9 @@ class LogStash::Outputs::ElasticSearch < LogStash::Outputs::Base
|
|
417
417
|
# @param noop_required_client [nil]: required `nil` for legacy reasons.
|
418
418
|
# @return [Boolean]
|
419
419
|
def use_event_type?(noop_required_client)
|
420
|
-
|
420
|
+
# always set type for ES <= 6
|
421
|
+
# for ES 7 only set it if the user defined it
|
422
|
+
(maximum_seen_major_version < 7) || (maximum_seen_major_version == 7 && @document_type)
|
421
423
|
end
|
422
424
|
|
423
425
|
def install_template
|
@@ -109,27 +109,50 @@ module LogStash; module Outputs; class ElasticSearch;
|
|
109
109
|
body_stream = StringIO.new
|
110
110
|
if http_compression
|
111
111
|
body_stream.set_encoding "BINARY"
|
112
|
-
stream_writer =
|
113
|
-
else
|
112
|
+
stream_writer = gzip_writer(body_stream)
|
113
|
+
else
|
114
114
|
stream_writer = body_stream
|
115
115
|
end
|
116
116
|
bulk_responses = []
|
117
|
-
|
117
|
+
batch_actions = []
|
118
|
+
bulk_actions.each_with_index do |action, index|
|
118
119
|
as_json = action.is_a?(Array) ?
|
119
120
|
action.map {|line| LogStash::Json.dump(line)}.join("\n") :
|
120
121
|
LogStash::Json.dump(action)
|
121
122
|
as_json << "\n"
|
122
|
-
if (
|
123
|
-
|
123
|
+
if (stream_writer.pos + as_json.bytesize) > TARGET_BULK_BYTES && stream_writer.pos > 0
|
124
|
+
stream_writer.flush # ensure writer has sync'd buffers before reporting sizes
|
125
|
+
logger.debug("Sending partial bulk request for batch with one or more actions remaining.",
|
126
|
+
:action_count => batch_actions.size,
|
127
|
+
:payload_size => stream_writer.pos,
|
128
|
+
:content_length => body_stream.size,
|
129
|
+
:batch_offset => (index + 1 - batch_actions.size))
|
130
|
+
bulk_responses << bulk_send(body_stream, batch_actions)
|
131
|
+
body_stream.truncate(0) && body_stream.seek(0)
|
132
|
+
stream_writer = gzip_writer(body_stream) if http_compression
|
133
|
+
batch_actions.clear
|
124
134
|
end
|
125
135
|
stream_writer.write(as_json)
|
136
|
+
batch_actions << action
|
126
137
|
end
|
127
138
|
stream_writer.close if http_compression
|
128
|
-
|
139
|
+
logger.debug("Sending final bulk request for batch.",
|
140
|
+
:action_count => batch_actions.size,
|
141
|
+
:payload_size => stream_writer.pos,
|
142
|
+
:content_length => body_stream.size,
|
143
|
+
:batch_offset => (actions.size - batch_actions.size))
|
144
|
+
bulk_responses << bulk_send(body_stream, batch_actions) if body_stream.size > 0
|
129
145
|
body_stream.close if !http_compression
|
130
146
|
join_bulk_responses(bulk_responses)
|
131
147
|
end
|
132
148
|
|
149
|
+
def gzip_writer(io)
|
150
|
+
fail(ArgumentError, "Cannot create gzip writer on IO with unread bytes") unless io.eof?
|
151
|
+
fail(ArgumentError, "Cannot create gzip writer on non-empty IO") unless io.pos == 0
|
152
|
+
|
153
|
+
Zlib::GzipWriter.new(io, Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY)
|
154
|
+
end
|
155
|
+
|
133
156
|
def join_bulk_responses(bulk_responses)
|
134
157
|
{
|
135
158
|
"errors" => bulk_responses.any? {|r| r["errors"] == true},
|
@@ -137,25 +160,37 @@ module LogStash; module Outputs; class ElasticSearch;
|
|
137
160
|
}
|
138
161
|
end
|
139
162
|
|
140
|
-
def bulk_send(body_stream)
|
163
|
+
def bulk_send(body_stream, batch_actions)
|
141
164
|
params = http_compression ? {:headers => {"Content-Encoding" => "gzip"}} : {}
|
142
|
-
# Discard the URL
|
143
165
|
response = @pool.post(@bulk_path, params, body_stream.string)
|
144
|
-
if !body_stream.closed?
|
145
|
-
body_stream.truncate(0)
|
146
|
-
body_stream.seek(0)
|
147
|
-
end
|
148
166
|
|
149
167
|
@bulk_response_metrics.increment(response.code.to_s)
|
150
168
|
|
151
|
-
|
169
|
+
case response.code
|
170
|
+
when 200 # OK
|
171
|
+
LogStash::Json.load(response.body)
|
172
|
+
when 413 # Payload Too Large
|
173
|
+
logger.warn("Bulk request rejected: `413 Payload Too Large`", :action_count => batch_actions.size, :content_length => body_stream.size)
|
174
|
+
emulate_batch_error_response(batch_actions, response.code, 'payload_too_large')
|
175
|
+
else
|
152
176
|
url = ::LogStash::Util::SafeURI.new(response.final_url)
|
153
177
|
raise ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError.new(
|
154
178
|
response.code, url, body_stream.to_s, response.body
|
155
179
|
)
|
156
180
|
end
|
181
|
+
end
|
157
182
|
|
158
|
-
|
183
|
+
def emulate_batch_error_response(actions, http_code, reason)
|
184
|
+
{
|
185
|
+
"errors" => true,
|
186
|
+
"items" => actions.map do |action|
|
187
|
+
action = action.first if action.is_a?(Array)
|
188
|
+
request_action, request_parameters = action.first
|
189
|
+
{
|
190
|
+
request_action => {"status" => http_code, "error" => { "type" => reason }}
|
191
|
+
}
|
192
|
+
end
|
193
|
+
}
|
159
194
|
end
|
160
195
|
|
161
196
|
def get(path)
|
@@ -400,6 +435,7 @@ module LogStash; module Outputs; class ElasticSearch;
|
|
400
435
|
|
401
436
|
# Build a bulk item for an elasticsearch update action
|
402
437
|
def update_action_builder(args, source)
|
438
|
+
args = args.clone()
|
403
439
|
if args[:_script]
|
404
440
|
# Use the event as a hash from your script with variable name defined
|
405
441
|
# by script_var_name (default: "event")
|
@@ -70,7 +70,7 @@ module LogStash; module Outputs; class ElasticSearch; class HttpClient;
|
|
70
70
|
@url_info = {}
|
71
71
|
@stopping = false
|
72
72
|
|
73
|
-
@license_checker = options
|
73
|
+
@license_checker = options[:license_checker] || LogStash::PluginMixins::ElasticSearch::NoopLicenseChecker::INSTANCE
|
74
74
|
end
|
75
75
|
|
76
76
|
def start
|
@@ -204,8 +204,16 @@ module LogStash; module PluginMixins; module ElasticSearch
|
|
204
204
|
return
|
205
205
|
end
|
206
206
|
|
207
|
+
responses = bulk_response["items"]
|
208
|
+
if responses.size != actions.size # can not map action -> response reliably
|
209
|
+
# an ES bug (on 7.10.2, 7.11.1) where a _bulk request to index X documents would return Y (> X) items
|
210
|
+
msg = "Sent #{actions.size} documents but Elasticsearch returned #{responses.size} responses"
|
211
|
+
@logger.warn(msg, actions: actions, responses: responses)
|
212
|
+
fail("#{msg} (likely a bug with _bulk endpoint)")
|
213
|
+
end
|
214
|
+
|
207
215
|
actions_to_retry = []
|
208
|
-
|
216
|
+
responses.each_with_index do |response,idx|
|
209
217
|
action_type, action_props = response.first
|
210
218
|
|
211
219
|
status = action_props["status"]
|
@@ -291,7 +299,7 @@ module LogStash; module PluginMixins; module ElasticSearch
|
|
291
299
|
retry unless @stopping.true?
|
292
300
|
rescue ::LogStash::Outputs::ElasticSearch::HttpClient::Pool::BadResponseCodeError => e
|
293
301
|
@bulk_request_metrics.increment(:failures)
|
294
|
-
log_hash = {:code => e.response_code, :url => e.url.sanitized.to_s}
|
302
|
+
log_hash = {:code => e.response_code, :url => e.url.sanitized.to_s, :content_length => e.request_body.bytesize}
|
295
303
|
log_hash[:body] = e.response_body if @logger.debug? # Generally this is too verbose
|
296
304
|
message = "Encountered a retryable error. Will Retry with exponential backoff "
|
297
305
|
|
@@ -5,7 +5,7 @@ shared_examples_for 'an ILM enabled Logstash' do
|
|
5
5
|
context 'with a policy with a maximum number of documents' do
|
6
6
|
let (:policy) { small_max_doc_policy }
|
7
7
|
let (:ilm_policy_name) { "logstash-policy-custom"}
|
8
|
-
let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
|
8
|
+
let (:settings) { super().merge("ilm_policy" => ilm_policy_name)}
|
9
9
|
|
10
10
|
it 'should rollover when the policy max docs is reached' do
|
11
11
|
put_policy(@es, ilm_policy_name, policy)
|
@@ -54,7 +54,7 @@ shared_examples_for 'an ILM enabled Logstash' do
|
|
54
54
|
context 'with a policy where the maximum number of documents is not reached' do
|
55
55
|
let (:policy) { large_max_doc_policy }
|
56
56
|
let (:ilm_policy_name) { "logstash-policy-custom-policy"}
|
57
|
-
let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
|
57
|
+
let (:settings) { super().merge("ilm_policy" => ilm_policy_name)}
|
58
58
|
|
59
59
|
it 'should ingest into a single index when max docs is not reached' do
|
60
60
|
put_policy(@es,ilm_policy_name, policy)
|
@@ -119,7 +119,7 @@ shared_examples_for 'an ILM disabled Logstash' do
|
|
119
119
|
context 'with an existing policy that will roll over' do
|
120
120
|
let (:policy) { small_max_doc_policy }
|
121
121
|
let (:ilm_policy_name) { "logstash-policy-3_docs"}
|
122
|
-
let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
|
122
|
+
let (:settings) { super().merge("ilm_policy" => ilm_policy_name)}
|
123
123
|
|
124
124
|
it 'should not roll over indices' do
|
125
125
|
subject.register
|
@@ -155,7 +155,7 @@ shared_examples_for 'an ILM disabled Logstash' do
|
|
155
155
|
|
156
156
|
context 'with a custom template name' do
|
157
157
|
let (:template_name) { "logstash_custom_template_name" }
|
158
|
-
let (:settings) { super.merge('template_name' => template_name)}
|
158
|
+
let (:settings) { super().merge('template_name' => template_name)}
|
159
159
|
|
160
160
|
it 'should not write the ILM settings into the template' do
|
161
161
|
subject.register
|
@@ -195,7 +195,7 @@ shared_examples_for 'an Elasticsearch instance that does not support index lifec
|
|
195
195
|
subject { LogStash::Outputs::ElasticSearch.new(settings) }
|
196
196
|
|
197
197
|
context 'when ilm is enabled in Logstash' do
|
198
|
-
let (:settings) { super.merge!({ 'ilm_enabled' => true }) }
|
198
|
+
let (:settings) { super().merge!({ 'ilm_enabled' => true }) }
|
199
199
|
|
200
200
|
it 'should raise a configuration error' do
|
201
201
|
expect do
|
@@ -210,13 +210,13 @@ shared_examples_for 'an Elasticsearch instance that does not support index lifec
|
|
210
210
|
end
|
211
211
|
|
212
212
|
context 'when ilm is disabled in Logstash' do
|
213
|
-
let (:settings) { super.merge!({ 'ilm_enabled' => false }) }
|
213
|
+
let (:settings) { super().merge!({ 'ilm_enabled' => false }) }
|
214
214
|
|
215
215
|
it_behaves_like 'an ILM disabled Logstash'
|
216
216
|
end
|
217
217
|
|
218
218
|
context 'when ilm is set to auto in Logstash' do
|
219
|
-
let (:settings) { super.merge!({ 'ilm_enabled' => 'auto' }) }
|
219
|
+
let (:settings) { super().merge!({ 'ilm_enabled' => 'auto' }) }
|
220
220
|
|
221
221
|
it_behaves_like 'an ILM disabled Logstash'
|
222
222
|
end
|
@@ -286,7 +286,7 @@ if ESHelper.es_version_satisfies?(">= 6.6")
|
|
286
286
|
|
287
287
|
context 'when using the default policy' do
|
288
288
|
context 'with a custom pattern' do
|
289
|
-
let (:settings) { super.merge("ilm_pattern" => "000001")}
|
289
|
+
let (:settings) { super().merge("ilm_pattern" => "000001")}
|
290
290
|
it 'should create a rollover alias' do
|
291
291
|
expect(@es.indices.exists_alias(name: "logstash")).to be_falsey
|
292
292
|
subject.register
|
@@ -346,7 +346,7 @@ if ESHelper.es_version_satisfies?(">= 6.6")
|
|
346
346
|
|
347
347
|
context 'when not using the default policy' do
|
348
348
|
let (:ilm_policy_name) {"logstash-policy-small"}
|
349
|
-
let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
|
349
|
+
let (:settings) { super().merge("ilm_policy" => ilm_policy_name)}
|
350
350
|
let (:policy) { small_max_doc_policy }
|
351
351
|
|
352
352
|
before do
|
@@ -363,7 +363,7 @@ if ESHelper.es_version_satisfies?(">= 6.6")
|
|
363
363
|
|
364
364
|
context 'when using a time based policy' do
|
365
365
|
let (:ilm_policy_name) {"logstash-policy-time"}
|
366
|
-
let (:settings) { super.merge("ilm_policy" => ilm_policy_name)}
|
366
|
+
let (:settings) { super().merge("ilm_policy" => ilm_policy_name)}
|
367
367
|
let (:policy) { max_age_policy("1d") }
|
368
368
|
|
369
369
|
before do
|
@@ -409,7 +409,7 @@ if ESHelper.es_version_satisfies?(">= 6.6")
|
|
409
409
|
let (:template) { "spec/fixtures/template-with-policy-es6x.json" }
|
410
410
|
end
|
411
411
|
|
412
|
-
let (:settings) { super.merge("template" => template,
|
412
|
+
let (:settings) { super().merge("template" => template,
|
413
413
|
"index" => "overwrite-4")}
|
414
414
|
|
415
415
|
it 'should not overwrite the index patterns' do
|
@@ -426,7 +426,7 @@ if ESHelper.es_version_satisfies?(">= 6.6")
|
|
426
426
|
let (:ilm_rollover_alias) { "logstash_the_cat_in_the_hat" }
|
427
427
|
let (:index) { ilm_rollover_alias }
|
428
428
|
let(:expected_index) { index }
|
429
|
-
let (:settings) { super.merge("ilm_policy" => ilm_policy_name,
|
429
|
+
let (:settings) { super().merge("ilm_policy" => ilm_policy_name,
|
430
430
|
"template" => template,
|
431
431
|
"ilm_rollover_alias" => ilm_rollover_alias)}
|
432
432
|
|
@@ -480,7 +480,7 @@ if ESHelper.es_version_satisfies?(">= 6.6")
|
|
480
480
|
|
481
481
|
context 'with a different template_name' do
|
482
482
|
let (:template_name) { "logstash_custom_template_name" }
|
483
|
-
let (:settings) { super.merge('template_name' => template_name)}
|
483
|
+
let (:settings) { super().merge('template_name' => template_name)}
|
484
484
|
|
485
485
|
it_behaves_like 'an ILM enabled Logstash'
|
486
486
|
|
@@ -514,7 +514,7 @@ if ESHelper.es_version_satisfies?(">= 6.6")
|
|
514
514
|
end
|
515
515
|
|
516
516
|
context 'when ilm_enabled is the default' do
|
517
|
-
let (:settings) { super.tap{|x|x.delete('ilm_enabled')}}
|
517
|
+
let (:settings) { super().tap{|x|x.delete('ilm_enabled')}}
|
518
518
|
|
519
519
|
if ESHelper.es_version_satisfies?(">=7.0")
|
520
520
|
context 'when Elasticsearch is version 7 or above' do
|
@@ -530,13 +530,13 @@ if ESHelper.es_version_satisfies?(">= 6.6")
|
|
530
530
|
end
|
531
531
|
|
532
532
|
context 'with ilm disabled' do
|
533
|
-
let (:settings) { super.merge('ilm_enabled' => false )}
|
533
|
+
let (:settings) { super().merge('ilm_enabled' => false )}
|
534
534
|
|
535
535
|
it_behaves_like 'an ILM disabled Logstash'
|
536
536
|
end
|
537
537
|
|
538
538
|
context 'with ilm disabled using a string' do
|
539
|
-
let (:settings) { super.merge('ilm_enabled' => 'false' )}
|
539
|
+
let (:settings) { super().merge('ilm_enabled' => 'false' )}
|
540
540
|
|
541
541
|
it_behaves_like 'an ILM disabled Logstash'
|
542
542
|
end
|
@@ -4,9 +4,21 @@ require_relative "../../../spec/es_spec_helper"
|
|
4
4
|
describe "failures in bulk class expected behavior", :integration => true do
|
5
5
|
let(:template) { '{"template" : "not important, will be updated by :index"}' }
|
6
6
|
let(:event1) { LogStash::Event.new("somevalue" => 100, "@timestamp" => "2014-11-17T20:37:17.223Z", "@metadata" => {"retry_count" => 0}) }
|
7
|
-
let(:action1)
|
7
|
+
let(:action1) do
|
8
|
+
if ESHelper.es_version_satisfies?(">= 6", "< 7")
|
9
|
+
ESHelper.action_for_version(["index", {:_id=>nil, routing_field_name =>nil, :_index=>"logstash-2014.11.17", :_type=> doc_type }, event1])
|
10
|
+
else
|
11
|
+
ESHelper.action_for_version(["index", {:_id=>nil, routing_field_name =>nil, :_index=>"logstash-2014.11.17" }, event1])
|
12
|
+
end
|
13
|
+
end
|
8
14
|
let(:event2) { LogStash::Event.new("geoip" => { "location" => [ 0.0, 0.0] }, "@timestamp" => "2014-11-17T20:37:17.223Z", "@metadata" => {"retry_count" => 0}) }
|
9
|
-
let(:action2)
|
15
|
+
let(:action2) do
|
16
|
+
if ESHelper.es_version_satisfies?(">= 6", "< 7")
|
17
|
+
ESHelper.action_for_version(["index", {:_id=>nil, routing_field_name =>nil, :_index=>"logstash-2014.11.17", :_type=> doc_type }, event2])
|
18
|
+
else
|
19
|
+
ESHelper.action_for_version(["index", {:_id=>nil, routing_field_name =>nil, :_index=>"logstash-2014.11.17" }, event2])
|
20
|
+
end
|
21
|
+
end
|
10
22
|
let(:invalid_event) { LogStash::Event.new("geoip" => { "location" => "notlatlon" }, "@timestamp" => "2014-11-17T20:37:17.223Z") }
|
11
23
|
|
12
24
|
def mock_actions_with_response(*resp)
|
@@ -40,10 +40,10 @@ describe LogStash::Outputs::ElasticSearch::HttpClientBuilder do
|
|
40
40
|
|
41
41
|
context "when setting bulk_path" do
|
42
42
|
let(:bulk_path) { "/meh" }
|
43
|
-
let(:options) { super.merge("bulk_path" => bulk_path) }
|
43
|
+
let(:options) { super().merge("bulk_path" => bulk_path) }
|
44
44
|
|
45
45
|
context "when using path" do
|
46
|
-
let(:options) { super.merge("path" => "/path") }
|
46
|
+
let(:options) { super().merge("path" => "/path") }
|
47
47
|
it "ignores the path setting" do
|
48
48
|
expect(described_class).to receive(:create_http_client) do |options|
|
49
49
|
expect(options[:bulk_path]).to eq(bulk_path)
|
@@ -66,7 +66,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClientBuilder do
|
|
66
66
|
|
67
67
|
context "when using path" do
|
68
68
|
let(:path) { "/meh" }
|
69
|
-
let(:options) { super.merge("path" => path) }
|
69
|
+
let(:options) { super().merge("path" => path) }
|
70
70
|
it "sets bulk_path to path+_bulk" do
|
71
71
|
expect(described_class).to receive(:create_http_client) do |options|
|
72
72
|
expect(options[:bulk_path]).to eq("#{path}/_bulk")
|
@@ -88,10 +88,10 @@ describe LogStash::Outputs::ElasticSearch::HttpClientBuilder do
|
|
88
88
|
describe "healthcheck_path" do
|
89
89
|
context "when setting healthcheck_path" do
|
90
90
|
let(:healthcheck_path) { "/meh" }
|
91
|
-
let(:options) { super.merge("healthcheck_path" => healthcheck_path) }
|
91
|
+
let(:options) { super().merge("healthcheck_path" => healthcheck_path) }
|
92
92
|
|
93
93
|
context "when using path" do
|
94
|
-
let(:options) { super.merge("path" => "/path") }
|
94
|
+
let(:options) { super().merge("path" => "/path") }
|
95
95
|
it "ignores the path setting" do
|
96
96
|
expect(described_class).to receive(:create_http_client) do |options|
|
97
97
|
expect(options[:healthcheck_path]).to eq(healthcheck_path)
|
@@ -114,7 +114,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClientBuilder do
|
|
114
114
|
|
115
115
|
context "when using path" do
|
116
116
|
let(:path) { "/meh" }
|
117
|
-
let(:options) { super.merge("path" => path) }
|
117
|
+
let(:options) { super().merge("path" => path) }
|
118
118
|
it "sets healthcheck_path to path" do
|
119
119
|
expect(described_class).to receive(:create_http_client) do |options|
|
120
120
|
expect(options[:healthcheck_path]).to eq(path)
|
@@ -136,10 +136,10 @@ describe LogStash::Outputs::ElasticSearch::HttpClientBuilder do
|
|
136
136
|
describe "sniffing_path" do
|
137
137
|
context "when setting sniffing_path" do
|
138
138
|
let(:sniffing_path) { "/meh" }
|
139
|
-
let(:options) { super.merge("sniffing_path" => sniffing_path) }
|
139
|
+
let(:options) { super().merge("sniffing_path" => sniffing_path) }
|
140
140
|
|
141
141
|
context "when using path" do
|
142
|
-
let(:options) { super.merge("path" => "/path") }
|
142
|
+
let(:options) { super().merge("path" => "/path") }
|
143
143
|
it "ignores the path setting" do
|
144
144
|
expect(described_class).to receive(:create_http_client) do |options|
|
145
145
|
expect(options[:sniffing_path]).to eq(sniffing_path)
|
@@ -162,7 +162,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClientBuilder do
|
|
162
162
|
|
163
163
|
context "when using path" do
|
164
164
|
let(:path) { "/meh" }
|
165
|
-
let(:options) { super.merge("path" => path) }
|
165
|
+
let(:options) { super().merge("path" => path) }
|
166
166
|
it "sets sniffing_path to path+_nodes/http" do
|
167
167
|
expect(described_class).to receive(:create_http_client) do |options|
|
168
168
|
expect(options[:sniffing_path]).to eq("#{path}/_nodes/http")
|
@@ -68,7 +68,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
68
68
|
|
69
69
|
context "and setting healthcheck_path" do
|
70
70
|
let(:healthcheck_path) { "/my/health" }
|
71
|
-
let(:options) { super.merge(:healthcheck_path => healthcheck_path) }
|
71
|
+
let(:options) { super().merge(:healthcheck_path => healthcheck_path) }
|
72
72
|
it "performs the healthcheck to the healthcheck_path" do
|
73
73
|
expect(adapter).to receive(:perform_request) do |url, method, req_path, _, _|
|
74
74
|
expect(method).to eq(:head)
|
@@ -130,7 +130,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
130
130
|
end
|
131
131
|
|
132
132
|
context "when enabled" do
|
133
|
-
let(:options) { super.merge(:sniffing => true)}
|
133
|
+
let(:options) { super().merge(:sniffing => true)}
|
134
134
|
|
135
135
|
it "should start the sniffer" do
|
136
136
|
expect(subject.sniffer_alive?).to eql(true)
|
@@ -247,7 +247,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient::Pool do
|
|
247
247
|
end
|
248
248
|
|
249
249
|
let(:options) do
|
250
|
-
super.merge(:license_checker => license_checker)
|
250
|
+
super().merge(:license_checker => license_checker)
|
251
251
|
end
|
252
252
|
|
253
253
|
context 'when LicenseChecker#acceptable_license? returns false' do
|
@@ -48,7 +48,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
48
48
|
describe "ssl" do
|
49
49
|
context "when SSL is true" do
|
50
50
|
let(:ssl) { true }
|
51
|
-
let(:base_options) { super.merge(:hosts => [http_hostname_port]) }
|
51
|
+
let(:base_options) { super().merge(:hosts => [http_hostname_port]) }
|
52
52
|
|
53
53
|
it "should refuse to handle an http url" do
|
54
54
|
expect {
|
@@ -59,7 +59,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
59
59
|
|
60
60
|
context "when SSL is false" do
|
61
61
|
let(:ssl) { false }
|
62
|
-
let(:base_options) { super.merge(:hosts => [https_hostname_port]) }
|
62
|
+
let(:base_options) { super().merge(:hosts => [https_hostname_port]) }
|
63
63
|
|
64
64
|
it "should refuse to handle an https url" do
|
65
65
|
expect {
|
@@ -69,7 +69,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
describe "ssl is nil" do
|
72
|
-
let(:base_options) { super.merge(:hosts => [https_hostname_port]) }
|
72
|
+
let(:base_options) { super().merge(:hosts => [https_hostname_port]) }
|
73
73
|
it "should handle an ssl url correctly when SSL is nil" do
|
74
74
|
subject
|
75
75
|
expect(subject.host_to_url(https_hostname_port).to_s).to eq(https_hostname_port.to_s + "/")
|
@@ -79,14 +79,14 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
79
79
|
|
80
80
|
describe "path" do
|
81
81
|
let(:url) { http_hostname_port_path }
|
82
|
-
let(:base_options) { super.merge(:hosts => [url]) }
|
82
|
+
let(:base_options) { super().merge(:hosts => [url]) }
|
83
83
|
|
84
84
|
it "should allow paths in a url" do
|
85
85
|
expect(subject.host_to_url(url)).to eq(url)
|
86
86
|
end
|
87
87
|
|
88
88
|
context "with the path option set" do
|
89
|
-
let(:base_options) { super.merge(:client_settings => {:path => "/otherpath"}) }
|
89
|
+
let(:base_options) { super().merge(:client_settings => {:path => "/otherpath"}) }
|
90
90
|
|
91
91
|
it "should not allow paths in two places" do
|
92
92
|
expect {
|
@@ -97,7 +97,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
97
97
|
|
98
98
|
context "with a path missing a leading /" do
|
99
99
|
let(:url) { http_hostname_port }
|
100
|
-
let(:base_options) { super.merge(:client_settings => {:path => "otherpath"}) }
|
100
|
+
let(:base_options) { super().merge(:client_settings => {:path => "otherpath"}) }
|
101
101
|
|
102
102
|
|
103
103
|
it "should automatically insert a / in front of path overlays" do
|
@@ -204,7 +204,7 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
204
204
|
end
|
205
205
|
|
206
206
|
describe "#bulk" do
|
207
|
-
subject { described_class.new(base_options) }
|
207
|
+
subject(:http_client) { described_class.new(base_options) }
|
208
208
|
|
209
209
|
require "json"
|
210
210
|
let(:message) { "hey" }
|
@@ -212,42 +212,61 @@ describe LogStash::Outputs::ElasticSearch::HttpClient do
|
|
212
212
|
["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message}],
|
213
213
|
]}
|
214
214
|
|
215
|
-
|
216
|
-
|
217
|
-
let(:message) { "a" * (target_bulk_bytes + 1) }
|
215
|
+
[true,false].each do |http_compression_enabled|
|
216
|
+
context "with `http_compression => #{http_compression_enabled}`" do
|
218
217
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
218
|
+
let(:base_options) { super().merge(:client_settings => {:http_compression => http_compression_enabled}) }
|
219
|
+
|
220
|
+
before(:each) do
|
221
|
+
if http_compression_enabled
|
222
|
+
expect(http_client).to receive(:gzip_writer).at_least(:once).and_call_original
|
223
|
+
else
|
224
|
+
expect(http_client).to_not receive(:gzip_writer)
|
225
|
+
end
|
223
226
|
end
|
224
|
-
s = subject.send(:bulk, actions)
|
225
|
-
end
|
226
|
-
end
|
227
227
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
228
|
+
context "if a message is over TARGET_BULK_BYTES" do
|
229
|
+
let(:target_bulk_bytes) { LogStash::Outputs::ElasticSearch::TARGET_BULK_BYTES }
|
230
|
+
let(:message) { "a" * (target_bulk_bytes + 1) }
|
231
|
+
|
232
|
+
it "should be handled properly" do
|
233
|
+
allow(subject).to receive(:join_bulk_responses)
|
234
|
+
expect(subject).to receive(:bulk_send).once do |data|
|
235
|
+
if !http_compression_enabled
|
236
|
+
expect(data.size).to be > target_bulk_bytes
|
237
|
+
else
|
238
|
+
expect(Zlib::gunzip(data.string).size).to be > target_bulk_bytes
|
239
|
+
end
|
240
|
+
end
|
241
|
+
s = subject.send(:bulk, actions)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context "with two messages" do
|
246
|
+
let(:message1) { "hey" }
|
247
|
+
let(:message2) { "you" }
|
248
|
+
let(:actions) { [
|
249
|
+
["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message1}],
|
250
|
+
["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message2}],
|
251
|
+
]}
|
252
|
+
it "executes one bulk_send operation" do
|
253
|
+
allow(subject).to receive(:join_bulk_responses)
|
254
|
+
expect(subject).to receive(:bulk_send).once
|
255
|
+
s = subject.send(:bulk, actions)
|
256
|
+
end
|
240
257
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
258
|
+
context "if one exceeds TARGET_BULK_BYTES" do
|
259
|
+
let(:target_bulk_bytes) { LogStash::Outputs::ElasticSearch::TARGET_BULK_BYTES }
|
260
|
+
let(:message1) { "a" * (target_bulk_bytes + 1) }
|
261
|
+
it "executes two bulk_send operations" do
|
262
|
+
allow(subject).to receive(:join_bulk_responses)
|
263
|
+
expect(subject).to receive(:bulk_send).twice
|
264
|
+
s = subject.send(:bulk, actions)
|
265
|
+
end
|
266
|
+
end
|
248
267
|
end
|
249
|
-
|
250
|
-
|
268
|
+
end
|
269
|
+
end
|
251
270
|
end
|
252
271
|
|
253
272
|
describe "sniffing" do
|