logstash-filter-rest 0.2.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2af5930ffb298925b7a340afd929ac9c85559f4f
4
- data.tar.gz: 57e160ff830adbc6b63d22968e4f20047b1779a3
3
+ metadata.gz: 4fac99e78c6f1c75edbbf92e74fede3862dca591
4
+ data.tar.gz: d7ccae6caf784862a5f998ff48116cf96b44030a
5
5
  SHA512:
6
- metadata.gz: bedafb7870ae6c5d0fc22c81f4fcedd5b1384d6524afd8394da949502f6af8ce9d551615fa73751e112db6e44acfb51b90854874ac4199f0cc3cf53e55a7951a
7
- data.tar.gz: cb947ea8b5cbd4f666afcb297f2e45cc2f8bf5655db1f16b66de7a7a649eefc01332fb6e3156076b92ada1986d9e469027c5a8552f1880ab0a69be55f86efc1e
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 [![Build Status](https://travis-ci.org/gandalfb/logstash-filter-rest.svg?branch=http-keep-alive)](https://travis-ci.org/gandalfb/logstash-filter-rest)
1
+ # Logstash REST Filter [![Build Status](https://travis-ci.org/gandalfb/logstash-filter-rest.svg?branch=version%2Flogstash-5)](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" # string (required, with field reference: "http://example.com?id=%{id}" or params, if defined)
34
- method => "post" # string (optional, default = "get")
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 => { # hash (optional, available for method => "get" and "post"; if post it will be transformed into body hash and posted as json)
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}" # Please set sprintf to true if you want to use field references
46
+ "key3" => "%{somefield}" # sprintf is used implicitly
47
47
  }
48
48
  }
49
- json => true # boolean (optional, default = false)
50
- sprintf => true # boolean (optional, default = false, set this to true if you want to use field references in url, header or params)
51
- target => "my_key" # string (optional, default = "rest_response")
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 => { # hash (optional)
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}" # Please set sprintf to true if you want to use field references
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
- # Defines the field, where the parsed response is written to
70
- # if set to '' it will be written to event root
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, :default => 'rest'
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).freeze
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 request_http(request)
159
- @logger.debug? && @logger.debug('Fetching URL', :request => request)
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
- event = add_to_event(parsed, event)
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 = add_to_event(@fallback, 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
- request = @request.dup
194
- request[2][:params] = sprint(@sprintf, @request[2][:params], event) if request[2].key?(:params)
195
- request[2][:body] = sprint(@sprintf, @request[2][:body], event) if request[2].key?(:body)
196
- request[1] = sprint(@sprintf, @request[1], event)
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
- event = process_response(body, event)
201
- @logger.debug? && @logger.debug('Sucess received', :code => code, :body => body)
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', :code => code, :body => body)
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
- event = add_to_event(@fallback, event)
209
- @logger.debug? && @logger.debug('Setting fallback', :fallback => @fallback)
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.2.1'
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/**/*','spec/**/*','vendor/**/*','*.gemspec','*.md','CONTRIBUTORS','Gemfile','LICENSE','NOTICE.TXT']
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.6.0', '< 3.0.0'
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', '~> 0'
26
- s.add_development_dependency 'pry', '~> 0'
32
+ s.add_development_dependency 'logstash-devutils', '>= 0', '< 2.0.0'
27
33
  end
@@ -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 "Set to Rest Filter Get without params" do
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 => "http://jsonplaceholder.typicode.com/users/10"
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("message" => "some text") do
19
+ sample('message' => 'some text') do
19
20
  expect(subject).to include('rest')
20
- expect(subject['rest']).to include("id")
21
- expect(subject['rest']['id']).to eq(10)
22
- expect(subject['rest']).to_not include("fallback")
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 "Set to Rest Filter Get without params custom target" do
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 => "http://jsonplaceholder.typicode.com/users/10"
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("message" => "some text") do
40
+ sample('message' => 'some text') do
40
41
  expect(subject).to include('testing')
41
- expect(subject['testing']).to include("id")
42
- expect(subject['testing']['id']).to eq(10)
43
- expect(subject['testing']).to_not include("fallback")
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 "Set to Rest Filter Get without params and sprintf" do
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("message" => "10") do
62
+ sample('message' => '10') do
61
63
  expect(subject).to include('rest')
62
- expect(subject['rest']).to include("id")
63
- expect(subject['rest']['id']).to eq(10)
64
- expect(subject['rest']).to_not include("fallback")
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("message" => "9") do
68
+ sample('message' => '9') do
67
69
  expect(subject).to include('rest')
68
- expect(subject['rest']).to include("id")
69
- expect(subject['rest']['id']).to eq(9)
70
- expect(subject['rest']).to_not include("fallback")
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 "Set to Rest Filter Get without params http error" do
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 => "http://httpstat.us/404"
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("message" => "some text") do
89
+ sample('message' => 'some text') do
87
90
  expect(subject).to_not include('rest')
88
- expect(subject['tags']).to include('_restfailure')
91
+ expect(subject.get('tags')).to include('_restfailure')
89
92
  end
90
93
  end
91
- describe "Set to Rest Filter Get with params" do
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 => "https://jsonplaceholder.typicode.com/posts"
99
+ url => 'https://jsonplaceholder.typicode.com/posts'
97
100
  params => {
98
101
  userId => 10
99
102
  }
100
103
  headers => {
101
- "Content-Type" => "application/json"
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("message" => "some text") do
114
+ sample('message' => 'some text') do
111
115
  expect(subject).to include('rest')
112
- expect(subject['rest'][0]).to include("userId")
113
- expect(subject['rest'][0]['userId']).to eq(10)
114
- expect(subject['rest']).to_not include("fallback")
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 "Set to Rest Filter Get with params sprintf" do
121
+ describe 'empty response' do
118
122
  let(:config) do <<-CONFIG
119
123
  filter {
120
124
  rest {
121
125
  request => {
122
- url => "https://jsonplaceholder.typicode.com/posts"
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
- "Content-Type" => "application/json"
156
+ 'Content-Type' => 'application/json'
128
157
  }
129
158
  }
130
159
  json => true
131
- sprintf => true
160
+ target => 'rest'
132
161
  }
133
162
  }
134
163
  CONFIG
135
164
  end
136
165
 
137
- sample("message" => "10") do
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['rest'][0]).to include("userId")
146
- expect(subject['rest'][0]['userId']).to eq(9)
147
- expect(subject['rest']).to_not include("fallback")
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 "Set to Rest Filter Post with params" do
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 => "https://jsonplaceholder.typicode.com/posts"
156
- method => "post"
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
- "Content-Type" => "application/json"
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("message" => "some text") do
198
+ sample('message' => 'some text') do
173
199
  expect(subject).to include('rest')
174
- expect(subject['rest']).to include("id")
175
- expect(subject['rest']['userId']).to eq(42)
176
- expect(subject['rest']).to_not include("fallback")
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 "Set to Rest Filter Post with params sprintf" do
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 => "https://jsonplaceholder.typicode.com/posts"
185
- method => "post"
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
- "Content-Type" => "application/json"
218
+ 'Content-Type' => 'application/json'
193
219
  }
194
220
  }
195
221
  json => true
196
- sprintf => true
222
+ target => 'rest'
197
223
  }
198
224
  }
199
225
  CONFIG
200
226
  end
201
227
 
202
- sample("message" => "42") do
228
+ sample('message' => '42') do
203
229
  expect(subject).to include('rest')
204
- expect(subject['rest']).to include("id")
205
- expect(subject['rest']['userId']).to eq(42)
206
- expect(subject['rest']).to_not include("fallback")
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 "Fallback" do
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 => "http://jsonplaceholder.typicode.com/users/0"
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
- fallback => {
218
- "fallback1" => true
219
- "fallback2" => true
220
- }
252
+ target => 'rest'
221
253
  }
222
254
  }
223
255
  CONFIG
224
256
  end
225
257
 
226
- sample("message" => "some text") do
258
+ sample('message' => '42') do
227
259
  expect(subject).to include('rest')
228
- expect(subject['rest']).to include("fallback1")
229
- expect(subject['rest']).to include("fallback2")
230
- expect(subject['rest']).to_not include("id")
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 "Fallback empty target" do
265
+ describe 'fallback' do
234
266
  let(:config) do <<-CONFIG
235
267
  filter {
236
268
  rest {
237
269
  request => {
238
- url => "http://jsonplaceholder.typicode.com/users/0"
270
+ url => 'http://jsonplaceholder.typicode.com/users/0'
239
271
  }
240
272
  json => true
241
- target => ''
242
273
  fallback => {
243
- "fallback1" => true
244
- "fallback2" => true
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("message" => "some text") do
252
- expect(subject).to_not include('rest')
253
- expect(subject).to include("fallback1")
254
- expect(subject).to include("fallback2")
255
- expect(subject).to_not include("id")
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 "Empty target" do
290
+ describe 'empty target exception' do
259
291
  let(:config) do <<-CONFIG
260
292
  filter {
261
293
  rest {
262
294
  request => {
263
- url => "http://jsonplaceholder.typicode.com/users/1"
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
- sample("message" => "some text") do
273
- expect(subject).to include("id")
274
- expect(subject).to_not include("fallback")
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.2.1
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-08-21 00:00:00.000000000 Z
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.6.0
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: 3.0.0
43
- name: logstash-codec-json
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.6.0
51
- - - "<"
30
+ version: '1.60'
31
+ - - "<="
52
32
  - !ruby/object:Gem::Version
53
- version: 3.0.0
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
- name: pry
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: '0'
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
@@ -1,2 +0,0 @@
1
- require 'logstash/devutils/rspec/spec_helper'
2
- require 'pry'