logstash-input-redis 2.0.2 → 2.0.3

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: 5dc8076a13a0c8563482032f19ce6371d23befd2
4
- data.tar.gz: 76d9b1bd9210129bbfe4cb3605d5ff4d19307f7a
3
+ metadata.gz: d9928285771d37dd118f099c40c59243cb24aedf
4
+ data.tar.gz: 9fa7aeb915e98e533b06aaddc91f830b2595256c
5
5
  SHA512:
6
- metadata.gz: 942e3733ec6c9bda66d614eb3fa0f8ffd682c119bb055e6396024a1442e12fffb93464acdfb3ec79d8a564dc6b30ea3acabe21461dae7cc07cffae87ebfc9713
7
- data.tar.gz: b286512a0bfcd241d64c44fbfd8df2eb6e5e0add94a812afa972ef1aa1d390600c02cece6022475b4a438ac39b052c732d3cebd9b92128898dc77652e75cc332
6
+ metadata.gz: dee7ad5a84df8293ffdb343a478caad99e1d951e2b5b344a866e25d5f19bb23128c5b63573dca91be6435142382589264f2bc9c97270454e5f7cdf853d91f1f7
7
+ data.tar.gz: 88deceeca56390a52fac036bba9191b15362ab6a3e972a85be4cf3ce7ea12c29d11f1a3ddc64fa98542cd05a4f4e4a9b0930ff8827253558aa6f9c670bd882cd
@@ -1,5 +1,8 @@
1
+ ## 2.0.3
2
+ - Changed default batch size to 125. Improve batch handling code. Add travis ci build with redis integration.
3
+
1
4
  ## 2.0.0
2
- - Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
5
+ - Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
3
6
  instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
4
7
  - Dependency on logstash-core update to 2.0
5
8
 
@@ -14,6 +14,7 @@ Contributors:
14
14
  * Pier-Hugues Pellerin (ph)
15
15
  * Richard Pijnenburg (electrical)
16
16
  * piavlo
17
+ * Guy Boertje (guyboertje)
17
18
 
18
19
  Note: If you've sent us patches, bug reports, or otherwise contributed to
19
20
  Logstash, and you aren't on the list above and want to be, please let us know
data/README.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Logstash Plugin
2
2
 
3
+ Travis Build
4
+ [![Travis Build Status](https://travis-ci.org/logstash-plugins/logstash-input-redis.svg)](https://travis-ci.org/logstash-plugins/logstash-input-redis)
5
+
6
+ Jenkins Build
7
+ [![Build
8
+ Status](http://build-eu-00.elastic.co/view/LS%20Plugins/view/LS%20Inputs/job/logstash-plugin-input-redis-unit/badge/icon)](http://build-eu-00.elastic.co/view/LS%20Plugins/view/LS%20Inputs/job/logstash-plugin-input-redis-unit/)
9
+
3
10
  This is a plugin for [Logstash](https://github.com/elastic/logstash).
4
11
 
5
12
  It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
@@ -83,4 +90,4 @@ Programming is not a required skill. Whatever you've seen about open source and
83
90
 
84
91
  It is more important to the community that you are able to contribute.
85
92
 
86
- For more information about contributing, see the [CONTRIBUTING](https://github.com/elastic/logstash/blob/master/CONTRIBUTING.md) file.
93
+ For more information about contributing, see the [CONTRIBUTING](https://github.com/elastic/logstash/blob/master/CONTRIBUTING.md) file.
@@ -2,6 +2,7 @@
2
2
  require "logstash/namespace"
3
3
  require "logstash/inputs/base"
4
4
  require "logstash/inputs/threadable"
5
+ require 'redis'
5
6
 
6
7
  # This input will read events from a Redis instance; it supports both Redis channels and lists.
7
8
  # The list command (BLPOP) used by Logstash is supported in Redis v1.3.1+, and
@@ -16,7 +17,7 @@ require "logstash/inputs/threadable"
16
17
  # newer. Anything older does not support the operations used by batching.
17
18
  #
18
19
  module LogStash module Inputs class Redis < LogStash::Inputs::Threadable
19
- # class LogStash::Inputs::Redis < LogStash::Inputs::Threadable
20
+ BATCH_EMPTY_SLEEP = 0.25
20
21
 
21
22
  config_name "redis"
22
23
 
@@ -56,7 +57,7 @@ module LogStash module Inputs class Redis < LogStash::Inputs::Threadable
56
57
  config :data_type, :validate => [ "list", "channel", "pattern_channel" ], :required => false
57
58
 
58
59
  # The number of events to return from Redis using EVAL.
59
- config :batch_count, :validate => :number, :default => 1
60
+ config :batch_count, :validate => :number, :default => 125
60
61
 
61
62
  public
62
63
  # public API
@@ -77,7 +78,6 @@ module LogStash module Inputs class Redis < LogStash::Inputs::Threadable
77
78
  end
78
79
 
79
80
  def register
80
- require 'redis'
81
81
  @redis_url = "redis://#{@password}@#{@host}:#{@port}/#{@db}"
82
82
 
83
83
  # TODO remove after setting key and data_type to true
@@ -112,6 +112,8 @@ module LogStash module Inputs class Redis < LogStash::Inputs::Threadable
112
112
  @stop_method = method(:subscribe_stop)
113
113
  end
114
114
 
115
+ @list_method = batched? ? method(:list_batch_listener) : method(:list_single_listener)
116
+
115
117
  # TODO(sissel, boertje): set @identity directly when @name config option is removed.
116
118
  @identity = @name != 'default' ? @name : "#{@redis_url} #{@data_type}:#{@key}"
117
119
  @logger.info("Registering Redis", :identity => @identity)
@@ -165,21 +167,11 @@ module LogStash module Inputs class Redis < LogStash::Inputs::Threadable
165
167
  # private
166
168
  def load_batch_script(redis)
167
169
  #A Redis Lua EVAL script to fetch a count of keys
168
- #in case count is bigger than current items in queue whole queue will be returned without extra nil values
169
- redis_script = <<EOF
170
- local i = tonumber(ARGV[1])
171
- local res = {}
172
- local length = redis.call('llen',KEYS[1])
173
- if length < i then i = length end
174
- while (i > 0) do
175
- local item = redis.call("lpop", KEYS[1])
176
- if (not item) then
177
- break
178
- end
179
- table.insert(res, item)
180
- i = i-1
181
- end
182
- return res
170
+ redis_script = <<EOF
171
+ local batchsize = tonumber(ARGV[1])
172
+ local result = redis.call('lrange', KEYS[1], 0, batchsize)
173
+ redis.call('ltrim', KEYS[1], batchsize + 1, -1)
174
+ return result
183
175
  EOF
184
176
  @redis_script_sha = redis.script(:load, redis_script)
185
177
  end
@@ -209,7 +201,7 @@ EOF
209
201
  while !stop?
210
202
  begin
211
203
  @redis ||= connect
212
- list_listener(@redis, output_queue)
204
+ @list_method.call(@redis, output_queue)
213
205
  rescue ::Redis::BaseError => e
214
206
  @logger.warn("Redis connection problem", :exception => e)
215
207
  # Reset the redis variable to trigger reconnect
@@ -221,24 +213,17 @@ EOF
221
213
  end
222
214
  end
223
215
 
224
- # private
225
- def list_listener(redis, output_queue)
226
-
227
- item = redis.blpop(@key, 0, :timeout => 1)
228
- return unless item # from timeout or other conditions
229
-
230
- # blpop returns the 'key' read from as well as the item result
231
- # we only care about the result (2nd item in the list).
232
- queue_event(item.last, output_queue)
233
-
234
- # If @batch_count is 1, there's no need to continue.
235
- return if !batched?
236
-
216
+ def list_batch_listener(redis, output_queue)
237
217
  begin
238
- redis.evalsha(@redis_script_sha, [@key], [@batch_count-1]).each do |item|
218
+ results = redis.evalsha(@redis_script_sha, [@key], [@batch_count-1])
219
+ results.each do |item|
239
220
  queue_event(item, output_queue)
240
221
  end
241
222
 
223
+ if results.size.zero?
224
+ sleep BATCH_EMPTY_SLEEP
225
+ end
226
+
242
227
  # Below is a commented-out implementation of 'batch fetch'
243
228
  # using pipelined LPOP calls. This in practice has been observed to
244
229
  # perform exactly the same in terms of event throughput as
@@ -253,6 +238,8 @@ EOF
253
238
  #queue_event(item, output_queue) if item
254
239
  #end
255
240
  # --- End commented out implementation of 'batch fetch'
241
+ # further to the above, the LUA script now uses lrange and trim
242
+ # which should further improve the efficiency of the script
256
243
  rescue ::Redis::CommandError => e
257
244
  if e.to_s =~ /NOSCRIPT/ then
258
245
  @logger.warn("Redis may have been restarted, reloading Redis batch EVAL script", :exception => e);
@@ -264,6 +251,15 @@ EOF
264
251
  end
265
252
  end
266
253
 
254
+ def list_single_listener(redis, output_queue)
255
+ item = redis.blpop(@key, 0, :timeout => 1)
256
+ return unless item # from timeout or other conditions
257
+
258
+ # blpop returns the 'key' read from as well as the item result
259
+ # we only care about the result (2nd item in the list).
260
+ queue_event(item.last, output_queue)
261
+ end
262
+
267
263
  # private
268
264
  def subscribe_stop
269
265
  return if @redis.nil? || !@redis.connected?
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
 
3
3
  s.name = 'logstash-input-redis'
4
- s.version = '2.0.2'
4
+ s.version = '2.0.3'
5
5
  s.licenses = ['Apache License (2.0)']
6
6
  s.summary = "This input will read events from a Redis instance"
7
7
  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"
@@ -2,6 +2,7 @@ require "logstash/devutils/rspec/spec_helper"
2
2
  require "redis"
3
3
  require "stud/try"
4
4
  require 'logstash/inputs/redis'
5
+ require 'securerandom'
5
6
 
6
7
  def populate(key, event_count)
7
8
  require "logstash/event"
@@ -19,17 +20,15 @@ def process(conf, event_count)
19
20
  event_count.times.map{queue.pop}
20
21
  end
21
22
 
22
- events.each_with_index do |event, i|
23
- insist { event["sequence"] } == i
24
- end
25
- end # process
23
+ expect(events.map{|evt| evt["sequence"]}).to eq((0..event_count.pred).to_a)
24
+ end
26
25
 
27
26
  # integration tests ---------------------
28
27
 
29
28
  describe "inputs/redis", :redis => true do
30
29
 
31
30
  it "should read events from a list" do
32
- key = 10.times.collect { rand(10).to_s }.join("")
31
+ key = SecureRandom.hex
33
32
  event_count = 1000 + rand(50)
34
33
  # event_count = 100
35
34
  conf = <<-CONFIG
@@ -38,6 +37,7 @@ describe "inputs/redis", :redis => true do
38
37
  type => "blah"
39
38
  key => "#{key}"
40
39
  data_type => "list"
40
+ batch_count => 1
41
41
  }
42
42
  }
43
43
  CONFIG
@@ -46,8 +46,8 @@ describe "inputs/redis", :redis => true do
46
46
  process(conf, event_count)
47
47
  end
48
48
 
49
- it "should read events from a list using batch_count" do
50
- key = 10.times.collect { rand(10).to_s }.join("")
49
+ it "should read events from a list using batch_count (default 125)" do
50
+ key = SecureRandom.hex
51
51
  event_count = 1000 + rand(50)
52
52
  conf = <<-CONFIG
53
53
  input {
@@ -55,7 +55,6 @@ describe "inputs/redis", :redis => true do
55
55
  type => "blah"
56
56
  key => "#{key}"
57
57
  data_type => "list"
58
- batch_count => #{rand(20)+1}
59
58
  }
60
59
  }
61
60
  CONFIG
@@ -73,7 +72,8 @@ describe LogStash::Inputs::Redis do
73
72
  let(:connection) { double('redis_connection') }
74
73
  let(:connected) { [true] }
75
74
  let(:data_type) { 'list' }
76
- let(:cfg) { {'key' => 'foo', 'data_type' => data_type} }
75
+ let(:batch_count) { 1 }
76
+ let(:cfg) { {'key' => 'foo', 'data_type' => data_type, 'batch_count' => batch_count} }
77
77
  let(:quit_calls) { [:quit] }
78
78
  let(:accumulator) { [] }
79
79
 
@@ -123,6 +123,65 @@ describe LogStash::Inputs::Redis do
123
123
  expect(accumulator.size).to be > 0
124
124
  end
125
125
 
126
+ context "when the batch size is greater than 1" do
127
+ let(:batch_count) { 10 }
128
+ let(:rates) { [] }
129
+
130
+ before do
131
+ allow(redis).to receive(:connected?).and_return(connected.last)
132
+ allow(redis).to receive(:script)
133
+ allow(redis).to receive(:quit)
134
+ end
135
+
136
+ it 'calling the run method, adds events to the queue' do
137
+ expect(redis).to receive(:evalsha).at_least(:once).and_return(['a', 'b'])
138
+
139
+ tt = Thread.new do
140
+ sleep 0.01
141
+ subject.do_stop
142
+ end
143
+
144
+ subject.run(accumulator)
145
+
146
+ tt.join
147
+ expect(accumulator.size).to be > 0
148
+ end
149
+ end
150
+
151
+ context "when there is no data" do
152
+ let(:batch_count) { 10 }
153
+ let(:rates) { [] }
154
+
155
+ it 'will throttle the loop' do
156
+ allow(redis).to receive(:evalsha) do
157
+ rates.unshift Time.now.to_f
158
+ []
159
+ end
160
+ allow(redis).to receive(:connected?).and_return(connected.last)
161
+ allow(redis).to receive(:script)
162
+ allow(redis).to receive(:quit)
163
+
164
+ tt = Thread.new do
165
+ sleep 1
166
+ subject.do_stop
167
+ end
168
+
169
+ subject.run(accumulator)
170
+
171
+ tt.join
172
+
173
+ inters = []
174
+ rates.each_cons(2) do |x, y|
175
+ inters << x - y
176
+ end
177
+
178
+ expect(accumulator.size).to eq(0)
179
+ inters.each do |delta|
180
+ expect(delta).to be_within(0.01).of(LogStash::Inputs::Redis::BATCH_EMPTY_SLEEP)
181
+ end
182
+ end
183
+ end
184
+
126
185
  it 'multiple close calls, calls to redis once' do
127
186
  subject.use_redis(redis)
128
187
  allow(redis).to receive(:blpop).and_return(['foo', 'l1'])
metadata CHANGED
@@ -1,17 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-14 00:00:00.000000000 Z
11
+ date: 2016-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- requirement: !ruby/object:Gem::Requirement
14
+ name: logstash-core
15
+ version_requirements: !ruby/object:Gem::Requirement
15
16
  requirements:
16
17
  - - '>='
17
18
  - !ruby/object:Gem::Version
@@ -19,10 +20,7 @@ dependencies:
19
20
  - - <
20
21
  - !ruby/object:Gem::Version
21
22
  version: 3.0.0
22
- name: logstash-core
23
- prerelease: false
24
- type: :runtime
25
- version_requirements: !ruby/object:Gem::Requirement
23
+ requirement: !ruby/object:Gem::Requirement
26
24
  requirements:
27
25
  - - '>='
28
26
  - !ruby/object:Gem::Version
@@ -30,48 +28,50 @@ dependencies:
30
28
  - - <
31
29
  - !ruby/object:Gem::Version
32
30
  version: 3.0.0
31
+ prerelease: false
32
+ type: :runtime
33
33
  - !ruby/object:Gem::Dependency
34
+ name: logstash-codec-json
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
34
40
  requirement: !ruby/object:Gem::Requirement
35
41
  requirements:
36
42
  - - '>='
37
43
  - !ruby/object:Gem::Version
38
44
  version: '0'
39
- name: logstash-codec-json
40
45
  prerelease: false
41
46
  type: :runtime
47
+ - !ruby/object:Gem::Dependency
48
+ name: redis
42
49
  version_requirements: !ruby/object:Gem::Requirement
43
50
  requirements:
44
51
  - - '>='
45
52
  - !ruby/object:Gem::Version
46
53
  version: '0'
47
- - !ruby/object:Gem::Dependency
48
54
  requirement: !ruby/object:Gem::Requirement
49
55
  requirements:
50
56
  - - '>='
51
57
  - !ruby/object:Gem::Version
52
58
  version: '0'
53
- name: redis
54
59
  prerelease: false
55
60
  type: :runtime
61
+ - !ruby/object:Gem::Dependency
62
+ name: logstash-devutils
56
63
  version_requirements: !ruby/object:Gem::Requirement
57
64
  requirements:
58
65
  - - '>='
59
66
  - !ruby/object:Gem::Version
60
67
  version: '0'
61
- - !ruby/object:Gem::Dependency
62
68
  requirement: !ruby/object:Gem::Requirement
63
69
  requirements:
64
70
  - - '>='
65
71
  - !ruby/object:Gem::Version
66
72
  version: '0'
67
- name: logstash-devutils
68
73
  prerelease: false
69
74
  type: :development
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - '>='
73
- - !ruby/object:Gem::Version
74
- version: '0'
75
75
  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
76
76
  email: info@elastic.co
77
77
  executables: []