logstash-output-http 5.1.2 → 5.2.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/docs/index.asciidoc +7 -2
- data/lib/logstash/outputs/http.rb +56 -16
- data/logstash-output-http.gemspec +1 -1
- data/spec/outputs/http_spec.rb +49 -16
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74a3adbb0ae7188d50a8c025f7fd256cfb4adb36e4e17862c6d64ae6b6b6c8ee
|
4
|
+
data.tar.gz: 72e55c3f943a81d2e5e89e4a52ba54a39495e7f9ea3e684273822d7dc59d7ec4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7d0109785a2fe03f9936e6a7d56cf6406d3c81c1f66f7afdae0d45fe9b998dfdd95fe1e5970ccec15b69f6f884e9104aacfc7ca063a83d7feae3b35e278bb8a
|
7
|
+
data.tar.gz: 074e51a776ec7c1b12f3fbb33ccc9da9d6bd1188b32884bd6403506709c09083c930420550f9ee5ce2d8c5a4aff32dcc709972df71a53bb69c6a05044b1580fe
|
data/CHANGELOG.md
CHANGED
data/docs/index.asciidoc
CHANGED
@@ -46,7 +46,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
|
|
46
46
|
| <<plugins-{type}s-{plugin}-content_type>> |<<string,string>>|No
|
47
47
|
| <<plugins-{type}s-{plugin}-cookies>> |<<boolean,boolean>>|No
|
48
48
|
| <<plugins-{type}s-{plugin}-follow_redirects>> |<<boolean,boolean>>|No
|
49
|
-
| <<plugins-{type}s-{plugin}-format>> |<<string,string>>, one of `["json", "form", "message"]`|No
|
49
|
+
| <<plugins-{type}s-{plugin}-format>> |<<string,string>>, one of `["json", "json_batch", "form", "message"]`|No
|
50
50
|
| <<plugins-{type}s-{plugin}-headers>> |<<hash,hash>>|No
|
51
51
|
| <<plugins-{type}s-{plugin}-http_compression>> |<<boolean,boolean>>|No
|
52
52
|
| <<plugins-{type}s-{plugin}-http_method>> |<<string,string>>, one of `["put", "post", "patch", "delete", "get", "head"]`|Yes
|
@@ -130,6 +130,7 @@ Content type
|
|
130
130
|
If not specified, this defaults to the following:
|
131
131
|
|
132
132
|
* if format is "json", "application/json"
|
133
|
+
* if format is "json_batch", "application/json". Each Logstash batch of events will be concatenated into a single array and sent in one request.
|
133
134
|
* if format is "form", "application/x-www-form-urlencoded"
|
134
135
|
|
135
136
|
[id="plugins-{type}s-{plugin}-cookies"]
|
@@ -152,11 +153,15 @@ Should redirects be followed? Defaults to `true`
|
|
152
153
|
[id="plugins-{type}s-{plugin}-format"]
|
153
154
|
===== `format`
|
154
155
|
|
155
|
-
* Value can be any of: `json`, `form`, `message`
|
156
|
+
* Value can be any of: `json`, `json_batch`, `form`, `message`
|
156
157
|
* Default value is `"json"`
|
157
158
|
|
158
159
|
Set the format of the http body.
|
159
160
|
|
161
|
+
If json_batch, each batch of events received by this output will be placed
|
162
|
+
into a single JSON array and sent in one request. This is particularly useful
|
163
|
+
for high throughput scenarios such as sending data between Logstash instaces.
|
164
|
+
|
160
165
|
If form, then the body will be the mapping (or whole event) converted
|
161
166
|
into a query parameter string, e.g. `foo=bar&baz=fizz...`
|
162
167
|
|
@@ -42,7 +42,7 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
42
42
|
|
43
43
|
# Custom headers to use
|
44
44
|
# format is `headers => ["X-My-Header", "%{host}"]`
|
45
|
-
config :headers, :validate => :hash
|
45
|
+
config :headers, :validate => :hash, :default => {}
|
46
46
|
|
47
47
|
# Content type
|
48
48
|
#
|
@@ -79,7 +79,7 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
79
79
|
# If message, then the body will be the result of formatting the event according to message
|
80
80
|
#
|
81
81
|
# Otherwise, the event is sent as json.
|
82
|
-
config :format, :validate => ["json", "form", "message"], :default => "json"
|
82
|
+
config :format, :validate => ["json", "json_batch", "form", "message"], :default => "json"
|
83
83
|
|
84
84
|
# Set this to true if you want to enable gzip compression for your http requests
|
85
85
|
config :http_compression, :validate => :boolean, :default => false
|
@@ -102,10 +102,14 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
102
102
|
case @format
|
103
103
|
when "form" ; @content_type = "application/x-www-form-urlencoded"
|
104
104
|
when "json" ; @content_type = "application/json"
|
105
|
+
when "json_batch" ; @content_type = "application/json"
|
105
106
|
when "message" ; @content_type = "text/plain"
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|
110
|
+
|
111
|
+
@headers["Content-Type"] = @content_type
|
112
|
+
|
109
113
|
validate_format!
|
110
114
|
|
111
115
|
# Run named Timer as daemon thread
|
@@ -113,7 +117,12 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
113
117
|
end # def register
|
114
118
|
|
115
119
|
def multi_receive(events)
|
116
|
-
|
120
|
+
return if events.empty?
|
121
|
+
if @format == "json_batch"
|
122
|
+
send_json_batch(events)
|
123
|
+
else
|
124
|
+
send_events(events)
|
125
|
+
end
|
117
126
|
end
|
118
127
|
|
119
128
|
class RetryTimerTask < java.util.TimerTask
|
@@ -128,6 +137,46 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
128
137
|
@pending << [@event, @attempt]
|
129
138
|
end
|
130
139
|
end
|
140
|
+
|
141
|
+
def send_json_batch(events)
|
142
|
+
attempt = 1
|
143
|
+
body = LogStash::Json.dump(events.map {|e| map_event(e) })
|
144
|
+
begin
|
145
|
+
while true
|
146
|
+
request = client.send(@http_method, @url, :body => body, :headers => @headers)
|
147
|
+
response = request.call
|
148
|
+
break if response_success?(response)
|
149
|
+
if retryable_response?(response)
|
150
|
+
log_retryable_response(response)
|
151
|
+
sleep_for_attempt attempt
|
152
|
+
attempt += 1
|
153
|
+
else
|
154
|
+
log_error_response(response, url, events)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
rescue *RETRYABLE_MANTICORE_EXCEPTIONS => e
|
158
|
+
logger.warn("Encountered exception during http output send, will retry after delay", :message => e.message, :class => e.class.name)
|
159
|
+
sleep_for_attempt attempt
|
160
|
+
retry
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def log_retryable_response(response)
|
165
|
+
if (response.code == 429)
|
166
|
+
@logger.debug? && @logger.debug("Encountered a 429 response, will retry. This is not serious, just flow control via HTTP")
|
167
|
+
else
|
168
|
+
@logger.warn("Encountered a retryable HTTP request in HTTP output, will retry", :code => response.code, :body => response.body)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def log_error_response(response, url, event)
|
173
|
+
log_failure(
|
174
|
+
"Encountered non-2xx HTTP code #{response.code}",
|
175
|
+
:response_code => response.code,
|
176
|
+
:url => url,
|
177
|
+
:event => event
|
178
|
+
)
|
179
|
+
end
|
131
180
|
|
132
181
|
def send_events(events)
|
133
182
|
successes = java.util.concurrent.atomic.AtomicInteger.new(0)
|
@@ -212,18 +261,11 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
212
261
|
request.on_success do |response|
|
213
262
|
begin
|
214
263
|
if !response_success?(response)
|
215
|
-
|
216
|
-
|
217
|
-
"Encountered non-2xx HTTP code #{response.code}",
|
218
|
-
:response_code => response.code,
|
219
|
-
:url => url,
|
220
|
-
:event => event,
|
221
|
-
:will_retry => will_retry
|
222
|
-
)
|
223
|
-
|
224
|
-
if will_retry
|
264
|
+
if retryable_response?(response)
|
265
|
+
log_retryable_response(response)
|
225
266
|
yield :retry, event, attempt
|
226
267
|
else
|
268
|
+
log_error_response(response, url, event)
|
227
269
|
yield :failure, event, attempt
|
228
270
|
end
|
229
271
|
else
|
@@ -343,9 +385,7 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
343
385
|
end
|
344
386
|
|
345
387
|
def event_headers(event)
|
346
|
-
|
347
|
-
headers["Content-Type"] = @content_type
|
348
|
-
headers
|
388
|
+
custom_headers(event) || {}
|
349
389
|
end
|
350
390
|
|
351
391
|
def custom_headers(event)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-output-http'
|
3
|
-
s.version = '5.
|
3
|
+
s.version = '5.2.0'
|
4
4
|
s.licenses = ['Apache License (2.0)']
|
5
5
|
s.summary = "Sends events to a generic HTTP or HTTPS endpoint"
|
6
6
|
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"
|
data/spec/outputs/http_spec.rb
CHANGED
@@ -47,7 +47,7 @@ class TestApp < Sinatra::Base
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def self.retry_fail_count()
|
50
|
-
@retry_fail_count
|
50
|
+
@retry_fail_count || 2
|
51
51
|
end
|
52
52
|
|
53
53
|
multiroute(%w(get post put patch delete), "/good") do
|
@@ -126,6 +126,7 @@ describe LogStash::Outputs::Http do
|
|
126
126
|
with(expected_method, url, anything).
|
127
127
|
and_call_original
|
128
128
|
allow(subject).to receive(:log_failure).with(any_args)
|
129
|
+
allow(subject).to receive(:log_retryable_response).with(any_args)
|
129
130
|
end
|
130
131
|
|
131
132
|
context 'sending no events' do
|
@@ -190,8 +191,8 @@ describe LogStash::Outputs::Http do
|
|
190
191
|
subject.multi_receive([event])
|
191
192
|
end
|
192
193
|
|
193
|
-
it "should log a
|
194
|
-
expect(subject).to have_received(:
|
194
|
+
it "should log a retryable response 2 times" do
|
195
|
+
expect(subject).to have_received(:log_retryable_response).with(any_args).twice
|
195
196
|
end
|
196
197
|
|
197
198
|
it "should make three total requests" do
|
@@ -213,24 +214,43 @@ describe LogStash::Outputs::Http do
|
|
213
214
|
TestApp.last_request = nil
|
214
215
|
end
|
215
216
|
|
216
|
-
|
217
|
-
subject.multi_receive([event])
|
218
|
-
end
|
217
|
+
let(:events) { [event] }
|
219
218
|
|
220
|
-
|
221
|
-
|
222
|
-
|
219
|
+
describe "with a good code" do
|
220
|
+
before do
|
221
|
+
subject.multi_receive(events)
|
222
|
+
end
|
223
223
|
|
224
|
-
|
225
|
-
|
226
|
-
|
224
|
+
let(:last_request) { TestApp.last_request }
|
225
|
+
let(:body) { last_request.body.read }
|
226
|
+
let(:content_type) { last_request.env["CONTENT_TYPE"] }
|
227
|
+
|
228
|
+
it "should receive the request" do
|
229
|
+
expect(last_request).to be_truthy
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should receive the event as a hash" do
|
233
|
+
expect(body).to eql(expected_body)
|
234
|
+
end
|
227
235
|
|
228
|
-
|
229
|
-
|
236
|
+
it "should have the correct content type" do
|
237
|
+
expect(content_type).to eql(expected_content_type)
|
238
|
+
end
|
230
239
|
end
|
231
240
|
|
232
|
-
|
233
|
-
|
241
|
+
describe "a retryable code" do
|
242
|
+
let(:url) { "http://localhost:#{port}/retry" }
|
243
|
+
|
244
|
+
before do
|
245
|
+
TestApp.retry_fail_count=2
|
246
|
+
allow(subject).to receive(:send_event).and_call_original
|
247
|
+
allow(subject).to receive(:log_retryable_response)
|
248
|
+
subject.multi_receive(events)
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should retry" do
|
252
|
+
expect(subject).to have_received(:log_retryable_response).with(any_args).twice
|
253
|
+
end
|
234
254
|
end
|
235
255
|
end
|
236
256
|
|
@@ -257,6 +277,19 @@ describe LogStash::Outputs::Http do
|
|
257
277
|
include_examples("a received event")
|
258
278
|
end
|
259
279
|
|
280
|
+
describe "sending the batch as JSON" do
|
281
|
+
let(:config) do
|
282
|
+
base_config.merge({"url" => url, "http_method" => "post", "format" => "json_batch"})
|
283
|
+
end
|
284
|
+
|
285
|
+
let(:expected_body) { ::LogStash::Json.dump events }
|
286
|
+
let(:events) { [::LogStash::Event.new("a" => 1), ::LogStash::Event.new("b" => 2)]}
|
287
|
+
let(:expected_content_type) { "application/json" }
|
288
|
+
|
289
|
+
include_examples("a received event")
|
290
|
+
|
291
|
+
end
|
292
|
+
|
260
293
|
describe "sending the event as a form" do
|
261
294
|
let(:config) {
|
262
295
|
base_config.merge({"url" => url, "http_method" => "post", "pool_max" => 1, "format" => "form"})
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-output-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0
|
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-
|
11
|
+
date: 2018-01-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|