logstash-input-http_poller 3.0.3 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a540e3224516716a40ccbad3b6c0006a689d0c8
4
- data.tar.gz: 6771a22df2b09883e6e853add0c86c669289108c
3
+ metadata.gz: fe8e760b955fa42eefe9e32efb1d22a45a5df599
4
+ data.tar.gz: 78892043c7636c6ae2390f0a0434049f2c0746a7
5
5
  SHA512:
6
- metadata.gz: ee59e72aee1dad65d3df850cf2eb9bbada57562c7207d1e0c3695b2a2f6e1d7a7a895061e86bc554e072e29d9da5060e0374633818e27dbcfc284c8b36f20551
7
- data.tar.gz: c46f4edcef1d326cdcf88c8b7ffddbd6b088244a76c4b09884f23ea13cee9201e7c523482ffc5555e9244b358440fea43def47b8c6ec9712e2af319db704018b
6
+ metadata.gz: 981963c7a77ca4ee065efea7dce6cfcef8764e58cca1c168275da196bf9f8255ec34af2ad52fc9051d019faf7820628fb41c37744ee492107f46e9f20f818ae8
7
+ data.tar.gz: f1db89d4d1a1a44dd750c0348e95b95875844af1a815efb4f9f8bb8e56084d45aa119cd433fb83f0ab775df8e54313783dac51d0997d7c8a6ec1a6f544362fb4
data/CHANGELOG.md CHANGED
@@ -1,15 +1,24 @@
1
+ ## 3.1.0
2
+ - Use rufus-scheduler for more flexible scheduling. Many thanks to [@hummingV](https://github.com/hummingV) for this contribution. ([#58](https://github.com/logstash-plugins/logstash-input-http_poller/pull/58))
3
+
1
4
  ## 3.0.3
2
5
  - Require logstash-mixin-http_client 4.0.3 which fixes error messaging around key/trust-stores when no password supplied
6
+
3
7
  ## 3.0.2
4
8
  - Relax constraint on logstash-core-plugin-api to >= 1.60 <= 2.99
9
+
5
10
  ## 3.0.1
6
11
  - Republish all the gems under jruby.
12
+
7
13
  ## 3.0.0
8
14
  - Update the plugin to the version 2.0 of the plugin api, this change is required for Logstash 5.0 compatibility. See https://github.com/elastic/logstash/issues/5141
9
- # 2.0.5
15
+
16
+ ## 2.0.5
10
17
  - Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash
11
- # 2.0.4
18
+
19
+ ## 2.0.4
12
20
  - New dependency requirements for logstash-core for the 5.0 release
21
+
13
22
  ## 2.0.2
14
23
  - Bump http_client mixin to use better stale check for keepalives
15
24
 
@@ -4,6 +4,7 @@ require "logstash/namespace"
4
4
  require "logstash/plugin_mixins/http_client"
5
5
  require "socket" # for Socket.gethostname
6
6
  require "manticore"
7
+ require "rufus/scheduler"
7
8
 
8
9
  # This Logstash input plugin allows you to call an HTTP API, decode the output of it into event(s), and
9
10
  # send them on their merry way. The idea behind this plugins came from a need to read springboot
@@ -33,7 +34,8 @@ require "manticore"
33
34
  # }
34
35
  # }
35
36
  # request_timeout => 60
36
- # interval => 60
37
+ # # Supports "cron", "every", "at" and "in" schedules by rufus scheduler
38
+ # schedule => { cron => "* * * * * UTC"}
37
39
  # codec => "json"
38
40
  # # A hash of request metadata info (timing, response headers, etc.) will be sent here
39
41
  # metadata_target => "http_poller_metadata"
@@ -51,9 +53,10 @@ require "manticore"
51
53
  #
52
54
  # If you have a self signed cert you will need to convert your server's certificate to a valid# `.jks` or `.p12` file. An easy way to do it is to run the following one-liner, substituting your server's URL for the placeholder `MYURL` and `MYPORT`.
53
55
  #
54
- #....
56
+ # [source,ruby]
57
+ # ----------------------------------
55
58
  # openssl s_client -showcerts -connect MYURL:MYPORT </dev/null 2>/dev/null|openssl x509 -outform PEM > downloaded_cert.pem; keytool -import -alias test -file downloaded_cert.pem -keystore downloaded_truststore.jks
56
- #....
59
+ # ----------------------------------
57
60
  #
58
61
  # The above snippet will create two files `downloaded_cert.pem` and `downloaded_truststore.jks`. You will be prompted to set a password for the `jks` file during this process. To configure logstash use a config like the one that follows.
59
62
  #
@@ -70,9 +73,9 @@ require "manticore"
70
73
  # interval => 30
71
74
  # }
72
75
  #}
76
+ # ----------------------------------
73
77
  #
74
78
 
75
-
76
79
  class LogStash::Inputs::HTTP_Poller < LogStash::Inputs::Base
77
80
  include LogStash::PluginMixins::HttpClient
78
81
 
@@ -85,7 +88,20 @@ class LogStash::Inputs::HTTP_Poller < LogStash::Inputs::Base
85
88
  config :urls, :validate => :hash, :required => true
86
89
 
87
90
  # How often (in seconds) the urls will be called
88
- config :interval, :validate => :number, :required => true
91
+ # DEPRECATED. Use 'schedule' option instead.
92
+ # If both interval and schedule options are specified, interval
93
+ # option takes higher precedence
94
+ config :interval, :validate => :number, :deprecated => true
95
+
96
+ # Schedule of when to periodically poll from the urls
97
+ # Format: A hash with
98
+ # + key: "cron" | "every" | "in" | "at"
99
+ # + value: string
100
+ # Examples:
101
+ # a) { "every" => "1h" }
102
+ # b) { "cron" => "* * * * * UTC" }
103
+ # See: rufus/scheduler for details about different schedule options and value string format
104
+ config :schedule, :validate => :hash
89
105
 
90
106
  # Define the target field for placing the received data. If this setting is omitted, the data will be stored at the root (top level) of the event.
91
107
  config :target, :validate => :string
@@ -96,17 +112,19 @@ class LogStash::Inputs::HTTP_Poller < LogStash::Inputs::Base
96
112
  config :metadata_target, :validate => :string, :default => '@metadata'
97
113
 
98
114
  public
115
+ Schedule_types = %w(cron every at in)
99
116
  def register
100
117
  @host = Socket.gethostname.force_encoding(Encoding::UTF_8)
101
118
 
102
119
  @logger.info("Registering http_poller Input", :type => @type,
103
- :urls => @urls, :interval => @interval, :timeout => @timeout)
120
+ :urls => @urls, :interval => @interval, :schedule => @schedule, :timeout => @timeout)
104
121
 
105
122
  setup_requests!
106
123
  end
107
124
 
108
125
  def stop
109
126
  Stud.stop!(@interval_thread) if @interval_thread
127
+ @scheduler.stop if @scheduler
110
128
  end
111
129
 
112
130
  private
@@ -159,13 +177,46 @@ class LogStash::Inputs::HTTP_Poller < LogStash::Inputs::Base
159
177
 
160
178
  public
161
179
  def run(queue)
180
+ #interval or schedule must be provided. Must be exclusively either one. Not neither. Not both.
181
+ raise LogStash::ConfigurationError, "Invalid config. Neither interval nor schedule was specified." \
182
+ unless @interval || @schedule
183
+ raise LogStash::ConfigurationError, "Invalid config. Specify only interval or schedule. Not both." \
184
+ if @interval && @schedule
185
+
186
+ if @interval
187
+ setup_interval(queue)
188
+ elsif @schedule
189
+ setup_schedule(queue)
190
+ else
191
+ #should not reach here
192
+ raise LogStash::ConfigurationError, "Invalid config. Neither interval nor schedule was specified."
193
+ end
194
+ end
195
+
196
+ private
197
+ def setup_interval(queue)
162
198
  @interval_thread = Thread.current
163
199
  Stud.interval(@interval) do
164
200
  run_once(queue)
165
201
  end
166
202
  end
167
203
 
168
- private
204
+ def setup_schedule(queue)
205
+ #schedule hash must contain exactly one of the allowed keys
206
+ msg_invalid_schedule = "Invalid config. schedule hash must contain " +
207
+ "exactly one of the following keys - cron, at, every or in"
208
+ raise Logstash::ConfigurationError, msg_invalid_schedule if @schedule.keys.length !=1
209
+ schedule_type = @schedule.keys.first
210
+ schedule_value = @schedule[schedule_type]
211
+ raise LogStash::ConfigurationError, msg_invalid_schedule unless Schedule_types.include?(schedule_type)
212
+
213
+ @scheduler = Rufus::Scheduler.new(:max_work_threads => 1)
214
+ #as of v3.0.9, :first_in => :now doesn't work. Use the following workaround instead
215
+ opts = schedule_type == "every" ? { :first_in => 0.01 } : {}
216
+ @scheduler.send(schedule_type, schedule_value, opts) { run_once(queue) }
217
+ @scheduler.join
218
+ end
219
+
169
220
  def run_once(queue)
170
221
  @requests.each do |name, request|
171
222
  request_async(queue, name, request)
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-input-http_poller'
3
- s.version = '3.0.3'
3
+ s.version = '3.1.0'
4
4
  s.licenses = ['Apache License (2.0)']
5
5
  s.summary = "Poll HTTP endpoints with Logstash."
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"
@@ -22,8 +22,10 @@ Gem::Specification.new do |s|
22
22
  s.add_runtime_dependency 'logstash-codec-plain'
23
23
  s.add_runtime_dependency 'logstash-mixin-http_client', ">= 2.2.4", "< 5.0.0"
24
24
  s.add_runtime_dependency 'stud', "~> 0.0.22"
25
+ s.add_runtime_dependency 'rufus-scheduler', "~>3.0.9"
25
26
 
26
27
  s.add_development_dependency 'logstash-codec-json'
27
28
  s.add_development_dependency 'logstash-devutils'
28
29
  s.add_development_dependency 'flores'
30
+ s.add_development_dependency 'timecop'
29
31
  end
@@ -1,11 +1,14 @@
1
1
  require "logstash/devutils/rspec/spec_helper"
2
2
  require 'logstash/inputs/http_poller'
3
3
  require 'flores/random'
4
+ require "timecop"
4
5
 
5
6
  describe LogStash::Inputs::HTTP_Poller do
6
7
  let(:metadata_target) { "_http_poller_metadata" }
7
8
  let(:queue) { Queue.new }
8
- let(:default_interval) { 5 }
9
+ let(:default_schedule) {
10
+ { "cron" => "* * * * * UTC" }
11
+ }
9
12
  let(:default_name) { "url1 " }
10
13
  let(:default_url) { "http://localhost:1827" }
11
14
  let(:default_urls) {
@@ -15,7 +18,7 @@ describe LogStash::Inputs::HTTP_Poller do
15
18
  }
16
19
  let(:default_opts) {
17
20
  {
18
- "interval" => default_interval,
21
+ "schedule" => default_schedule,
19
22
  "urls" => default_urls,
20
23
  "codec" => "json",
21
24
  "metadata_target" => metadata_target
@@ -31,9 +34,13 @@ describe LogStash::Inputs::HTTP_Poller do
31
34
  end
32
35
 
33
36
  describe "#run" do
34
- it "should run at the specified interval" do
35
- expect(Stud).to receive(:interval).with(default_interval).once
36
- subject.run(double("queue"))
37
+ it "should setup a scheduler" do
38
+ runner = Thread.new do
39
+ subject.run(double("queue"))
40
+ expect(subject.instance_variable_get("@scheduler")).to be_a_kind_of(Rufus::Scheduler)
41
+ end
42
+ runner.kill
43
+ runner.join
37
44
  end
38
45
  end
39
46
 
@@ -151,6 +158,163 @@ describe LogStash::Inputs::HTTP_Poller do
151
158
  end
152
159
  end
153
160
 
161
+ describe "scheduler configuration" do
162
+ context "given an interval" do
163
+ let(:opts) {
164
+ {
165
+ "interval" => 2,
166
+ "urls" => default_urls,
167
+ "codec" => "json",
168
+ "metadata_target" => metadata_target
169
+ }
170
+ }
171
+ it "should run once in each interval" do
172
+ instance = klass.new(opts)
173
+ instance.register
174
+ queue = Queue.new
175
+ runner = Thread.new do
176
+ instance.run(queue)
177
+ end
178
+ #T 0123456
179
+ #events x x x x
180
+ #expects 3 events at T=5
181
+ sleep 5
182
+ instance.stop
183
+ runner.kill
184
+ runner.join
185
+ expect(queue.size).to eq(3)
186
+ end
187
+ end
188
+
189
+ context "given both interval and schedule options" do
190
+ let(:opts) {
191
+ {
192
+ "interval" => 1,
193
+ "schedule" => { "every" => "5s" },
194
+ "urls" => default_urls,
195
+ "codec" => "json",
196
+ "metadata_target" => metadata_target
197
+ }
198
+ }
199
+ it "should raise ConfigurationError" do
200
+ instance = klass.new(opts)
201
+ instance.register
202
+ queue = Queue.new
203
+ runner = Thread.new do
204
+ expect{instance.run(queue)}.to raise_error(LogStash::ConfigurationError)
205
+ end
206
+ instance.stop
207
+ runner.kill
208
+ runner.join
209
+ end
210
+ end
211
+
212
+ context "given 'cron' expression" do
213
+ let(:opts) {
214
+ {
215
+ "schedule" => { "cron" => "* * * * * UTC" },
216
+ "urls" => default_urls,
217
+ "codec" => "json",
218
+ "metadata_target" => metadata_target
219
+ }
220
+ }
221
+ it "should run at the schedule" do
222
+ instance = klass.new(opts)
223
+ instance.register
224
+ Timecop.travel(Time.new(2000,1,1,0,0,0,'+00:00'))
225
+ Timecop.scale(60)
226
+ queue = Queue.new
227
+ runner = Thread.new do
228
+ instance.run(queue)
229
+ end
230
+ sleep 3
231
+ instance.stop
232
+ runner.kill
233
+ runner.join
234
+ expect(queue.size).to eq(2)
235
+ Timecop.return
236
+ end
237
+ end
238
+
239
+ context "given 'at' expression" do
240
+ let(:opts) {
241
+ {
242
+ "schedule" => { "at" => "2000-01-01 00:05:00 +0000"},
243
+ "urls" => default_urls,
244
+ "codec" => "json",
245
+ "metadata_target" => metadata_target
246
+ }
247
+ }
248
+ it "should run at the schedule" do
249
+ instance = klass.new(opts)
250
+ instance.register
251
+ Timecop.travel(Time.new(2000,1,1,0,0,0,'+00:00'))
252
+ Timecop.scale(60 * 5)
253
+ queue = Queue.new
254
+ runner = Thread.new do
255
+ instance.run(queue)
256
+ end
257
+ sleep 2
258
+ instance.stop
259
+ runner.kill
260
+ runner.join
261
+ expect(queue.size).to eq(1)
262
+ Timecop.return
263
+ end
264
+ end
265
+
266
+ context "given 'every' expression" do
267
+ let(:opts) {
268
+ {
269
+ "schedule" => { "every" => "2s"},
270
+ "urls" => default_urls,
271
+ "codec" => "json",
272
+ "metadata_target" => metadata_target
273
+ }
274
+ }
275
+ it "should run at the schedule" do
276
+ instance = klass.new(opts)
277
+ instance.register
278
+ queue = Queue.new
279
+ runner = Thread.new do
280
+ instance.run(queue)
281
+ end
282
+ #T 0123456
283
+ #events x x x x
284
+ #expects 3 events at T=5
285
+ sleep 5
286
+ instance.stop
287
+ runner.kill
288
+ runner.join
289
+ expect(queue.size).to eq(3)
290
+ end
291
+ end
292
+
293
+ context "given 'in' expression" do
294
+ let(:opts) {
295
+ {
296
+ "schedule" => { "in" => "2s"},
297
+ "urls" => default_urls,
298
+ "codec" => "json",
299
+ "metadata_target" => metadata_target
300
+ }
301
+ }
302
+ it "should run at the schedule" do
303
+ instance = klass.new(opts)
304
+ instance.register
305
+ queue = Queue.new
306
+ runner = Thread.new do
307
+ instance.run(queue)
308
+ end
309
+ sleep 3
310
+ instance.stop
311
+ runner.kill
312
+ runner.join
313
+ expect(queue.size).to eq(1)
314
+ end
315
+ end
316
+ end
317
+
154
318
  describe "events" do
155
319
  shared_examples("matching metadata") {
156
320
  let(:metadata) { event.get(metadata_target) }
@@ -292,7 +456,9 @@ describe LogStash::Inputs::HTTP_Poller do
292
456
  }
293
457
  let(:opts) {
294
458
  {
295
- "interval" => default_interval,
459
+ "schedule" => {
460
+ "cron" => "* * * * * UTC"
461
+ },
296
462
  "urls" => {
297
463
  default_name => url
298
464
  },
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-http_poller
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-07-21 00:00:00.000000000 Z
12
+ date: 2016-08-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  requirement: !ruby/object:Gem::Requirement
@@ -79,6 +79,20 @@ dependencies:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: 0.0.22
82
+ - !ruby/object:Gem::Dependency
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: 3.0.9
88
+ name: rufus-scheduler
89
+ prerelease: false
90
+ type: :runtime
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 3.0.9
82
96
  - !ruby/object:Gem::Dependency
83
97
  requirement: !ruby/object:Gem::Requirement
84
98
  requirements:
@@ -121,6 +135,20 @@ dependencies:
121
135
  - - ">="
122
136
  - !ruby/object:Gem::Version
123
137
  version: '0'
138
+ - !ruby/object:Gem::Dependency
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ name: timecop
145
+ prerelease: false
146
+ type: :development
147
+ version_requirements: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
124
152
  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
125
153
  email: info@elastic.co
126
154
  executables: []