logstash-output-elasticsearch 10.8.0-java → 10.8.6-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- maximum_seen_major_version < 8
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 = Zlib::GzipWriter.new(body_stream, Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY)
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
- bulk_actions.each do |action|
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 (body_stream.size + as_json.bytesize) > TARGET_BULK_BYTES
123
- bulk_responses << bulk_send(body_stream) unless body_stream.size == 0
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
- bulk_responses << bulk_send(body_stream) if body_stream.size > 0
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
- if response.code != 200
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
- LogStash::Json.load(response.body)
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.fetch(:license_checker) { LogStash::PluginMixins::ElasticSearch::NoopLicenseChecker::INSTANCE }
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
- bulk_response["items"].each_with_index do |response,idx|
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
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-elasticsearch'
3
- s.version = '10.8.0'
3
+ s.version = '10.8.6'
4
4
 
5
5
  s.licenses = ['apache-2.0']
6
6
  s.summary = "Stores logs in Elasticsearch"
@@ -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) { ESHelper.action_for_version(["index", {:_id=>nil, routing_field_name =>nil, :_index=>"logstash-2014.11.17", :_type=> doc_type }, event1]) }
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) { ESHelper.action_for_version(["index", {:_id=>nil, routing_field_name =>nil, :_index=>"logstash-2014.11.17", :_type=> doc_type }, event2]) }
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
- context "if a message is over TARGET_BULK_BYTES" do
216
- let(:target_bulk_bytes) { LogStash::Outputs::ElasticSearch::TARGET_BULK_BYTES }
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
- it "should be handled properly" do
220
- allow(subject).to receive(:join_bulk_responses)
221
- expect(subject).to receive(:bulk_send).once do |data|
222
- expect(data.size).to be > target_bulk_bytes
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
- context "with two messages" do
229
- let(:message1) { "hey" }
230
- let(:message2) { "you" }
231
- let(:actions) { [
232
- ["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message1}],
233
- ["index", {:_id=>nil, :_index=>"logstash"}, {"message"=> message2}],
234
- ]}
235
- it "executes one bulk_send operation" do
236
- allow(subject).to receive(:join_bulk_responses)
237
- expect(subject).to receive(:bulk_send).once
238
- s = subject.send(:bulk, actions)
239
- end
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
- context "if one exceeds TARGET_BULK_BYTES" do
242
- let(:target_bulk_bytes) { LogStash::Outputs::ElasticSearch::TARGET_BULK_BYTES }
243
- let(:message1) { "a" * (target_bulk_bytes + 1) }
244
- it "executes two bulk_send operations" do
245
- allow(subject).to receive(:join_bulk_responses)
246
- expect(subject).to receive(:bulk_send).twice
247
- s = subject.send(:bulk, actions)
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
- end
250
- end
268
+ end
269
+ end
251
270
  end
252
271
 
253
272
  describe "sniffing" do