logstash-filter-rest 0.2.1 → 0.5.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 +10 -0
- data/README.md +33 -9
- data/lib/logstash/filters/rest.rb +111 -50
- data/logstash-filter-rest.gemspec +12 -6
- data/spec/filters/rest_spec.rb +144 -90
- metadata +17 -46
- data/spec/spec_helper.rb +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4fac99e78c6f1c75edbbf92e74fede3862dca591
|
4
|
+
data.tar.gz: d7ccae6caf784862a5f998ff48116cf96b44030a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b49a566196685abb817a20f4438f9fedcf14a33bb8c82a9a766ed0bdb91e7cbeeb9f18746e4eba277fbce034ad798c32361bf6e54e7bfd1c4ccfebb2eb891ad7
|
7
|
+
data.tar.gz: 15d9d11fb62f6bda9b4d67e70e753eb5b0e2a447f054213bcc8e9831a06b5358ffc635ea57e5988cc05fd8760bebcecace6bba7a5c9412d773a83aaed666d20f
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
## 0.5.0
|
2
|
+
- Relax constraint on logstash-core-plugin-api to >= 1.60 <= 2.99
|
3
|
+
- Require devutils >= 0 to make `bundler` update the package
|
4
|
+
- Use Event API for LS-5
|
5
|
+
- Implicit `sprintf`, deprecating the setting
|
6
|
+
- `target` is now required, dropping support to write into top-level in favor of only using new Event API
|
7
|
+
- this follows other logstash-plugins like `logstash-filter-json`
|
8
|
+
- if the response is empty, add the restfailure tags
|
9
|
+
- Some logging moved before code
|
10
|
+
- Testcases adapted to new behavior with error check
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Logstash REST Filter [](https://travis-ci.org/gandalfb/logstash-filter-rest)
|
2
2
|
|
3
3
|
This is a filter plugin for [Logstash](https://github.com/elasticsearch/logstash).
|
4
4
|
|
@@ -30,8 +30,8 @@ Add the following inside the filter section of your logstash configuration:
|
|
30
30
|
filter {
|
31
31
|
rest {
|
32
32
|
request => {
|
33
|
-
url => "http://example.com"
|
34
|
-
method => "post"
|
33
|
+
url => "http://example.com" # string (required, with field reference: "http://example.com?id=%{id}" or params, if defined)
|
34
|
+
method => "post" # string (optional, default = "get")
|
35
35
|
headers => { # hash (optional)
|
36
36
|
"key1" => "value1"
|
37
37
|
"key2" => "value2"
|
@@ -40,16 +40,15 @@ filter {
|
|
40
40
|
user => "AzureDiamond"
|
41
41
|
password => "hunter2"
|
42
42
|
}
|
43
|
-
params => {
|
43
|
+
params => { # hash (optional, available for method => "get" and "post"; if post it will be transformed into body hash and posted as json)
|
44
44
|
"key1" => "value1"
|
45
45
|
"key2" => "value2"
|
46
|
-
"key3" => "%{somefield}"
|
46
|
+
"key3" => "%{somefield}" # sprintf is used implicitly
|
47
47
|
}
|
48
48
|
}
|
49
|
-
json => true
|
50
|
-
|
51
|
-
|
52
|
-
fallback => { # hash describing a default in case of error
|
49
|
+
json => true # boolean (optional, default = true)
|
50
|
+
target => "my_key" # string (mandatory, no default)
|
51
|
+
fallback => { # hash describing a default in case of error
|
53
52
|
"key1" => "value1"
|
54
53
|
"key2" => "value2"
|
55
54
|
}
|
@@ -57,6 +56,31 @@ filter {
|
|
57
56
|
}
|
58
57
|
```
|
59
58
|
|
59
|
+
Print plugin version:
|
60
|
+
|
61
|
+
``` bash
|
62
|
+
bin/logstash-plugin list --verbose | grep rest
|
63
|
+
```
|
64
|
+
|
65
|
+
Examples for running logstash from `cli`:
|
66
|
+
|
67
|
+
``` bash
|
68
|
+
bin/logstash --debug -e 'input { stdin{} } filter { rest { request => { url => "https://jsonplaceholder.typicode.com/posts" method => "post" params => { "userId" => "%{message}" } headers => { "Content-Type" => "application/json" } } target => 'rest' } } output {stdout { codec => rubydebug }}'
|
69
|
+
```
|
70
|
+
|
71
|
+
``` bash
|
72
|
+
bin/logstash --debug -e 'input { stdin{} } filter { rest { request => { url => "https://jsonplaceholder.typicode.com/posts" method => "post" body => { "userId" => "%{message}" } headers => { "Content-Type" => "application/json" } } target => 'rest' } } output {stdout { codec => rubydebug }}'
|
73
|
+
```
|
74
|
+
|
75
|
+
``` bash
|
76
|
+
bin/logstash --debug -e 'input { stdin{} } filter { rest { request => { url => "http://jsonplaceholder.typicode.com/users/%{message}" } target => 'rest' } } output {stdout { codec => rubydebug }}'
|
77
|
+
```
|
78
|
+
|
79
|
+
``` bash
|
80
|
+
bin/logstash --debug -e 'input { stdin{} } filter { rest { request => { url => "https://jsonplaceholder.typicode.com/posts" method => "get" params => { "userId" => "%{message}" } headers => { "Content-Type" => "application/json" } } target => 'rest' } } output {stdout { codec => rubydebug }}'
|
81
|
+
```
|
82
|
+
|
83
|
+
|
60
84
|
## Contributing
|
61
85
|
|
62
86
|
All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.
|
@@ -4,6 +4,36 @@ require 'logstash/namespace'
|
|
4
4
|
require 'logstash/plugin_mixins/http_client'
|
5
5
|
require 'logstash/json'
|
6
6
|
|
7
|
+
# Monkey Patch hsh with a recursive compact and deep freeze
|
8
|
+
class Hash
|
9
|
+
def compact
|
10
|
+
delete_if { |_k, v| v.respond_to?(:each) ? v.compact.empty? : v.nil? }
|
11
|
+
end
|
12
|
+
|
13
|
+
def deep_freeze
|
14
|
+
each { |_k, v| v.deep_freeze if v.respond_to? :deep_freeze }
|
15
|
+
freeze
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Monkey Patch string to parse to hsh
|
20
|
+
class String
|
21
|
+
def to_object(symbolize = true)
|
22
|
+
LogStash::Json.load(
|
23
|
+
gsub(/:([a-zA-z]+)/, '"\\1"').gsub('=>', ': '),
|
24
|
+
:symbolize_keys => symbolize
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Monkey Patch Array with deep freeze
|
30
|
+
class Array
|
31
|
+
def deep_freeze
|
32
|
+
each { |j| j.deep_freeze if j.respond_to? :deep_freeze }
|
33
|
+
freeze
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
7
37
|
# Logstash REST Filter
|
8
38
|
# This filter calls a defined URL and saves the answer into a specified field.
|
9
39
|
#
|
@@ -22,7 +52,7 @@ class LogStash::Filters::Rest < LogStash::Filters::Base
|
|
22
52
|
# request => {
|
23
53
|
# url => "http://example.com" # string (required, with field reference: "http://example.com?id=%{id}" or params, if defined)
|
24
54
|
# method => "post" # string (optional, default = "get")
|
25
|
-
# headers => {
|
55
|
+
# headers => { # hash (optional)
|
26
56
|
# "key1" => "value1"
|
27
57
|
# "key2" => "value2"
|
28
58
|
# }
|
@@ -33,9 +63,10 @@ class LogStash::Filters::Rest < LogStash::Filters::Base
|
|
33
63
|
# params => { # hash (optional, available for method => "get" and "post"; if post it will be transformed into body hash and posted as json)
|
34
64
|
# "key1" => "value1"
|
35
65
|
# "key2" => "value2"
|
36
|
-
# "key3" => "%{somefield}" #
|
66
|
+
# "key3" => "%{somefield}" # Field references are found implicitly on startup
|
37
67
|
# }
|
38
68
|
# }
|
69
|
+
# target => "doc"
|
39
70
|
# }
|
40
71
|
# }
|
41
72
|
#
|
@@ -48,7 +79,6 @@ class LogStash::Filters::Rest < LogStash::Filters::Base
|
|
48
79
|
# [source,ruby]
|
49
80
|
# filter {
|
50
81
|
# rest {
|
51
|
-
# request => { .. }
|
52
82
|
# json => true
|
53
83
|
# }
|
54
84
|
# }
|
@@ -64,22 +94,24 @@ class LogStash::Filters::Rest < LogStash::Filters::Base
|
|
64
94
|
# sprintf => true
|
65
95
|
# }
|
66
96
|
# }
|
67
|
-
config :sprintf, :validate => :boolean, :default => false
|
97
|
+
config :sprintf, :validate => :boolean, :default => false, :deprecated => true
|
68
98
|
|
69
|
-
#
|
70
|
-
#
|
99
|
+
# Define the target field for placing the response data. This setting is
|
100
|
+
# required and may not be omitted. It is not possible to place the response
|
101
|
+
# into the event top-level.
|
71
102
|
#
|
72
103
|
# For example, if you want the data to be put in the `doc` field:
|
73
104
|
# [source,ruby]
|
74
105
|
# filter {
|
75
106
|
# rest {
|
76
|
-
# request => { .. }
|
77
107
|
# target => "doc"
|
78
108
|
# }
|
79
109
|
# }
|
80
110
|
#
|
111
|
+
# Rest response will be expanded into a data structure in the `target` field.
|
112
|
+
#
|
81
113
|
# NOTE: if the `target` field already exists, it will be overwritten!
|
82
|
-
config :target, :validate => :string, :
|
114
|
+
config :target, :validate => :string, :required => true
|
83
115
|
|
84
116
|
# If set, any error like json parsing or invalid http response
|
85
117
|
# will result in this hash to be added to target instead of error tags
|
@@ -88,7 +120,6 @@ class LogStash::Filters::Rest < LogStash::Filters::Base
|
|
88
120
|
# [source,ruby]
|
89
121
|
# filter {
|
90
122
|
# rest {
|
91
|
-
# request => { .. }
|
92
123
|
# fallback => {
|
93
124
|
# 'key1' => 'value1'
|
94
125
|
# 'key2' => 'value2'
|
@@ -106,11 +137,25 @@ class LogStash::Filters::Rest < LogStash::Filters::Base
|
|
106
137
|
public
|
107
138
|
|
108
139
|
def register
|
109
|
-
@request = normalize_request(@request)
|
140
|
+
@request = normalize_request(@request)
|
141
|
+
@sprintf_fields = find_sprintf(
|
142
|
+
Marshal.load(Marshal.dump(@request))
|
143
|
+
).deep_freeze
|
144
|
+
@target = normalize_target(@target)
|
110
145
|
end # def register
|
111
146
|
|
112
147
|
private
|
113
148
|
|
149
|
+
def normalize_target(target)
|
150
|
+
# make sure @target is in the format [field name] if defined,
|
151
|
+
# i.e. not empty and surrounded by brakets
|
152
|
+
raise LogStash::ConfigurationError, 'target config string is empty, please set a valid field name' if target.empty?
|
153
|
+
target = "[#{target}]" if target && target !~ /^\[[^\[\]]+\]$/
|
154
|
+
target
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
114
159
|
def normalize_request(url_or_spec)
|
115
160
|
if url_or_spec.is_a?(String)
|
116
161
|
res = [:get, url_or_spec]
|
@@ -123,12 +168,12 @@ class LogStash::Filters::Rest < LogStash::Filters::Base
|
|
123
168
|
url = spec.delete(:url)
|
124
169
|
|
125
170
|
# if it is a post and json, it is used as body string, not params
|
126
|
-
spec[:body] = spec.delete(:params) if method == :post
|
171
|
+
spec[:body] = spec.delete(:params) if method == :post && spec[:params]
|
127
172
|
|
128
173
|
# We need these strings to be keywords!
|
129
174
|
spec[:auth] = { user: spec[:auth]['user'], pass: spec[:auth]['password'] } if spec[:auth]
|
130
175
|
|
131
|
-
res = [method, url, spec]
|
176
|
+
res = [method.freeze, url, spec]
|
132
177
|
else
|
133
178
|
raise LogStash::ConfigurationError, "Invalid URL or request spec: '#{url_or_spec}', expected a String or Hash!"
|
134
179
|
end
|
@@ -155,10 +200,27 @@ class LogStash::Filters::Rest < LogStash::Filters::Base
|
|
155
200
|
|
156
201
|
private
|
157
202
|
|
158
|
-
def
|
159
|
-
|
203
|
+
def find_sprintf(config)
|
204
|
+
field_matcher = /%\{[^}]+\}/
|
205
|
+
if config.is_a?(Hash)
|
206
|
+
config.keep_if do |_k, v|
|
207
|
+
find_sprintf(v)
|
208
|
+
end.compact
|
209
|
+
elsif config.is_a?(Array)
|
210
|
+
config.keep_if do |v|
|
211
|
+
find_sprintf(v)
|
212
|
+
end.compact
|
213
|
+
elsif config.is_a?(String) && config =~ field_matcher
|
214
|
+
config
|
215
|
+
end
|
216
|
+
end
|
160
217
|
|
218
|
+
private
|
219
|
+
|
220
|
+
def request_http(request)
|
161
221
|
request[2][:body] = LogStash::Json.dump(request[2][:body]) if request[2].key?(:body)
|
222
|
+
@logger.debug? && @logger.debug('Fetching request',
|
223
|
+
:request => request)
|
162
224
|
|
163
225
|
method, url, *request_opts = request
|
164
226
|
response = client.http(method, url, *request_opts)
|
@@ -171,65 +233,64 @@ class LogStash::Filters::Rest < LogStash::Filters::Base
|
|
171
233
|
if @json
|
172
234
|
begin
|
173
235
|
parsed = LogStash::Json.load(response)
|
174
|
-
|
236
|
+
if parsed.empty?
|
237
|
+
@logger.warn('rest response empty',
|
238
|
+
:response => response, :event => event)
|
239
|
+
@tag_on_rest_failure.each { |tag| event.tag(tag) }
|
240
|
+
else
|
241
|
+
event.set(@target, parsed)
|
242
|
+
end
|
175
243
|
rescue
|
176
244
|
if @fallback.empty?
|
245
|
+
@logger.warn('JSON parsing error',
|
246
|
+
:response => response, :event => event)
|
177
247
|
@tag_on_json_failure.each { |tag| event.tag(tag) }
|
178
|
-
@logger.warn('JSON parsing error', :response => response, :event => event)
|
179
248
|
else
|
180
|
-
event
|
249
|
+
event.set(@target, @fallback)
|
181
250
|
end
|
182
251
|
end
|
183
252
|
else
|
184
253
|
event.set(@target, response.strip)
|
185
254
|
end
|
186
|
-
event
|
187
255
|
end
|
188
256
|
|
189
257
|
public
|
190
258
|
|
191
259
|
def filter(event)
|
192
260
|
return unless filter?(event)
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
261
|
+
@logger.debug? && @logger.debug('Parsing event fields',
|
262
|
+
:sprintf_fields => @sprintf_fields)
|
263
|
+
parsed_request_fields = event.sprintf(@sprintf_fields).to_object
|
264
|
+
parsed_request_fields.each do |v|
|
265
|
+
case v
|
266
|
+
when Hash
|
267
|
+
@request[2].merge!(v)
|
268
|
+
when String
|
269
|
+
@request[1] = v
|
270
|
+
end
|
271
|
+
end
|
272
|
+
@logger.debug? && @logger.debug('Parsed request',
|
273
|
+
:request => @request)
|
197
274
|
|
198
|
-
code, body = request_http(request)
|
275
|
+
code, body = request_http(@request)
|
199
276
|
if code.between?(200, 299)
|
200
|
-
|
201
|
-
|
277
|
+
@logger.debug? && @logger.debug('Sucess received',
|
278
|
+
:code => code, :body => body)
|
279
|
+
process_response(body, event)
|
202
280
|
else
|
203
|
-
@logger.debug? && @logger.debug('Http error received',
|
281
|
+
@logger.debug? && @logger.debug('Http error received',
|
282
|
+
:code => code, :body => body)
|
204
283
|
if @fallback.empty?
|
284
|
+
@logger.error('Error in Rest filter',
|
285
|
+
:request => @request, :json => @json,
|
286
|
+
:code => code, :body => body)
|
205
287
|
@tag_on_rest_failure.each { |tag| event.tag(tag) }
|
206
|
-
@logger.error('Error in Rest filter', :request => request, :json => @json, :code => code, :body => body)
|
207
288
|
else
|
208
|
-
|
209
|
-
|
289
|
+
@logger.debug? && @logger.debug('Setting fallback',
|
290
|
+
:fallback => @fallback)
|
291
|
+
event.set(@target, @fallback)
|
210
292
|
end
|
211
293
|
end
|
212
294
|
filter_matched(event)
|
213
295
|
end # def filter
|
214
|
-
|
215
|
-
private
|
216
|
-
|
217
|
-
def sprint(sprintf, hash, event)
|
218
|
-
return hash unless sprintf
|
219
|
-
return event.sprintf(hash) unless hash.is_a?(Hash)
|
220
|
-
result = {}
|
221
|
-
hash.each { |k, v| result[k] = event.sprintf(v) }
|
222
|
-
result
|
223
|
-
end
|
224
|
-
|
225
|
-
private
|
226
|
-
|
227
|
-
def add_to_event(to_add, event)
|
228
|
-
if @target.empty?
|
229
|
-
to_add.each { |k, v| event[k] = v }
|
230
|
-
else
|
231
|
-
event[@target] = to_add
|
232
|
-
end
|
233
|
-
event
|
234
|
-
end
|
235
296
|
end # class LogStash::Filters::Rest
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'logstash-filter-rest'
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '0.5.0'
|
4
4
|
s.licenses = ['Apache License (2.0)']
|
5
5
|
s.summary = 'This filter requests data from a RESTful Web Service.'
|
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/plugin install gemname. This gem is not a stand-alone program'
|
@@ -10,7 +10,15 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.require_paths = ['lib']
|
11
11
|
|
12
12
|
# Files
|
13
|
-
s.files = Dir['lib/**/*',
|
13
|
+
s.files = Dir['lib/**/*',
|
14
|
+
'spec/**/*',
|
15
|
+
'vendor/**/*',
|
16
|
+
'*.gemspec',
|
17
|
+
'*.md',
|
18
|
+
'CONTRIBUTORS',
|
19
|
+
'Gemfile',
|
20
|
+
'LICENSE',
|
21
|
+
'NOTICE.TXT']
|
14
22
|
# Tests
|
15
23
|
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
16
24
|
|
@@ -18,10 +26,8 @@ Gem::Specification.new do |s|
|
|
18
26
|
s.metadata = { 'logstash_plugin' => 'true', 'logstash_group' => 'filter' }
|
19
27
|
|
20
28
|
# Gem dependencies
|
21
|
-
s.add_runtime_dependency 'logstash-core', '>= 1.
|
22
|
-
s.add_runtime_dependency 'logstash-codec-json', '>= 1.6.0', '< 3.0.0'
|
29
|
+
s.add_runtime_dependency 'logstash-core-plugin-api', '>= 1.60', '<= 2.99'
|
23
30
|
s.add_runtime_dependency 'logstash-mixin-http_client', '>= 2.2.4', '< 5.0.0'
|
24
31
|
|
25
|
-
s.add_development_dependency 'logstash-devutils', '
|
26
|
-
s.add_development_dependency 'pry', '~> 0'
|
32
|
+
s.add_development_dependency 'logstash-devutils', '>= 0', '< 2.0.0'
|
27
33
|
end
|
data/spec/filters/rest_spec.rb
CHANGED
@@ -1,33 +1,34 @@
|
|
1
|
-
require 'spec_helper'
|
1
|
+
require 'logstash/devutils/rspec/spec_helper'
|
2
2
|
require 'logstash/filters/rest'
|
3
3
|
|
4
4
|
describe LogStash::Filters::Rest do
|
5
|
-
describe
|
5
|
+
describe 'Set to Rest Filter Get without params' do
|
6
6
|
let(:config) do <<-CONFIG
|
7
7
|
filter {
|
8
8
|
rest {
|
9
9
|
request => {
|
10
|
-
url =>
|
10
|
+
url => 'http://jsonplaceholder.typicode.com/users/10'
|
11
11
|
}
|
12
12
|
json => true
|
13
|
+
target => 'rest'
|
13
14
|
}
|
14
15
|
}
|
15
16
|
CONFIG
|
16
17
|
end
|
17
18
|
|
18
|
-
sample(
|
19
|
+
sample('message' => 'some text') do
|
19
20
|
expect(subject).to include('rest')
|
20
|
-
expect(subject
|
21
|
-
expect(subject[
|
22
|
-
expect(subject
|
21
|
+
expect(subject.get('rest')).to include('id')
|
22
|
+
expect(subject.get('[rest][id]')).to eq(10)
|
23
|
+
expect(subject.get('rest')).to_not include('fallback')
|
23
24
|
end
|
24
25
|
end
|
25
|
-
describe
|
26
|
+
describe 'Set to Rest Filter Get without params custom target' do
|
26
27
|
let(:config) do <<-CONFIG
|
27
28
|
filter {
|
28
29
|
rest {
|
29
30
|
request => {
|
30
|
-
url =>
|
31
|
+
url => 'http://jsonplaceholder.typicode.com/users/10'
|
31
32
|
}
|
32
33
|
json => true
|
33
34
|
target => 'testing'
|
@@ -36,14 +37,14 @@ describe LogStash::Filters::Rest do
|
|
36
37
|
CONFIG
|
37
38
|
end
|
38
39
|
|
39
|
-
sample(
|
40
|
+
sample('message' => 'some text') do
|
40
41
|
expect(subject).to include('testing')
|
41
|
-
expect(subject
|
42
|
-
expect(subject[
|
43
|
-
expect(subject
|
42
|
+
expect(subject.get('testing')).to include('id')
|
43
|
+
expect(subject.get('[testing][id]')).to eq(10)
|
44
|
+
expect(subject.get('testing')).to_not include('fallback')
|
44
45
|
end
|
45
46
|
end
|
46
|
-
describe
|
47
|
+
describe 'Set to Rest Filter Get without params and sprintf' do
|
47
48
|
let(:config) do <<-CONFIG
|
48
49
|
filter {
|
49
50
|
rest {
|
@@ -52,226 +53,279 @@ describe LogStash::Filters::Rest do
|
|
52
53
|
}
|
53
54
|
json => true
|
54
55
|
sprintf => true
|
56
|
+
target => 'rest'
|
55
57
|
}
|
56
58
|
}
|
57
59
|
CONFIG
|
58
60
|
end
|
59
61
|
|
60
|
-
sample(
|
62
|
+
sample('message' => '10') do
|
61
63
|
expect(subject).to include('rest')
|
62
|
-
expect(subject
|
63
|
-
expect(subject[
|
64
|
-
expect(subject
|
64
|
+
expect(subject.get('rest')).to include('id')
|
65
|
+
expect(subject.get('[rest][id]')).to eq(10)
|
66
|
+
expect(subject.get('rest')).to_not include('fallback')
|
65
67
|
end
|
66
|
-
sample(
|
68
|
+
sample('message' => '9') do
|
67
69
|
expect(subject).to include('rest')
|
68
|
-
expect(subject
|
69
|
-
expect(subject[
|
70
|
-
expect(subject
|
70
|
+
expect(subject.get('rest')).to include('id')
|
71
|
+
expect(subject.get('[rest][id]')).to eq(9)
|
72
|
+
expect(subject.get('rest')).to_not include('fallback')
|
71
73
|
end
|
72
74
|
end
|
73
|
-
describe
|
75
|
+
describe 'Set to Rest Filter Get without params http error' do
|
74
76
|
let(:config) do <<-CONFIG
|
75
77
|
filter {
|
76
78
|
rest {
|
77
79
|
request => {
|
78
|
-
url =>
|
80
|
+
url => 'http://httpstat.us/404'
|
79
81
|
}
|
80
82
|
json => true
|
83
|
+
target => 'rest'
|
81
84
|
}
|
82
85
|
}
|
83
86
|
CONFIG
|
84
87
|
end
|
85
88
|
|
86
|
-
sample(
|
89
|
+
sample('message' => 'some text') do
|
87
90
|
expect(subject).to_not include('rest')
|
88
|
-
expect(subject
|
91
|
+
expect(subject.get('tags')).to include('_restfailure')
|
89
92
|
end
|
90
93
|
end
|
91
|
-
describe
|
94
|
+
describe 'Set to Rest Filter Get with params' do
|
92
95
|
let(:config) do <<-CONFIG
|
93
96
|
filter {
|
94
97
|
rest {
|
95
98
|
request => {
|
96
|
-
url =>
|
99
|
+
url => 'https://jsonplaceholder.typicode.com/posts'
|
97
100
|
params => {
|
98
101
|
userId => 10
|
99
102
|
}
|
100
103
|
headers => {
|
101
|
-
|
104
|
+
'Content-Type' => 'application/json'
|
102
105
|
}
|
103
106
|
}
|
104
107
|
json => true
|
108
|
+
target => 'rest'
|
105
109
|
}
|
106
110
|
}
|
107
111
|
CONFIG
|
108
112
|
end
|
109
113
|
|
110
|
-
sample(
|
114
|
+
sample('message' => 'some text') do
|
111
115
|
expect(subject).to include('rest')
|
112
|
-
expect(subject[
|
113
|
-
expect(subject[
|
114
|
-
expect(subject
|
116
|
+
expect(subject.get('[rest][0]')).to include('userId')
|
117
|
+
expect(subject.get('[rest][0][userId]')).to eq(10)
|
118
|
+
expect(subject.get('rest')).to_not include('fallback')
|
115
119
|
end
|
116
120
|
end
|
117
|
-
describe
|
121
|
+
describe 'empty response' do
|
118
122
|
let(:config) do <<-CONFIG
|
119
123
|
filter {
|
120
124
|
rest {
|
121
125
|
request => {
|
122
|
-
url =>
|
126
|
+
url => 'https://jsonplaceholder.typicode.com/posts'
|
127
|
+
params => {
|
128
|
+
userId => 0
|
129
|
+
}
|
130
|
+
headers => {
|
131
|
+
'Content-Type' => 'application/json'
|
132
|
+
}
|
133
|
+
}
|
134
|
+
target => 'rest'
|
135
|
+
}
|
136
|
+
}
|
137
|
+
CONFIG
|
138
|
+
end
|
139
|
+
|
140
|
+
sample('message' => 'some text') do
|
141
|
+
expect(subject).to_not include('rest')
|
142
|
+
expect(subject.get('tags')).to include('_restfailure')
|
143
|
+
end
|
144
|
+
end
|
145
|
+
describe 'Set to Rest Filter Get with params sprintf' do
|
146
|
+
let(:config) do <<-CONFIG
|
147
|
+
filter {
|
148
|
+
rest {
|
149
|
+
request => {
|
150
|
+
url => 'https://jsonplaceholder.typicode.com/posts'
|
123
151
|
params => {
|
124
152
|
userId => "%{message}"
|
153
|
+
id => "%{message}"
|
125
154
|
}
|
126
155
|
headers => {
|
127
|
-
|
156
|
+
'Content-Type' => 'application/json'
|
128
157
|
}
|
129
158
|
}
|
130
159
|
json => true
|
131
|
-
|
160
|
+
target => 'rest'
|
132
161
|
}
|
133
162
|
}
|
134
163
|
CONFIG
|
135
164
|
end
|
136
165
|
|
137
|
-
sample(
|
138
|
-
expect(subject).to include('rest')
|
139
|
-
expect(subject['rest'][0]).to include("userId")
|
140
|
-
expect(subject['rest'][0]['userId']).to eq(10)
|
141
|
-
expect(subject['rest']).to_not include("fallback")
|
142
|
-
end
|
143
|
-
sample("message" => "9") do
|
166
|
+
sample('message' => '1') do
|
144
167
|
expect(subject).to include('rest')
|
145
|
-
expect(subject[
|
146
|
-
expect(subject[
|
147
|
-
expect(subject[
|
168
|
+
expect(subject.get('[rest][0]')).to include('userId')
|
169
|
+
expect(subject.get('[rest][0][userId]')).to eq(1)
|
170
|
+
expect(subject.get('[rest][0][id]')).to eq(1)
|
171
|
+
expect(subject.get('rest').length).to eq(1)
|
172
|
+
expect(subject.get('rest')).to_not include('fallback')
|
148
173
|
end
|
149
174
|
end
|
150
|
-
describe
|
175
|
+
describe 'Set to Rest Filter Post with params' do
|
151
176
|
let(:config) do <<-CONFIG
|
152
177
|
filter {
|
153
178
|
rest {
|
154
179
|
request => {
|
155
|
-
url =>
|
156
|
-
method =>
|
180
|
+
url => 'https://jsonplaceholder.typicode.com/posts'
|
181
|
+
method => 'post'
|
157
182
|
params => {
|
158
183
|
title => 'foo'
|
159
184
|
body => 'bar'
|
160
185
|
userId => 42
|
161
186
|
}
|
162
187
|
headers => {
|
163
|
-
|
188
|
+
'Content-Type' => 'application/json'
|
164
189
|
}
|
165
190
|
}
|
166
191
|
json => true
|
192
|
+
target => 'rest'
|
167
193
|
}
|
168
194
|
}
|
169
195
|
CONFIG
|
170
196
|
end
|
171
197
|
|
172
|
-
sample(
|
198
|
+
sample('message' => 'some text') do
|
173
199
|
expect(subject).to include('rest')
|
174
|
-
expect(subject
|
175
|
-
expect(subject[
|
176
|
-
expect(subject
|
200
|
+
expect(subject.get('rest')).to include('id')
|
201
|
+
expect(subject.get('[rest][userId]')).to eq(42)
|
202
|
+
expect(subject.get('rest')).to_not include('fallback')
|
177
203
|
end
|
178
204
|
end
|
179
|
-
describe
|
205
|
+
describe 'Set to Rest Filter Post with params sprintf' do
|
180
206
|
let(:config) do <<-CONFIG
|
181
207
|
filter {
|
182
208
|
rest {
|
183
209
|
request => {
|
184
|
-
url =>
|
185
|
-
method =>
|
210
|
+
url => 'https://jsonplaceholder.typicode.com/posts'
|
211
|
+
method => 'post'
|
186
212
|
params => {
|
187
213
|
title => 'foo'
|
188
214
|
body => 'bar'
|
189
215
|
userId => "%{message}"
|
190
216
|
}
|
191
217
|
headers => {
|
192
|
-
|
218
|
+
'Content-Type' => 'application/json'
|
193
219
|
}
|
194
220
|
}
|
195
221
|
json => true
|
196
|
-
|
222
|
+
target => 'rest'
|
197
223
|
}
|
198
224
|
}
|
199
225
|
CONFIG
|
200
226
|
end
|
201
227
|
|
202
|
-
sample(
|
228
|
+
sample('message' => '42') do
|
203
229
|
expect(subject).to include('rest')
|
204
|
-
expect(subject
|
205
|
-
expect(subject[
|
206
|
-
expect(subject
|
230
|
+
expect(subject.get('rest')).to include('id')
|
231
|
+
expect(subject.get('[rest][userId]')).to eq(42)
|
232
|
+
expect(subject.get('rest')).to_not include('fallback')
|
207
233
|
end
|
208
234
|
end
|
209
|
-
describe
|
235
|
+
describe 'Set to Rest Filter Post with body sprintf' do
|
210
236
|
let(:config) do <<-CONFIG
|
211
237
|
filter {
|
212
238
|
rest {
|
213
239
|
request => {
|
214
|
-
url =>
|
240
|
+
url => 'https://jsonplaceholder.typicode.com/posts'
|
241
|
+
method => 'post'
|
242
|
+
body => {
|
243
|
+
title => 'foo'
|
244
|
+
body => 'bar'
|
245
|
+
userId => "%{message}"
|
246
|
+
}
|
247
|
+
headers => {
|
248
|
+
'Content-Type' => 'application/json'
|
249
|
+
}
|
215
250
|
}
|
216
251
|
json => true
|
217
|
-
|
218
|
-
"fallback1" => true
|
219
|
-
"fallback2" => true
|
220
|
-
}
|
252
|
+
target => 'rest'
|
221
253
|
}
|
222
254
|
}
|
223
255
|
CONFIG
|
224
256
|
end
|
225
257
|
|
226
|
-
sample(
|
258
|
+
sample('message' => '42') do
|
227
259
|
expect(subject).to include('rest')
|
228
|
-
expect(subject
|
229
|
-
expect(subject[
|
230
|
-
expect(subject
|
260
|
+
expect(subject.get('rest')).to include('id')
|
261
|
+
expect(subject.get('[rest][userId]')).to eq(42)
|
262
|
+
expect(subject.get('rest')).to_not include('fallback')
|
231
263
|
end
|
232
264
|
end
|
233
|
-
describe
|
265
|
+
describe 'fallback' do
|
234
266
|
let(:config) do <<-CONFIG
|
235
267
|
filter {
|
236
268
|
rest {
|
237
269
|
request => {
|
238
|
-
url =>
|
270
|
+
url => 'http://jsonplaceholder.typicode.com/users/0'
|
239
271
|
}
|
240
272
|
json => true
|
241
|
-
target => ''
|
242
273
|
fallback => {
|
243
|
-
|
244
|
-
|
274
|
+
'fallback1' => true
|
275
|
+
'fallback2' => true
|
245
276
|
}
|
277
|
+
target => 'rest'
|
246
278
|
}
|
247
279
|
}
|
248
280
|
CONFIG
|
249
281
|
end
|
250
282
|
|
251
|
-
sample(
|
252
|
-
expect(subject).
|
253
|
-
expect(subject).to include(
|
254
|
-
expect(subject).to include(
|
255
|
-
expect(subject).to_not include(
|
283
|
+
sample('message' => 'some text') do
|
284
|
+
expect(subject).to include('rest')
|
285
|
+
expect(subject.get('rest')).to include('fallback1')
|
286
|
+
expect(subject.get('rest')).to include('fallback2')
|
287
|
+
expect(subject.get('rest')).to_not include('id')
|
256
288
|
end
|
257
289
|
end
|
258
|
-
describe
|
290
|
+
describe 'empty target exception' do
|
259
291
|
let(:config) do <<-CONFIG
|
260
292
|
filter {
|
261
293
|
rest {
|
262
294
|
request => {
|
263
|
-
url =>
|
295
|
+
url => 'http://jsonplaceholder.typicode.com/users/0'
|
264
296
|
}
|
265
297
|
json => true
|
298
|
+
fallback => {
|
299
|
+
'fallback1' => true
|
300
|
+
'fallback2' => true
|
301
|
+
}
|
266
302
|
target => ''
|
267
303
|
}
|
268
304
|
}
|
269
305
|
CONFIG
|
270
306
|
end
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
307
|
+
sample('message' => 'some text') do
|
308
|
+
expect { subject }.to raise_error(LogStash::ConfigurationError)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
describe 'missing target exception' do
|
312
|
+
let(:config) do <<-CONFIG
|
313
|
+
filter {
|
314
|
+
rest {
|
315
|
+
request => {
|
316
|
+
url => 'http://jsonplaceholder.typicode.com/users/0'
|
317
|
+
}
|
318
|
+
json => true
|
319
|
+
fallback => {
|
320
|
+
'fallback1' => true
|
321
|
+
'fallback2' => true
|
322
|
+
}
|
323
|
+
}
|
324
|
+
}
|
325
|
+
CONFIG
|
326
|
+
end
|
327
|
+
sample('message' => 'some text') do
|
328
|
+
expect { subject }.to raise_error(LogStash::ConfigurationError)
|
275
329
|
end
|
276
330
|
end
|
277
331
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-filter-rest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lucas Henning
|
@@ -9,48 +9,28 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-12-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
20
|
-
- - "
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 3.0.0
|
23
|
-
name: logstash-core
|
24
|
-
prerelease: false
|
25
|
-
type: :runtime
|
26
|
-
version_requirements: !ruby/object:Gem::Requirement
|
27
|
-
requirements:
|
28
|
-
- - ">="
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
version: 1.6.0
|
31
|
-
- - "<"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 3.0.0
|
34
|
-
- !ruby/object:Gem::Dependency
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - ">="
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: 1.6.0
|
40
|
-
- - "<"
|
19
|
+
version: '1.60'
|
20
|
+
- - "<="
|
41
21
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
43
|
-
name: logstash-
|
22
|
+
version: '2.99'
|
23
|
+
name: logstash-core-plugin-api
|
44
24
|
prerelease: false
|
45
25
|
type: :runtime
|
46
26
|
version_requirements: !ruby/object:Gem::Requirement
|
47
27
|
requirements:
|
48
28
|
- - ">="
|
49
29
|
- !ruby/object:Gem::Version
|
50
|
-
version: 1.
|
51
|
-
- - "
|
30
|
+
version: '1.60'
|
31
|
+
- - "<="
|
52
32
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
33
|
+
version: '2.99'
|
54
34
|
- !ruby/object:Gem::Dependency
|
55
35
|
requirement: !ruby/object:Gem::Requirement
|
56
36
|
requirements:
|
@@ -74,37 +54,30 @@ dependencies:
|
|
74
54
|
- !ruby/object:Gem::Dependency
|
75
55
|
requirement: !ruby/object:Gem::Requirement
|
76
56
|
requirements:
|
77
|
-
- - "
|
57
|
+
- - ">="
|
78
58
|
- !ruby/object:Gem::Version
|
79
59
|
version: '0'
|
60
|
+
- - "<"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.0.0
|
80
63
|
name: logstash-devutils
|
81
64
|
prerelease: false
|
82
65
|
type: :development
|
83
66
|
version_requirements: !ruby/object:Gem::Requirement
|
84
67
|
requirements:
|
85
|
-
- - "
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version: '0'
|
88
|
-
- !ruby/object:Gem::Dependency
|
89
|
-
requirement: !ruby/object:Gem::Requirement
|
90
|
-
requirements:
|
91
|
-
- - "~>"
|
68
|
+
- - ">="
|
92
69
|
- !ruby/object:Gem::Version
|
93
70
|
version: '0'
|
94
|
-
|
95
|
-
prerelease: false
|
96
|
-
type: :development
|
97
|
-
version_requirements: !ruby/object:Gem::Requirement
|
98
|
-
requirements:
|
99
|
-
- - "~>"
|
71
|
+
- - "<"
|
100
72
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
73
|
+
version: 2.0.0
|
102
74
|
description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program
|
103
75
|
email: mail@hurb.de
|
104
76
|
executables: []
|
105
77
|
extensions: []
|
106
78
|
extra_rdoc_files: []
|
107
79
|
files:
|
80
|
+
- CHANGELOG.md
|
108
81
|
- CONTRIBUTORS
|
109
82
|
- Gemfile
|
110
83
|
- LICENSE
|
@@ -112,7 +85,6 @@ files:
|
|
112
85
|
- lib/logstash/filters/rest.rb
|
113
86
|
- logstash-filter-rest.gemspec
|
114
87
|
- spec/filters/rest_spec.rb
|
115
|
-
- spec/spec_helper.rb
|
116
88
|
homepage: https://github.com/lucashenning/logstash-filter-rest/
|
117
89
|
licenses:
|
118
90
|
- Apache License (2.0)
|
@@ -141,4 +113,3 @@ specification_version: 4
|
|
141
113
|
summary: This filter requests data from a RESTful Web Service.
|
142
114
|
test_files:
|
143
115
|
- spec/filters/rest_spec.rb
|
144
|
-
- spec/spec_helper.rb
|
data/spec/spec_helper.rb
DELETED