logstash-filter-zeromq 0.1.2
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 +4 -0
- data/Gemfile +3 -0
- data/Rakefile +7 -0
- data/lib/logstash/filters/zeromq.rb +214 -0
- data/logstash-filter-zeromq.gemspec +29 -0
- data/spec/filters/zeromq_spec.rb +6 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e3dcdef0b8b0bcd244c53f52988a55af838825ef
|
4
|
+
data.tar.gz: 0d5bf5f6fa3781c2a0a9d7a82dd312d882e4cf59
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 936eff3ec8d09106d1186e69a5efc0f689b221961eebb18dc2b4f2d8b03e595da41314ca4c9c7cc19d2384b97400426e702528c5ab6bf009e9f54f158f03c7d9
|
7
|
+
data.tar.gz: d53c4b023a10ac06d8726d0a6f9171a503de0fe74a538550f8543374eeddc3fec2397eb324752a58290a956e1ba617d3b317238287b163b4c82cc0953022cafa
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/filters/base"
|
3
|
+
require "logstash/namespace"
|
4
|
+
|
5
|
+
# ZeroMQ filter. This is the best way to send an event externally for filtering
|
6
|
+
# It works much like an exec filter would by sending the event "offsite"
|
7
|
+
# for processing and waiting for a response
|
8
|
+
#
|
9
|
+
# The protocol here is:
|
10
|
+
# * REQ sent with JSON-serialized logstash event
|
11
|
+
# * REP read expected to be the full JSON 'filtered' event
|
12
|
+
# * - if reply read is an empty string, it will cancel the event.
|
13
|
+
#
|
14
|
+
# Note that this is a limited subset of the zeromq functionality in
|
15
|
+
# inputs and outputs. The only topology that makes sense here is:
|
16
|
+
# REQ/REP.
|
17
|
+
class LogStash::Filters::ZeroMQ < LogStash::Filters::Base
|
18
|
+
|
19
|
+
config_name "zeromq"
|
20
|
+
milestone 1
|
21
|
+
|
22
|
+
# 0mq socket address to connect or bind
|
23
|
+
# Please note that inproc:// will not work with logstash
|
24
|
+
# as we use a context per thread
|
25
|
+
# By default, filters connect
|
26
|
+
config :address, :validate => :string, :default => "tcp://127.0.0.1:2121"
|
27
|
+
|
28
|
+
# The field to send off-site for processing
|
29
|
+
# If this is unset, the whole event will be sent
|
30
|
+
# TODO (lusis)
|
31
|
+
# Allow filtering multiple fields
|
32
|
+
config :field, :validate => :string
|
33
|
+
|
34
|
+
# 0mq mode
|
35
|
+
# server mode binds/listens
|
36
|
+
# client mode connects
|
37
|
+
config :mode, :validate => ["server", "client"], :default => "client"
|
38
|
+
|
39
|
+
# timeout in milliseconds on which to wait for a reply.
|
40
|
+
config :timeout, :validate => :number, :default => 500
|
41
|
+
|
42
|
+
# number of retries, used for both sending and receiving messages.
|
43
|
+
# for sending, retries should return instantly.
|
44
|
+
# for receiving, the total blocking time is up to retries X timeout,
|
45
|
+
# which by default is 3 X 500 = 1500ms
|
46
|
+
config :retries, :validate => :number, :default => 3
|
47
|
+
|
48
|
+
# tag to add if zeromq timeout expires before getting back an answer.
|
49
|
+
# If set to "" then no tag will be added.
|
50
|
+
config :add_tag_on_timeout, :validate => :string, :default => "zeromqtimeout"
|
51
|
+
|
52
|
+
# 0mq socket options
|
53
|
+
# This exposes zmq_setsockopt
|
54
|
+
# for advanced tuning
|
55
|
+
# see http://api.zeromq.org/2-1:zmq-setsockopt for details
|
56
|
+
#
|
57
|
+
# This is where you would set values like:
|
58
|
+
# ZMQ::HWM - high water mark
|
59
|
+
# ZMQ::IDENTITY - named queues
|
60
|
+
# ZMQ::SWAP_SIZE - space for disk overflow
|
61
|
+
# ZMQ::SUBSCRIBE - topic filters for pubsub
|
62
|
+
#
|
63
|
+
# example: sockopt => ["ZMQ::HWM", 50, "ZMQ::IDENTITY", "my_named_queue"]
|
64
|
+
config :sockopt, :validate => :hash
|
65
|
+
|
66
|
+
public
|
67
|
+
def initialize(params)
|
68
|
+
super(params)
|
69
|
+
|
70
|
+
@threadsafe = false
|
71
|
+
end
|
72
|
+
|
73
|
+
public
|
74
|
+
def register
|
75
|
+
require "ffi-rzmq"
|
76
|
+
require "logstash/util/zeromq"
|
77
|
+
self.class.send(:include, LogStash::Util::ZeroMQ)
|
78
|
+
connect
|
79
|
+
end #def register
|
80
|
+
|
81
|
+
public
|
82
|
+
def teardown
|
83
|
+
close
|
84
|
+
super()
|
85
|
+
end #def teardown
|
86
|
+
|
87
|
+
private
|
88
|
+
def close
|
89
|
+
@logger.debug("0mq: closing socket.")
|
90
|
+
@poller.deregister(@zsocket, ZMQ::POLLIN)
|
91
|
+
@zsocket.close
|
92
|
+
end #def close
|
93
|
+
|
94
|
+
private
|
95
|
+
def connect
|
96
|
+
@logger.debug("0mq: connecting socket")
|
97
|
+
@zsocket = context.socket(ZMQ::REQ)
|
98
|
+
error_check(@zsocket.setsockopt(ZMQ::LINGER, 0),
|
99
|
+
"while setting ZMQ::LINGER == 0)")
|
100
|
+
@poller = ZMQ::Poller.new
|
101
|
+
@poller.register(@zsocket, ZMQ::POLLIN)
|
102
|
+
|
103
|
+
if @sockopt
|
104
|
+
#TODO: should make sure that ZMQ::LINGER and ZMQ::POLLIN are not changed
|
105
|
+
setopts(@zsocket, @sockopt)
|
106
|
+
end
|
107
|
+
|
108
|
+
setup(@zsocket, @address)
|
109
|
+
end #def connect
|
110
|
+
|
111
|
+
private
|
112
|
+
def reconnect
|
113
|
+
close
|
114
|
+
connect
|
115
|
+
end #def reconnect
|
116
|
+
|
117
|
+
#send and receive data. message is assumed to be json
|
118
|
+
#will return a boolean for success, and a string containing one of several things:
|
119
|
+
# - empty string: response from server
|
120
|
+
# - updated string: response from server
|
121
|
+
# - original message: could not send request or get response from server in time
|
122
|
+
private
|
123
|
+
def send_recv(message)
|
124
|
+
success = false
|
125
|
+
@retries.times do
|
126
|
+
@logger.debug("0mq: sending", :request => message)
|
127
|
+
rc = @zsocket.send_string(message)
|
128
|
+
if ZMQ::Util.resultcode_ok?(rc)
|
129
|
+
success = true
|
130
|
+
break
|
131
|
+
else
|
132
|
+
@logger.debug("0mq: error sending message (zmq_errno = #{ZMQ::Util.errno}, zmq_error_string = '#{ZMQ::Util.error_string}'")
|
133
|
+
reconnect
|
134
|
+
end #if resultcode
|
135
|
+
end #retries.times
|
136
|
+
|
137
|
+
#if we did not succeed log it and fail here.
|
138
|
+
if not success
|
139
|
+
@logger.warn("0mq: error sending message (zmq_errno = #{ZMQ::Util.errno}, zmq_error_string = '#{ZMQ::Util.error_string}'")
|
140
|
+
return success, message
|
141
|
+
end
|
142
|
+
|
143
|
+
#now get reply
|
144
|
+
reply = ''
|
145
|
+
success = false
|
146
|
+
@retries.times do
|
147
|
+
@logger.debug("0mq: polling for reply for #{@timeout}ms.")
|
148
|
+
#poll the socket. If > 0, something to read. If < 0, error. If zero, loop
|
149
|
+
num_readable = @poller.poll(@timeout)
|
150
|
+
if num_readable > 0
|
151
|
+
#something to read, do it.
|
152
|
+
rc = @zsocket.recv_string(reply)
|
153
|
+
@logger.debug("0mq: message received, checking error")
|
154
|
+
error_check(rc, "in recv_string")
|
155
|
+
success = true
|
156
|
+
break
|
157
|
+
elsif num_readable < 0
|
158
|
+
#error, reconnect
|
159
|
+
close
|
160
|
+
connect
|
161
|
+
end
|
162
|
+
end # @retries.times
|
163
|
+
|
164
|
+
#if we maxed out on number of retries, then set reply to message so that
|
165
|
+
#the event isn't cancelled. we want to carry on if the server is down.
|
166
|
+
if not success
|
167
|
+
@logger.warn("0mq: did not receive reply (zmq_errno = #{ZMQ::Util.errno}, zmq_error_string = '#{ZMQ::Util.error_string}'")
|
168
|
+
return success, message
|
169
|
+
end
|
170
|
+
|
171
|
+
return success, reply
|
172
|
+
end #def send_recv
|
173
|
+
|
174
|
+
public
|
175
|
+
def filter(event)
|
176
|
+
return unless filter?(event)
|
177
|
+
|
178
|
+
begin
|
179
|
+
if @field
|
180
|
+
success, reply = send_recv(event[@field])
|
181
|
+
else
|
182
|
+
success, reply = send_recv(event.to_json)
|
183
|
+
end
|
184
|
+
# If we receive an empty reply, this is an indication that the filter
|
185
|
+
# wishes to cancel this event.
|
186
|
+
if reply.empty?
|
187
|
+
@logger.debug("0mq: recieved empty reply, cancelling event.")
|
188
|
+
event.cancel
|
189
|
+
return
|
190
|
+
end
|
191
|
+
@logger.debug("0mq: receiving", :reply => reply)
|
192
|
+
if @field
|
193
|
+
event[@field] = event.sprintf(reply)
|
194
|
+
filter_matched(event)
|
195
|
+
else
|
196
|
+
reply = JSON.parse(reply)
|
197
|
+
event.overwrite(reply)
|
198
|
+
end
|
199
|
+
filter_matched(event)
|
200
|
+
#if message send/recv was not successful add the timeout
|
201
|
+
if not success
|
202
|
+
(event["tags"] ||= []) << @add_tag_on_timeout
|
203
|
+
end
|
204
|
+
rescue => e
|
205
|
+
@logger.warn("0mq filter exception", :address => @address, :exception => e, :backtrace => e.backtrace)
|
206
|
+
end
|
207
|
+
end # def filter
|
208
|
+
|
209
|
+
private
|
210
|
+
def server?
|
211
|
+
@mode == "server"
|
212
|
+
end # def server?
|
213
|
+
|
214
|
+
end # class LogStash::Filters::ZeroMQ
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
|
3
|
+
s.name = 'logstash-filter-zeromq'
|
4
|
+
s.version = '0.1.2'
|
5
|
+
s.licenses = ['Apache License (2.0)']
|
6
|
+
s.summary = "ZeroMQ filter. This is a way to send an event externally for filtering"
|
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"
|
8
|
+
s.authors = ["Elasticsearch"]
|
9
|
+
s.email = 'info@elasticsearch.com'
|
10
|
+
s.homepage = "http://www.elasticsearch.org/guide/en/logstash/current/index.html"
|
11
|
+
s.require_paths = ["lib"]
|
12
|
+
|
13
|
+
# Files
|
14
|
+
s.files = `git ls-files`.split($\)+::Dir.glob('vendor/*')
|
15
|
+
|
16
|
+
# Tests
|
17
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
18
|
+
|
19
|
+
# Special flag to let us know this is actually a logstash plugin
|
20
|
+
s.metadata = { "logstash_plugin" => "true", "logstash_group" => "filter" }
|
21
|
+
|
22
|
+
# Gem dependencies
|
23
|
+
s.add_runtime_dependency 'logstash', '>= 1.4.0', '< 2.0.0'
|
24
|
+
|
25
|
+
s.add_runtime_dependency 'ffi-rzmq', ['1.0.0']
|
26
|
+
|
27
|
+
s.add_development_dependency 'logstash-devutils'
|
28
|
+
end
|
29
|
+
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: logstash-filter-zeromq
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elasticsearch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: logstash
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.4.0
|
20
|
+
- - <
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.0.0
|
23
|
+
requirement: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 1.4.0
|
28
|
+
- - <
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 2.0.0
|
31
|
+
prerelease: false
|
32
|
+
type: :runtime
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: ffi-rzmq
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.0.0
|
40
|
+
requirement: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - '='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.0.0
|
45
|
+
prerelease: false
|
46
|
+
type: :runtime
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: logstash-devutils
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
prerelease: false
|
60
|
+
type: :development
|
61
|
+
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
|
62
|
+
email: info@elasticsearch.com
|
63
|
+
executables: []
|
64
|
+
extensions: []
|
65
|
+
extra_rdoc_files: []
|
66
|
+
files:
|
67
|
+
- .gitignore
|
68
|
+
- Gemfile
|
69
|
+
- Rakefile
|
70
|
+
- lib/logstash/filters/zeromq.rb
|
71
|
+
- logstash-filter-zeromq.gemspec
|
72
|
+
- spec/filters/zeromq_spec.rb
|
73
|
+
homepage: http://www.elasticsearch.org/guide/en/logstash/current/index.html
|
74
|
+
licenses:
|
75
|
+
- Apache License (2.0)
|
76
|
+
metadata:
|
77
|
+
logstash_plugin: 'true'
|
78
|
+
logstash_group: filter
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.4.4
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: ZeroMQ filter. This is a way to send an event externally for filtering
|
99
|
+
test_files:
|
100
|
+
- spec/filters/zeromq_spec.rb
|