logstash-output-http 5.0.1 → 5.1.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 +3 -0
- data/docs/index.asciidoc +10 -0
- data/lib/logstash/outputs/http.rb +20 -0
- data/logstash-output-http.gemspec +1 -1
- data/spec/outputs/http_spec.rb +32 -18
- data/spec/supports/compressed_requests.rb +38 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed1975dd9a23d8a355ca14ccd0d191d387620356
|
4
|
+
data.tar.gz: d4ce66fe7f7c0b4e5396f819a70aeb62292be625
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d393ce2604784a67dcdedd1196650054cc32e246e16fb13fc93638941fbf6f0dffad804a758b9b99bd87ebefa16ed194b3e5558c52bf92b403c54af1fc72cd70
|
7
|
+
data.tar.gz: 70237b74bcdbeaeb2a0bd482f07189faf3c3f9dedda59226ca29086f9967eb7cf93dab8caecfb10e47093b508ca9aa8d2fc5013fec3f3b84feadca79dec6cabb
|
data/CHANGELOG.md
CHANGED
data/docs/index.asciidoc
CHANGED
@@ -48,6 +48,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
|
|
48
48
|
| <<plugins-{type}s-{plugin}-follow_redirects>> |<<boolean,boolean>>|No
|
49
49
|
| <<plugins-{type}s-{plugin}-format>> |<<string,string>>, one of `["json", "form", "message"]`|No
|
50
50
|
| <<plugins-{type}s-{plugin}-headers>> |<<hash,hash>>|No
|
51
|
+
| <<plugins-{type}s-{plugin}-http_compression>> |<<boolean,boolean>>|No
|
51
52
|
| <<plugins-{type}s-{plugin}-http_method>> |<<string,string>>, one of `["put", "post", "patch", "delete", "get", "head"]`|Yes
|
52
53
|
| <<plugins-{type}s-{plugin}-ignorable_codes>> |<<number,number>>|No
|
53
54
|
| <<plugins-{type}s-{plugin}-keepalive>> |<<boolean,boolean>>|No
|
@@ -172,6 +173,15 @@ Otherwise, the event is sent as json.
|
|
172
173
|
Custom headers to use
|
173
174
|
format is `headers => ["X-My-Header", "%{host}"]`
|
174
175
|
|
176
|
+
[id="plugins-{type}s-{plugin}-http_compression"]
|
177
|
+
===== `http_compression`
|
178
|
+
|
179
|
+
* Value type is <<boolean,boolean>>
|
180
|
+
* Default value is `false`
|
181
|
+
|
182
|
+
Enable request compression support. With this enabled the plugin will compress
|
183
|
+
http requests using gzip.
|
184
|
+
|
175
185
|
[id="plugins-{type}s-{plugin}-http_method"]
|
176
186
|
===== `http_method`
|
177
187
|
|
@@ -4,6 +4,7 @@ require "logstash/namespace"
|
|
4
4
|
require "logstash/json"
|
5
5
|
require "uri"
|
6
6
|
require "logstash/plugin_mixins/http_client"
|
7
|
+
require "zlib"
|
7
8
|
|
8
9
|
class LogStash::Outputs::Http < LogStash::Outputs::Base
|
9
10
|
include LogStash::PluginMixins::HttpClient
|
@@ -80,6 +81,9 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
80
81
|
# Otherwise, the event is sent as json.
|
81
82
|
config :format, :validate => ["json", "form", "message"], :default => "json"
|
82
83
|
|
84
|
+
# Set this to true if you want to enable gzip compression for your http requests
|
85
|
+
config :http_compression, :validate => :boolean, :default => false
|
86
|
+
|
83
87
|
config :message, :validate => :string
|
84
88
|
|
85
89
|
def register
|
@@ -196,6 +200,12 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
196
200
|
url = event.sprintf(@url)
|
197
201
|
headers = event_headers(event)
|
198
202
|
|
203
|
+
# Compress the body and add appropriate header
|
204
|
+
if @http_compression == true
|
205
|
+
headers["Content-Encoding"] = "gzip"
|
206
|
+
body = gzip(body)
|
207
|
+
end
|
208
|
+
|
199
209
|
# Create an async request
|
200
210
|
request = client.background.send(@http_method, url, :body => body, :headers => headers)
|
201
211
|
|
@@ -300,6 +310,16 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
|
|
300
310
|
end
|
301
311
|
end
|
302
312
|
|
313
|
+
# gzip data
|
314
|
+
def gzip(data)
|
315
|
+
gz = StringIO.new
|
316
|
+
gz.set_encoding("BINARY")
|
317
|
+
z = Zlib::GzipWriter.new(gz)
|
318
|
+
z.write(data)
|
319
|
+
z.close
|
320
|
+
gz.string
|
321
|
+
end
|
322
|
+
|
303
323
|
def convert_mapping(mapping, event)
|
304
324
|
if mapping.is_a?(Hash)
|
305
325
|
mapping.reduce({}) do |acc, kv|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-output-http'
|
3
|
-
s.version = '5.0
|
3
|
+
s.version = '5.1.0'
|
4
4
|
s.licenses = ['Apache License (2.0)']
|
5
5
|
s.summary = "This output lets you `PUT` or `POST` events to a generic HTTP(S) 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
@@ -3,6 +3,7 @@ require "logstash/outputs/http"
|
|
3
3
|
require "logstash/codecs/plain"
|
4
4
|
require "thread"
|
5
5
|
require "sinatra"
|
6
|
+
require_relative "../supports/compressed_requests"
|
6
7
|
|
7
8
|
PORT = rand(65535-1024) + 1025
|
8
9
|
|
@@ -16,8 +17,10 @@ end
|
|
16
17
|
#
|
17
18
|
# == Sinatra (v1.4.6) has taken the stage on 51572 for development with backup from WEBrick
|
18
19
|
# == Sinatra has ended his set (crowd applauds)
|
19
|
-
|
20
|
+
#
|
20
21
|
class TestApp < Sinatra::Base
|
22
|
+
# on the fly uncompress gzip content
|
23
|
+
use CompressedRequests
|
21
24
|
|
22
25
|
# disable WEBrick logging
|
23
26
|
def self.server_settings
|
@@ -38,11 +41,11 @@ class TestApp < Sinatra::Base
|
|
38
41
|
def self.last_request
|
39
42
|
@last_request
|
40
43
|
end
|
41
|
-
|
44
|
+
|
42
45
|
def self.retry_fail_count=(count)
|
43
46
|
@retry_fail_count = count
|
44
47
|
end
|
45
|
-
|
48
|
+
|
46
49
|
def self.retry_fail_count()
|
47
50
|
@retry_fail_count
|
48
51
|
end
|
@@ -56,10 +59,10 @@ class TestApp < Sinatra::Base
|
|
56
59
|
self.class.last_request = request
|
57
60
|
[400, "YUP"]
|
58
61
|
end
|
59
|
-
|
62
|
+
|
60
63
|
multiroute(%w(get post put patch delete), "/retry") do
|
61
64
|
self.class.last_request = request
|
62
|
-
|
65
|
+
|
63
66
|
if self.class.retry_fail_count > 0
|
64
67
|
self.class.retry_fail_count -= 1
|
65
68
|
[429, "Will succeed in #{self.class.retry_fail_count}"]
|
@@ -80,7 +83,7 @@ RSpec.configure do |config|
|
|
80
83
|
app.run!(opts) do |server|
|
81
84
|
queue.push("started")
|
82
85
|
end
|
83
|
-
rescue => e
|
86
|
+
rescue => e
|
84
87
|
puts "Error in webserver thread #{e}"
|
85
88
|
# ignore
|
86
89
|
end
|
@@ -158,7 +161,7 @@ describe LogStash::Outputs::Http do
|
|
158
161
|
expect(subject).to have_received(:log_failure).with(any_args)
|
159
162
|
end
|
160
163
|
end
|
161
|
-
|
164
|
+
|
162
165
|
context "with ignorable failing requests" do
|
163
166
|
let(:url) { "http://localhost:#{port}/bad"}
|
164
167
|
let(:verb_behavior_config) { super.merge("ignorable_codes" => [400]) }
|
@@ -171,7 +174,7 @@ describe LogStash::Outputs::Http do
|
|
171
174
|
expect(subject).not_to have_received(:log_failure).with(any_args)
|
172
175
|
end
|
173
176
|
end
|
174
|
-
|
177
|
+
|
175
178
|
context "with retryable failing requests" do
|
176
179
|
let(:url) { "http://localhost:#{port}/retry"}
|
177
180
|
|
@@ -184,12 +187,12 @@ describe LogStash::Outputs::Http do
|
|
184
187
|
it "should log a failure 2 times" do
|
185
188
|
expect(subject).to have_received(:log_failure).with(any_args).twice
|
186
189
|
end
|
187
|
-
|
190
|
+
|
188
191
|
it "should make three total requests" do
|
189
192
|
expect(subject).to have_received(:send_event).exactly(3).times
|
190
193
|
end
|
191
|
-
end
|
192
|
-
|
194
|
+
end
|
195
|
+
|
193
196
|
end
|
194
197
|
end
|
195
198
|
|
@@ -225,7 +228,8 @@ describe LogStash::Outputs::Http do
|
|
225
228
|
end
|
226
229
|
end
|
227
230
|
|
228
|
-
|
231
|
+
shared_examples "integration tests" do
|
232
|
+
let(:base_config) { {} }
|
229
233
|
let(:url) { "http://localhost:#{port}/good" }
|
230
234
|
let(:event) {
|
231
235
|
LogStash::Event.new("foo" => "bar", "baz" => "bot", "user" => "McBest")
|
@@ -239,7 +243,7 @@ describe LogStash::Outputs::Http do
|
|
239
243
|
|
240
244
|
describe "sending with the default (JSON) config" do
|
241
245
|
let(:config) {
|
242
|
-
{"url" => url, "http_method" => "post", "pool_max" => 1}
|
246
|
+
base_config.merge({"url" => url, "http_method" => "post", "pool_max" => 1})
|
243
247
|
}
|
244
248
|
let(:expected_body) { LogStash::Json.dump(event) }
|
245
249
|
let(:expected_content_type) { "application/json" }
|
@@ -249,7 +253,7 @@ describe LogStash::Outputs::Http do
|
|
249
253
|
|
250
254
|
describe "sending the event as a form" do
|
251
255
|
let(:config) {
|
252
|
-
{"url" => url, "http_method" => "post", "pool_max" => 1, "format" => "form"}
|
256
|
+
base_config.merge({"url" => url, "http_method" => "post", "pool_max" => 1, "format" => "form"})
|
253
257
|
}
|
254
258
|
let(:expected_body) { subject.send(:encode, event.to_hash) }
|
255
259
|
let(:expected_content_type) { "application/x-www-form-urlencoded" }
|
@@ -259,7 +263,7 @@ describe LogStash::Outputs::Http do
|
|
259
263
|
|
260
264
|
describe "sending the event as a message" do
|
261
265
|
let(:config) {
|
262
|
-
{"url" => url, "http_method" => "post", "pool_max" => 1, "format" => "message", "message" => "%{foo} AND %{baz}"}
|
266
|
+
base_config.merge({"url" => url, "http_method" => "post", "pool_max" => 1, "format" => "message", "message" => "%{foo} AND %{baz}"})
|
263
267
|
}
|
264
268
|
let(:expected_body) { "#{event.get("foo")} AND #{event.get("baz")}" }
|
265
269
|
let(:expected_content_type) { "text/plain" }
|
@@ -269,7 +273,7 @@ describe LogStash::Outputs::Http do
|
|
269
273
|
|
270
274
|
describe "sending a mapped event" do
|
271
275
|
let(:config) {
|
272
|
-
{"url" => url, "http_method" => "post", "pool_max" => 1, "mapping" => {"blah" => "X %{foo}"} }
|
276
|
+
base_config.merge({"url" => url, "http_method" => "post", "pool_max" => 1, "mapping" => {"blah" => "X %{foo}"} })
|
273
277
|
}
|
274
278
|
let(:expected_body) { LogStash::Json.dump("blah" => "X #{event.get("foo")}") }
|
275
279
|
let(:expected_content_type) { "application/json" }
|
@@ -279,7 +283,7 @@ describe LogStash::Outputs::Http do
|
|
279
283
|
|
280
284
|
describe "sending a mapped, nested event" do
|
281
285
|
let(:config) {
|
282
|
-
{
|
286
|
+
base_config.merge({
|
283
287
|
"url" => url,
|
284
288
|
"http_method" => "post",
|
285
289
|
"pool_max" => 1,
|
@@ -292,7 +296,7 @@ describe LogStash::Outputs::Http do
|
|
292
296
|
"user" => "Z %{user}"
|
293
297
|
}]
|
294
298
|
}
|
295
|
-
}
|
299
|
+
})
|
296
300
|
}
|
297
301
|
let(:expected_body) {
|
298
302
|
LogStash::Json.dump({
|
@@ -310,4 +314,14 @@ describe LogStash::Outputs::Http do
|
|
310
314
|
include_examples("a received event")
|
311
315
|
end
|
312
316
|
end
|
317
|
+
|
318
|
+
describe "integration test without gzip compression" do
|
319
|
+
include_examples("integration tests")
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "integration test with gzip compression" do
|
323
|
+
include_examples("integration tests") do
|
324
|
+
let(:base_config) { { "http_compression" => true } }
|
325
|
+
end
|
326
|
+
end
|
313
327
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# based on relistan's rack handler
|
4
|
+
# out of the box rack only gives use the rack deflater handler to return compressed
|
5
|
+
# response, this gist offer the inverse and should work on all rack based app like sinatra or rails.
|
6
|
+
#
|
7
|
+
# original source: https://gist.github.com/relistan/2109707
|
8
|
+
require "zlib"
|
9
|
+
|
10
|
+
class CompressedRequests
|
11
|
+
def initialize(app)
|
12
|
+
@app = app
|
13
|
+
end
|
14
|
+
|
15
|
+
def encoding_handled?(env)
|
16
|
+
['gzip', 'deflate'].include? env['HTTP_CONTENT_ENCODING']
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
if encoding_handled?(env)
|
21
|
+
extracted = decode(env['rack.input'], env['HTTP_CONTENT_ENCODING'])
|
22
|
+
|
23
|
+
env.delete('HTTP_CONTENT_ENCODING')
|
24
|
+
env['CONTENT_LENGTH'] = extracted.bytesize
|
25
|
+
env['rack.input'] = StringIO.new(extracted)
|
26
|
+
end
|
27
|
+
|
28
|
+
status, headers, response = @app.call(env)
|
29
|
+
return [status, headers, response]
|
30
|
+
end
|
31
|
+
|
32
|
+
def decode(input, content_encoding)
|
33
|
+
case content_encoding
|
34
|
+
when 'gzip' then Zlib::GzipReader.new(input).read
|
35
|
+
when 'deflate' then Zlib::Inflate.inflate(input.read)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
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.0
|
4
|
+
version: 5.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +108,7 @@ files:
|
|
108
108
|
- lib/logstash/outputs/http.rb
|
109
109
|
- logstash-output-http.gemspec
|
110
110
|
- spec/outputs/http_spec.rb
|
111
|
+
- spec/supports/compressed_requests.rb
|
111
112
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
112
113
|
licenses:
|
113
114
|
- Apache License (2.0)
|
@@ -136,3 +137,4 @@ specification_version: 4
|
|
136
137
|
summary: This output lets you `PUT` or `POST` events to a generic HTTP(S) endpoint
|
137
138
|
test_files:
|
138
139
|
- spec/outputs/http_spec.rb
|
140
|
+
- spec/supports/compressed_requests.rb
|