fluent-plugin-redis_list_poller 0.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 +7 -0
- data/.gitignore +10 -0
- data/CHANGELOG.txt +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +11 -0
- data/README.md +71 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/data.sh +6 -0
- data/examples/standalone.conf +25 -0
- data/fluent-plugin-redis_list_poller.gemspec +22 -0
- data/lib/fluent/plugin/in_redis_list_monitor.rb +174 -0
- data/lib/fluent/plugin/in_redis_list_poller.rb +263 -0
- data/lib/fluent/plugin_mixin/redis.rb +63 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5664df7a09d8c92d2eff417ca21e3e77c1469d96
|
4
|
+
data.tar.gz: f23f3179502d0104f0634e7acb5ad1bdc8abd430
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 60ecb470169580c8b2a27ae5d7892f55d547680433ce16e66eb58d0141c0fbabf6d8e4c71de6c100fd8bfead32edae64e94928ad75d63e71691cb09c29ed7f38
|
7
|
+
data.tar.gz: 5a15699078c53d68f47cdbe5543ddabff3be92676e9d670ccc67a3739e8a8b0e6725a21620509dd5c89a833681dc451b3589a84a780039aa25ab30afb32fd08e
|
data/.gitignore
ADDED
data/CHANGELOG.txt
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
2
|
+
you may not use this file except in compliance with the License.
|
3
|
+
You may obtain a copy of the License at
|
4
|
+
|
5
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
|
7
|
+
Unless required by applicable law or agreed to in writing, software
|
8
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
9
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
See the License for the specific language governing permissions and
|
11
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Fluent::Plugin::RedisListPoller
|
2
|
+
|
3
|
+
This gem provides a few input plugins for Fluentd which are designed to more efficiently poll large volumes of messages than other existing redis input plugins.
|
4
|
+
|
5
|
+
* *redis_list_poller*: Input plugin designed to fetch large volumes of messages
|
6
|
+
* *redis_list_monitor*: Input plugin designed to fetch queue size metrics
|
7
|
+
|
8
|
+
In additional to the standard stuff, the `redis_list_poller` input plugin also looks for a lock key in Redis to see whether it has been administratively disabled. This lock key follows the naming convention of `redis:KEY_NAME:lock`.
|
9
|
+
|
10
|
+
## Requirements
|
11
|
+
|
12
|
+
* Fluentd v0.14+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
```bash
|
17
|
+
gem install fluent-plugin-redis_list_poller
|
18
|
+
```
|
19
|
+
|
20
|
+
## Configuration Options
|
21
|
+
|
22
|
+
```
|
23
|
+
<source>
|
24
|
+
@type redis_list_poller
|
25
|
+
host 127.0.0.1
|
26
|
+
port 6379
|
27
|
+
path nil
|
28
|
+
password nil
|
29
|
+
db 0
|
30
|
+
timeout 5.0
|
31
|
+
driver ruby
|
32
|
+
|
33
|
+
key redis_list_item
|
34
|
+
command lpop
|
35
|
+
batch_size 100
|
36
|
+
|
37
|
+
tag redis.data
|
38
|
+
format json
|
39
|
+
|
40
|
+
poll_inteval 0.01
|
41
|
+
sleep_inteval 5
|
42
|
+
retry_interval 5
|
43
|
+
</source>
|
44
|
+
```
|
45
|
+
|
46
|
+
## Benchmarks
|
47
|
+
|
48
|
+
These very simple benchmarks which give a rough ideas of the sorts of message rates one can expect from this input plugin.
|
49
|
+
|
50
|
+
They were run within a Vagrant box, with a local Redis, running on my Macbook Pro 15'. Fluentd is running on a single CPU core and is using the examples/standalone.conf.
|
51
|
+
|
52
|
+
poll_interval|batch_size|messages/second|
|
53
|
+
-------------|----------|---------------|
|
54
|
+
1 | 1 | 1
|
55
|
+
0.5 | 1 | 2
|
56
|
+
0.2 | 1 | 5
|
57
|
+
0.01 | 1 | 100
|
58
|
+
0.001 | 1 | 457
|
59
|
+
poll_interval|batch_size|messages/second|
|
60
|
+
1 | 10 | 10
|
61
|
+
0.5 | 10 | 20
|
62
|
+
0.2 | 10 | 50
|
63
|
+
0.01 | 10 | 1000
|
64
|
+
0.001 | 10 | 1793
|
65
|
+
poll_interval|batch_size|messages/second|
|
66
|
+
1 | 100 | 100
|
67
|
+
0.5 | 100 | 200
|
68
|
+
0.2 | 100 | 500
|
69
|
+
0.01 | 100 | 7823
|
70
|
+
0.001 | 100 | 7600
|
71
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "aargh"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/examples/data.sh
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#<source>
|
2
|
+
# @type redis_list_monitor
|
3
|
+
# tag redis.metrics
|
4
|
+
# host 127.0.0.1
|
5
|
+
# key test
|
6
|
+
# poll_interval 1
|
7
|
+
#</source>
|
8
|
+
|
9
|
+
<source>
|
10
|
+
@type redis_list_poller
|
11
|
+
tag redis.content
|
12
|
+
host 127.0.0.1
|
13
|
+
key test
|
14
|
+
batch_size 1
|
15
|
+
poll_interval 1
|
16
|
+
</source>
|
17
|
+
|
18
|
+
<match redis.content>
|
19
|
+
@type flowcounter_simple
|
20
|
+
unit second
|
21
|
+
</match>
|
22
|
+
|
23
|
+
#<match redis.metrics>
|
24
|
+
# @type stdout
|
25
|
+
#</match>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "fluent-plugin-redis_list_poller"
|
5
|
+
spec.version = "0.1.0"
|
6
|
+
spec.authors = ["Jonathan Serafini"]
|
7
|
+
spec.email = ["jonathan@serafini.ca"]
|
8
|
+
|
9
|
+
spec.summary = %q{A fluentd redis input plugin supporting batch operations}
|
10
|
+
spec.description = spec.summary
|
11
|
+
spec.homepage = "https://github.com/JonathanSerafini/fluent-plugin-redis_list_poller"
|
12
|
+
spec.license = "apache2"
|
13
|
+
|
14
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
15
|
+
spec.executables = []
|
16
|
+
spec.require_paths = ["lib"]
|
17
|
+
|
18
|
+
spec.add_development_dependency "bundler"
|
19
|
+
spec.add_development_dependency "rake"
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "fluentd", [">= 0.12.0", "< 2"]
|
22
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require "fluent/plugin/input"
|
2
|
+
require "fluent/plugin_mixin/redis"
|
3
|
+
|
4
|
+
module Fluent
|
5
|
+
module Plugin
|
6
|
+
# Input plugin which will monitor the size of a redis list and periodically
|
7
|
+
# output metrics to the login pipeline.
|
8
|
+
# @since 0.1.0
|
9
|
+
class RedisListMonitorInput < Input
|
10
|
+
include Fluent::PluginMixin::Redis
|
11
|
+
|
12
|
+
Plugin.register_input('redis_list_monitor', self)
|
13
|
+
|
14
|
+
# input plugin parameters
|
15
|
+
config_param :tag, :string, :default => nil
|
16
|
+
|
17
|
+
# Initialize new input plugin
|
18
|
+
# @since 0.1.0
|
19
|
+
# @return [NilClass]
|
20
|
+
def initialize
|
21
|
+
super
|
22
|
+
require 'cool.io'
|
23
|
+
end
|
24
|
+
|
25
|
+
# Initialize attributes and parameters
|
26
|
+
# @since 0.1.0
|
27
|
+
# @return [NilClass]
|
28
|
+
def configure(config)
|
29
|
+
super
|
30
|
+
|
31
|
+
configure_params(config)
|
32
|
+
configure_locking(config)
|
33
|
+
|
34
|
+
@queue_length = 0
|
35
|
+
@retry_at = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
# Configure plugin parameters
|
39
|
+
# @since 0.1.0
|
40
|
+
# @return [NilClass]
|
41
|
+
def configure_params(config)
|
42
|
+
%w(host port key tag).each do |key|
|
43
|
+
next if instance_variable_get("@#{key}")
|
44
|
+
raise Fluent::ConfigError, "configuration key missing: #{key}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Configure locking
|
49
|
+
# @since 0.1.0
|
50
|
+
# @return [NilClass]
|
51
|
+
def configure_locking(config)
|
52
|
+
@storage = storage_create(type: 'local')
|
53
|
+
@lock_key = "redis:#{@key}:lock"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Prepare the plugin event loop
|
57
|
+
#
|
58
|
+
# This method will initialize the Redis connection object, create any required Redis structures as well
|
59
|
+
# as define and begin the event pollers.
|
60
|
+
#
|
61
|
+
# @since 0.1.0
|
62
|
+
# @return [NilClass]
|
63
|
+
def start
|
64
|
+
super
|
65
|
+
|
66
|
+
@loop = Coolio::Loop.new
|
67
|
+
|
68
|
+
start_redis
|
69
|
+
start_poller
|
70
|
+
|
71
|
+
@thread = Thread.new(&method(:run))
|
72
|
+
end
|
73
|
+
|
74
|
+
def start_poller
|
75
|
+
@poller = TimerWatcher.new(
|
76
|
+
@poll_interval,
|
77
|
+
log,
|
78
|
+
&method(:action_poll)
|
79
|
+
)
|
80
|
+
|
81
|
+
@loop.attach(@poller)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Begin the logging pipeline
|
85
|
+
# @since 0.1.0
|
86
|
+
# @return [NilClass]
|
87
|
+
def run
|
88
|
+
@loop.run
|
89
|
+
rescue => e
|
90
|
+
log.error "unexpected error", :error => e
|
91
|
+
log.error_backtrace
|
92
|
+
end
|
93
|
+
|
94
|
+
# Tear down the plugin
|
95
|
+
# @since 0.1.0
|
96
|
+
# @return [NilClass]
|
97
|
+
def shutdown
|
98
|
+
@loop.watchers.each { |w| w.detach }
|
99
|
+
@loop.stop
|
100
|
+
Thread.kill(@thread)
|
101
|
+
@thread.join
|
102
|
+
shutdown_redis
|
103
|
+
super
|
104
|
+
end
|
105
|
+
|
106
|
+
# Wether the poller has been temporarily disabled or should fetch messages
|
107
|
+
# been temporarily disabled
|
108
|
+
# @since 0.1.0
|
109
|
+
# @return [TrueClass, FalseClass]
|
110
|
+
def sleeping?
|
111
|
+
@retry_at and @retry_at >= Engine.now
|
112
|
+
end
|
113
|
+
|
114
|
+
# Set a sleep delay, ensuring that we will not attempt to fetch messages
|
115
|
+
# @since 0.1.0
|
116
|
+
# @param [Integer] delay, the amount of seconds to wait
|
117
|
+
# @return [Integer] timestamp when this expires
|
118
|
+
def sleep!(delay = @sleep_interval)
|
119
|
+
@retry_at = Engine.now + delay
|
120
|
+
end
|
121
|
+
|
122
|
+
# Action to execute when the monitor event watcher executes
|
123
|
+
#
|
124
|
+
# The monitor is simply responsible for outputting the queue length to
|
125
|
+
# the logs as well as detecting zero length lists.
|
126
|
+
#
|
127
|
+
# @since 0.1.0
|
128
|
+
# @return [NilClass]
|
129
|
+
def action_poll
|
130
|
+
now = Engine.now
|
131
|
+
|
132
|
+
if sleeping?
|
133
|
+
log.trace "redis worker is sleeping"
|
134
|
+
return
|
135
|
+
end
|
136
|
+
|
137
|
+
list_size = @redis.llen(@key)
|
138
|
+
|
139
|
+
event = {
|
140
|
+
"timestamp" => now,
|
141
|
+
"message" => "redis queue monitor",
|
142
|
+
"hostname" => @host,
|
143
|
+
"key" => @key,
|
144
|
+
"size" => list_size
|
145
|
+
}
|
146
|
+
|
147
|
+
router.emit @tag, now, event
|
148
|
+
rescue => e
|
149
|
+
log.error "error monitoring queue", :error => e
|
150
|
+
log.error_backtrace
|
151
|
+
sleep!(@retry_interval)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Generic Cool.io timer which will execute a given callback on schedule.
|
155
|
+
# @since 0.1.0
|
156
|
+
class TimerWatcher < Coolio::TimerWatcher
|
157
|
+
attr_reader :log
|
158
|
+
|
159
|
+
def initialize(interval, log, &callback)
|
160
|
+
@callback = callback
|
161
|
+
@log = log
|
162
|
+
super(interval, true)
|
163
|
+
end
|
164
|
+
|
165
|
+
def on_timer
|
166
|
+
@callback.call
|
167
|
+
rescue => e
|
168
|
+
log.error "unexpected error", :error=>e
|
169
|
+
log.error_backtrace
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
require "fluent/plugin/input"
|
2
|
+
require "fluent/plugin_mixin/redis"
|
3
|
+
|
4
|
+
module Fluent
|
5
|
+
module Plugin
|
6
|
+
class RedisListPollerInput < Input
|
7
|
+
include Fluent::PluginMixin::Redis
|
8
|
+
|
9
|
+
Plugin.register_input('redis_list_poller', self)
|
10
|
+
|
11
|
+
helpers :storage
|
12
|
+
|
13
|
+
# redis list details
|
14
|
+
# - command: redis command to execute when fetching messages
|
15
|
+
# - batch_size: if greater than 0, fetch messages in batches
|
16
|
+
config_param :command, :string, :default => "lpop"
|
17
|
+
config_param :batch_size, :integer, :default => 0
|
18
|
+
|
19
|
+
# input plugin parameters
|
20
|
+
config_param :tag, :string, :default => nil
|
21
|
+
config_param :format, :string, :default => "json"
|
22
|
+
|
23
|
+
# Initialize new input plugin
|
24
|
+
# @since 0.1.0
|
25
|
+
# @return [NilClass]
|
26
|
+
def initialize
|
27
|
+
super
|
28
|
+
require 'cool.io'
|
29
|
+
require 'msgpack'
|
30
|
+
end
|
31
|
+
|
32
|
+
# Initialize attributes and parameters
|
33
|
+
# @since 0.1.0
|
34
|
+
# @return [NilClass]
|
35
|
+
def configure(config)
|
36
|
+
super
|
37
|
+
|
38
|
+
configure_params(config)
|
39
|
+
configure_parser(config)
|
40
|
+
configure_locking(config)
|
41
|
+
|
42
|
+
@retry_at = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Configure plugin parameters
|
46
|
+
# @since 0.1.0
|
47
|
+
# @return [NilClass]
|
48
|
+
def configure_params(config)
|
49
|
+
%w(host port key command format tag).each do |key|
|
50
|
+
next if instance_variable_get("@#{key}")
|
51
|
+
raise Fluent::ConfigError, "configuration key missing: #{key}"
|
52
|
+
end
|
53
|
+
|
54
|
+
unless %w(lpop rpop).include?(@command)
|
55
|
+
raise Fluent::ConfigError, "command must be either lpop or rpop"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Configure record parser
|
60
|
+
# @since 0.1.0
|
61
|
+
# @return [NilClass]
|
62
|
+
def configure_parser(config)
|
63
|
+
@parser = Plugin.new_parser(@format)
|
64
|
+
@parser.configure(config)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Configure locking
|
68
|
+
# @since 0.1.0
|
69
|
+
# @return [NilClass]
|
70
|
+
def configure_locking(config)
|
71
|
+
@storage = storage_create(type: 'local')
|
72
|
+
@lock_key = "fluentd:#{@key}:lock"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Prepare the plugin event loop
|
76
|
+
#
|
77
|
+
# This method will initialize the Redis connection object, create any required Redis structures as well
|
78
|
+
# as define and begin the event pollers.
|
79
|
+
#
|
80
|
+
# @since 0.1.0
|
81
|
+
# @return [NilClass]
|
82
|
+
def start
|
83
|
+
super
|
84
|
+
|
85
|
+
@loop = Coolio::Loop.new
|
86
|
+
start_redis
|
87
|
+
start_poller
|
88
|
+
@thread = Thread.new(&method(:run))
|
89
|
+
end
|
90
|
+
|
91
|
+
# Prepare the Redis queue poller
|
92
|
+
#
|
93
|
+
# This timed event will routinely poll items from the Redis list and
|
94
|
+
# emit those through the pipeline.
|
95
|
+
#
|
96
|
+
# @since 0.1.0
|
97
|
+
# @return [NilClass]
|
98
|
+
def start_poller
|
99
|
+
@poller = TimerWatcher.new(
|
100
|
+
@poll_interval,
|
101
|
+
log,
|
102
|
+
&method(:action_poll)
|
103
|
+
)
|
104
|
+
|
105
|
+
@lock_monitor = TimerWatcher.new(
|
106
|
+
1,
|
107
|
+
log,
|
108
|
+
&method(:action_locking_monitor)
|
109
|
+
)
|
110
|
+
|
111
|
+
@loop.attach(@poller)
|
112
|
+
@loop.attach(@lock_monitor)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Begin the logging pipeline
|
116
|
+
# @since 0.1.0
|
117
|
+
# @return [NilClass]
|
118
|
+
def run
|
119
|
+
@loop.run
|
120
|
+
rescue => e
|
121
|
+
log.error "unexpected error", :error => e
|
122
|
+
log.error_backtrace
|
123
|
+
end
|
124
|
+
|
125
|
+
# Tear down the plugin
|
126
|
+
# @since 0.1.0
|
127
|
+
# @return [NilClass]
|
128
|
+
def shutdown
|
129
|
+
@loop.watchers.each { |w| w.detach }
|
130
|
+
@loop.stop
|
131
|
+
Thread.kill(@thread)
|
132
|
+
@thread.join
|
133
|
+
shutdown_redis
|
134
|
+
super
|
135
|
+
end
|
136
|
+
|
137
|
+
# Whether to fetch a single item or a multiple items in batch
|
138
|
+
# @since 0.1.0
|
139
|
+
# @return [TrueClass, FalseClass]
|
140
|
+
def batched?
|
141
|
+
@batch_size and @batch_size > 1
|
142
|
+
end
|
143
|
+
|
144
|
+
# Wether the poller has been temporarily disabled or should fetch messages
|
145
|
+
# been temporarily disabled
|
146
|
+
# @since 0.1.0
|
147
|
+
# @return [TrueClass, FalseClass]
|
148
|
+
def sleeping?
|
149
|
+
@retry_at and @retry_at >= Engine.now
|
150
|
+
end
|
151
|
+
|
152
|
+
# Whether the poller has been locked
|
153
|
+
# @since 0.1.0
|
154
|
+
# @return [TrueClass, FalseClass]
|
155
|
+
def locked?
|
156
|
+
@storage.get(@lock_key)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Set a sleep delay, ensuring that we will not attempt to fetch messages
|
160
|
+
# @since 0.1.0
|
161
|
+
# @param [Integer] delay, the amount of seconds to wait
|
162
|
+
# @return [Integer] timestamp when this expires
|
163
|
+
def sleep!(delay = @sleep_interval)
|
164
|
+
@retry_at = Engine.now + delay
|
165
|
+
end
|
166
|
+
|
167
|
+
# Poll messages from the redis server in either single message or
|
168
|
+
# batch mode.
|
169
|
+
# @since 0.1.0
|
170
|
+
# @param [&block] the block to yield single messages to
|
171
|
+
# @return [NilClass]
|
172
|
+
def poll_messages
|
173
|
+
commands = []
|
174
|
+
|
175
|
+
if batched?
|
176
|
+
@redis.pipelined do
|
177
|
+
@batch_size.times do
|
178
|
+
commands << @redis.call(@command, @key)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
else
|
182
|
+
commands << @redis.call(@command, @key)
|
183
|
+
end
|
184
|
+
|
185
|
+
commands.each do |command|
|
186
|
+
yield command.is_a?(Redis::Future) ? command.value : command
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Action to execute when polling for the lock key
|
191
|
+
# @since 0.1.0
|
192
|
+
# @return [NilClass]
|
193
|
+
def action_locking_monitor
|
194
|
+
lock_value = @redis.get(@lock_key)
|
195
|
+
@storage.put(@lock_key, lock_value)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Action to execute when the poller event watcher executes
|
199
|
+
#
|
200
|
+
# Given that the watcher is pretty lightweight, we simply return if the
|
201
|
+
# worker has been set to sleep instead of actually sleeping. Doing
|
202
|
+
# otherwise seemed to cause locking.
|
203
|
+
#
|
204
|
+
# Otherwise we iterate through messages, parse and emit them.
|
205
|
+
#
|
206
|
+
# @since 0.1.0
|
207
|
+
# @return [NilClass]
|
208
|
+
def action_poll
|
209
|
+
now = Engine.now
|
210
|
+
messages = []
|
211
|
+
|
212
|
+
if sleeping?
|
213
|
+
log.trace "redis worker is sleeping"
|
214
|
+
return
|
215
|
+
end
|
216
|
+
|
217
|
+
if locked?
|
218
|
+
log.trace "redis queue is locked"
|
219
|
+
return
|
220
|
+
end
|
221
|
+
|
222
|
+
poll_messages do |message|
|
223
|
+
if message.nil?
|
224
|
+
log.debug "redis queue is empty"
|
225
|
+
sleep!(@sleep_interval)
|
226
|
+
break
|
227
|
+
end
|
228
|
+
|
229
|
+
@parser.parse(message) do |time, record|
|
230
|
+
if time && record
|
231
|
+
router.emit @tag || @key, time || Engine.now, record
|
232
|
+
else
|
233
|
+
log.warn "failed to parse message: #{message}"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
rescue => e
|
238
|
+
log.error "error fetching record", :error => e
|
239
|
+
log.error_backtrace
|
240
|
+
sleep!(@retry_interval)
|
241
|
+
end
|
242
|
+
|
243
|
+
# Generic Cool.io timer which will execute a given callback on schedule.
|
244
|
+
# @since 0.1.0
|
245
|
+
class TimerWatcher < Coolio::TimerWatcher
|
246
|
+
attr_reader :log
|
247
|
+
|
248
|
+
def initialize(interval, log, &callback)
|
249
|
+
@callback = callback
|
250
|
+
@log = log
|
251
|
+
super(interval, true)
|
252
|
+
end
|
253
|
+
|
254
|
+
def on_timer
|
255
|
+
@callback.call
|
256
|
+
rescue => e
|
257
|
+
log.error "unexpected error", :error => e
|
258
|
+
log.error_backtrace
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
|
2
|
+
module Fluent
|
3
|
+
module PluginMixin
|
4
|
+
module Redis
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
# redis connection details
|
8
|
+
config_param :host, :string, :default => '127.0.0.1'
|
9
|
+
config_param :port, :integer, :default => 6379
|
10
|
+
config_param :path, :string, :default => nil
|
11
|
+
config_param :password, :string, :default => nil
|
12
|
+
config_param :db, :integer, :default => 0
|
13
|
+
config_param :timeout, :float, :default => 5.0
|
14
|
+
config_param :driver, :string, :default => "ruby"
|
15
|
+
|
16
|
+
# redis list details
|
17
|
+
# - key: redis key of type `list` to fetch messages from
|
18
|
+
# - command: redis command to execute when fetching messages
|
19
|
+
# - batch_size: if greater than 0, fetch messages in batches
|
20
|
+
config_param :key, :string, :default => nil
|
21
|
+
|
22
|
+
# worker parameters
|
23
|
+
# - poll_inteval: interval between message polling actions
|
24
|
+
# *NOTE*: Apparently this must be greather than 0
|
25
|
+
# - sleep_interval: interval to wait after receiving 0 messages
|
26
|
+
# - retry_interval: interval to wait before retrying after an error
|
27
|
+
config_param :poll_interval, :float, :default => 1
|
28
|
+
config_param :sleep_interval, :float, :default => 5
|
29
|
+
config_param :retry_interval, :float, :default => 5
|
30
|
+
|
31
|
+
attr_reader :redis
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initialize new input plugin
|
36
|
+
# @since 0.1.0
|
37
|
+
# @return [NilClass]
|
38
|
+
def initialize
|
39
|
+
require 'redis'
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
# Prepare the Redis conncection object
|
44
|
+
# @since 0.1.0
|
45
|
+
# @return [Redis]
|
46
|
+
def start_redis
|
47
|
+
@redis = ::Redis.new(
|
48
|
+
:host => @host,
|
49
|
+
:port => @port,
|
50
|
+
:driver => @driver,
|
51
|
+
:thread_safe => true
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Destroy the Redis connection object
|
56
|
+
# @since 0.1.0
|
57
|
+
# @return [NilClass]
|
58
|
+
def shutdown_redis
|
59
|
+
@redis.quit
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-redis_list_poller
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jonathan Serafini
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: fluentd
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.12.0
|
48
|
+
- - "<"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '2'
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 0.12.0
|
58
|
+
- - "<"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2'
|
61
|
+
description: A fluentd redis input plugin supporting batch operations
|
62
|
+
email:
|
63
|
+
- jonathan@serafini.ca
|
64
|
+
executables: []
|
65
|
+
extensions: []
|
66
|
+
extra_rdoc_files: []
|
67
|
+
files:
|
68
|
+
- ".gitignore"
|
69
|
+
- CHANGELOG.txt
|
70
|
+
- Gemfile
|
71
|
+
- LICENSE.txt
|
72
|
+
- README.md
|
73
|
+
- Rakefile
|
74
|
+
- bin/console
|
75
|
+
- bin/setup
|
76
|
+
- examples/data.sh
|
77
|
+
- examples/standalone.conf
|
78
|
+
- fluent-plugin-redis_list_poller.gemspec
|
79
|
+
- lib/fluent/plugin/in_redis_list_monitor.rb
|
80
|
+
- lib/fluent/plugin/in_redis_list_poller.rb
|
81
|
+
- lib/fluent/plugin_mixin/redis.rb
|
82
|
+
homepage: https://github.com/JonathanSerafini/fluent-plugin-redis_list_poller
|
83
|
+
licenses:
|
84
|
+
- apache2
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.5.2
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: A fluentd redis input plugin supporting batch operations
|
106
|
+
test_files: []
|
107
|
+
has_rdoc:
|