logstash-input-http_poller 2.0.6 → 2.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: 10e023a2848c2a827b18e11fc0db42dd6d257d70
4
- data.tar.gz: a014c52d6aa4509e877f064c214ed8e5dac2e803
3
+ metadata.gz: 791035a6079e584fae5b891675e5e17225405a70
4
+ data.tar.gz: 8286793c8788fc5af3c0d90ee10f613d49933e25
5
5
  SHA512:
6
- metadata.gz: d85efa4810a99e15900b5387266c93ed81b58bdd11e0e89059bfb3aee2358524cc888ebcecef3c5bbf6151103004e46306482683d36d3ada0a68d618211ac1f0
7
- data.tar.gz: 822a8f6881d29c803dc7328188c25cedbb456230312cbf61e520913f8db32c30cac7ef532b6fa494637fcd741b9b5e22861600f06ff5012502f234350c0cee81
6
+ metadata.gz: 95894f281b1440dd9c07bdf4790a2bf3017791c9c1f038a14b735637cb7a9b28db992c4e30898f29b37bbd158b51bc61ed159ad2d7fdbf5d2b68a45fac8303c3
7
+ data.tar.gz: 2b93713dad3146739aaed0a0b7ba838381d8e7b46ef9fa9a2a217e83d40b063d9ce4a04221c9d5697542aab77960572e8bbe7274776a1d416d30b8035b0b0be7
data/README.md CHANGED
@@ -63,7 +63,12 @@ gem "logstash-filter-awesome", :path => "/your/local/logstash-filter-awesome"
63
63
  ```
64
64
  - Install plugin
65
65
  ```sh
66
+ # Logstash 2.3 and higher
67
+ bin/logstash-plugin install --no-verify
68
+
69
+ # Prior to Logstash 2.3
66
70
  bin/plugin install --no-verify
71
+
67
72
  ```
68
73
  - Run Logstash with your plugin
69
74
  ```sh
@@ -81,7 +86,12 @@ gem build logstash-filter-awesome.gemspec
81
86
  ```
82
87
  - Install the plugin from the Logstash home
83
88
  ```sh
84
- bin/plugin install /your/local/plugin/logstash-filter-awesome.gem
89
+ # Logstash 2.3 and higher
90
+ bin/logstash-plugin install --no-verify
91
+
92
+ # Prior to Logstash 2.3
93
+ bin/plugin install --no-verify
94
+
85
95
  ```
86
96
  - Start Logstash and proceed to test the plugin
87
97
 
@@ -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"
@@ -59,7 +61,20 @@ class LogStash::Inputs::HTTP_Poller < LogStash::Inputs::Base
59
61
  config :urls, :validate => :hash, :required => true
60
62
 
61
63
  # How often (in seconds) the urls will be called
62
- config :interval, :validate => :number, :required => true
64
+ # DEPRECATED. Use 'schedule' option instead.
65
+ # If both interval and schedule options are specified, interval
66
+ # option takes higher precedence
67
+ config :interval, :validate => :number, :deprecated => true
68
+
69
+ # Schedule of when to periodically poll from the urls
70
+ # Format: A hash with
71
+ # + key: "cron" | "every" | "in" | "at"
72
+ # + value: string
73
+ # Examples:
74
+ # a) { "every" => "1h" }
75
+ # b) { "cron" => "* * * * * UTC" }
76
+ # See: rufus/scheduler for details about different schedule options and value string format
77
+ config :schedule, :validate => :hash
63
78
 
64
79
  # 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.
65
80
  config :target, :validate => :string
@@ -70,17 +85,19 @@ class LogStash::Inputs::HTTP_Poller < LogStash::Inputs::Base
70
85
  config :metadata_target, :validate => :string, :default => '@metadata'
71
86
 
72
87
  public
88
+ Schedule_types = %w(cron every at in)
73
89
  def register
74
90
  @host = Socket.gethostname.force_encoding(Encoding::UTF_8)
75
91
 
76
92
  @logger.info("Registering http_poller Input", :type => @type,
77
- :urls => @urls, :interval => @interval, :timeout => @timeout)
93
+ :urls => @urls, :interval => @interval, :schedule => @schedule, :timeout => @timeout)
78
94
 
79
95
  setup_requests!
80
96
  end
81
97
 
82
98
  def stop
83
99
  Stud.stop!(@interval_thread) if @interval_thread
100
+ @scheduler.stop if @scheduler
84
101
  end
85
102
 
86
103
  private
@@ -133,13 +150,46 @@ class LogStash::Inputs::HTTP_Poller < LogStash::Inputs::Base
133
150
 
134
151
  public
135
152
  def run(queue)
153
+ #interval or schedule must be provided. Must be exclusively either one. Not neither. Not both.
154
+ raise LogStash::ConfigurationError, "Invalid config. Neither interval nor schedule was specified." \
155
+ unless @interval || @schedule
156
+ raise LogStash::ConfigurationError, "Invalid config. Specify only interval or schedule. Not both." \
157
+ if @interval && @schedule
158
+
159
+ if @interval
160
+ setup_interval(queue)
161
+ elsif @schedule
162
+ setup_schedule(queue)
163
+ else
164
+ #should not reach here
165
+ raise LogStash::ConfigurationError, "Invalid config. Neither interval nor schedule was specified."
166
+ end
167
+ end
168
+
169
+ private
170
+ def setup_interval(queue)
136
171
  @interval_thread = Thread.current
137
172
  Stud.interval(@interval) do
138
173
  run_once(queue)
139
174
  end
140
175
  end
141
176
 
142
- private
177
+ def setup_schedule(queue)
178
+ #schedule hash must contain exactly one of the allowed keys
179
+ msg_invalid_schedule = "Invalid config. schedule hash must contain " +
180
+ "exactly one of the following keys - cron, at, every or in"
181
+ raise Logstash::ConfigurationError, msg_invalid_schedule if @schedule.keys.length !=1
182
+ schedule_type = @schedule.keys.first
183
+ schedule_value = @schedule[schedule_type]
184
+ raise LogStash::ConfigurationError, msg_invalid_schedule unless Schedule_types.include?(schedule_type)
185
+
186
+ @scheduler = Rufus::Scheduler.new(:max_work_threads => 1)
187
+ #as of v3.0.9, :first_in => :now doesn't work. Use the following workaround instead
188
+ opts = schedule_type == "every" ? { :first_in => 0.01 } : {}
189
+ @scheduler.send(schedule_type, schedule_value, opts) { run_once(queue) }
190
+ @scheduler.join
191
+ end
192
+
143
193
  def run_once(queue)
144
194
  @requests.each do |name, request|
145
195
  request_async(queue, name, request)
@@ -1,9 +1,9 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-input-http_poller'
3
- s.version = '2.0.6'
3
+ s.version = '2.1.0'
4
4
  s.licenses = ['Apache License (2.0)']
5
5
  s.summary = "Poll HTTP endpoints with Logstash."
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."
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"
7
7
  s.authors = [ "Elastic", "andrewvc"]
8
8
  s.email = 'info@elastic.co'
9
9
  s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
@@ -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", "< 3.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[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: 2.0.6
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
@@ -9,113 +9,141 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-04-11 00:00:00.000000000 Z
12
+ date: 2016-09-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
15
20
  name: logstash-core-plugin-api
21
+ prerelease: false
22
+ type: :runtime
16
23
  version_requirements: !ruby/object:Gem::Requirement
17
24
  requirements:
18
- - - ~>
25
+ - - "~>"
19
26
  - !ruby/object:Gem::Version
20
27
  version: '1.0'
28
+ - !ruby/object:Gem::Dependency
21
29
  requirement: !ruby/object:Gem::Requirement
22
30
  requirements:
23
- - - ~>
31
+ - - ">="
24
32
  - !ruby/object:Gem::Version
25
- version: '1.0'
33
+ version: '0'
34
+ name: logstash-codec-plain
26
35
  prerelease: false
27
36
  type: :runtime
28
- - !ruby/object:Gem::Dependency
29
- name: logstash-codec-plain
30
37
  version_requirements: !ruby/object:Gem::Requirement
31
38
  requirements:
32
- - - '>='
39
+ - - ">="
33
40
  - !ruby/object:Gem::Version
34
41
  version: '0'
42
+ - !ruby/object:Gem::Dependency
35
43
  requirement: !ruby/object:Gem::Requirement
36
44
  requirements:
37
- - - '>='
45
+ - - ">="
38
46
  - !ruby/object:Gem::Version
39
- version: '0'
47
+ version: 2.2.4
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: 3.0.0
51
+ name: logstash-mixin-http_client
40
52
  prerelease: false
41
53
  type: :runtime
42
- - !ruby/object:Gem::Dependency
43
- name: logstash-mixin-http_client
44
54
  version_requirements: !ruby/object:Gem::Requirement
45
55
  requirements:
46
- - - '>='
56
+ - - ">="
47
57
  - !ruby/object:Gem::Version
48
58
  version: 2.2.4
49
- - - <
59
+ - - "<"
50
60
  - !ruby/object:Gem::Version
51
61
  version: 3.0.0
62
+ - !ruby/object:Gem::Dependency
52
63
  requirement: !ruby/object:Gem::Requirement
53
64
  requirements:
54
- - - '>='
55
- - !ruby/object:Gem::Version
56
- version: 2.2.4
57
- - - <
65
+ - - "~>"
58
66
  - !ruby/object:Gem::Version
59
- version: 3.0.0
67
+ version: 0.0.22
68
+ name: stud
60
69
  prerelease: false
61
70
  type: :runtime
62
- - !ruby/object:Gem::Dependency
63
- name: stud
64
71
  version_requirements: !ruby/object:Gem::Requirement
65
72
  requirements:
66
- - - ~>
73
+ - - "~>"
67
74
  - !ruby/object:Gem::Version
68
75
  version: 0.0.22
76
+ - !ruby/object:Gem::Dependency
69
77
  requirement: !ruby/object:Gem::Requirement
70
78
  requirements:
71
- - - ~>
79
+ - - "~>"
72
80
  - !ruby/object:Gem::Version
73
- version: 0.0.22
81
+ version: 3.0.9
82
+ name: rufus-scheduler
74
83
  prerelease: false
75
84
  type: :runtime
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 3.0.9
76
90
  - !ruby/object:Gem::Dependency
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
77
96
  name: logstash-codec-json
97
+ prerelease: false
98
+ type: :development
78
99
  version_requirements: !ruby/object:Gem::Requirement
79
100
  requirements:
80
- - - '>='
101
+ - - ">="
81
102
  - !ruby/object:Gem::Version
82
103
  version: '0'
104
+ - !ruby/object:Gem::Dependency
83
105
  requirement: !ruby/object:Gem::Requirement
84
106
  requirements:
85
- - - '>='
107
+ - - ">="
86
108
  - !ruby/object:Gem::Version
87
109
  version: '0'
110
+ name: logstash-devutils
88
111
  prerelease: false
89
112
  type: :development
90
- - !ruby/object:Gem::Dependency
91
- name: logstash-devutils
92
113
  version_requirements: !ruby/object:Gem::Requirement
93
114
  requirements:
94
- - - '>='
115
+ - - ">="
95
116
  - !ruby/object:Gem::Version
96
117
  version: '0'
118
+ - !ruby/object:Gem::Dependency
97
119
  requirement: !ruby/object:Gem::Requirement
98
120
  requirements:
99
- - - '>='
121
+ - - ">="
100
122
  - !ruby/object:Gem::Version
101
123
  version: '0'
124
+ name: flores
102
125
  prerelease: false
103
126
  type: :development
104
- - !ruby/object:Gem::Dependency
105
- name: flores
106
127
  version_requirements: !ruby/object:Gem::Requirement
107
128
  requirements:
108
- - - '>='
129
+ - - ">="
109
130
  - !ruby/object:Gem::Version
110
131
  version: '0'
132
+ - !ruby/object:Gem::Dependency
111
133
  requirement: !ruby/object:Gem::Requirement
112
134
  requirements:
113
- - - '>='
135
+ - - ">="
114
136
  - !ruby/object:Gem::Version
115
137
  version: '0'
138
+ name: timecop
116
139
  prerelease: false
117
140
  type: :development
118
- 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.
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ 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
119
147
  email: info@elastic.co
120
148
  executables: []
121
149
  extensions: []
@@ -141,12 +169,12 @@ require_paths:
141
169
  - lib
142
170
  required_ruby_version: !ruby/object:Gem::Requirement
143
171
  requirements:
144
- - - '>='
172
+ - - ">="
145
173
  - !ruby/object:Gem::Version
146
174
  version: '0'
147
175
  required_rubygems_version: !ruby/object:Gem::Requirement
148
176
  requirements:
149
- - - '>='
177
+ - - ">="
150
178
  - !ruby/object:Gem::Version
151
179
  version: '0'
152
180
  requirements: []