logstash-input-redis 2.0.2 → 2.0.3

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: 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: []