riemann-client 0.2.5 → 1.0.1
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/.github/workflows/ci.yml +58 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +18 -0
- data/CHANGELOG.md +84 -0
- data/Gemfile +7 -0
- data/README.markdown +21 -12
- data/Rakefile +15 -0
- data/lib/riemann/attribute.rb +2 -0
- data/lib/riemann/auto_state.rb +9 -3
- data/lib/riemann/client/ssl_socket.rb +92 -0
- data/lib/riemann/client/tcp.rb +46 -39
- data/lib/riemann/client/tcp_socket.rb +76 -58
- data/lib/riemann/client/udp.rb +8 -4
- data/lib/riemann/client.rb +84 -78
- data/lib/riemann/event.rb +60 -61
- data/lib/riemann/message.rb +2 -0
- data/lib/riemann/metric_thread.rb +59 -54
- data/lib/riemann/query.rb +4 -2
- data/lib/riemann/state.rb +8 -8
- data/lib/riemann/version.rb +3 -1
- data/lib/riemann.rb +2 -3
- data/riemann-client.gemspec +34 -0
- data/spec/client.rb +384 -0
- data/spec/riemann.config +30 -0
- metadata +84 -38
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'socket'
|
2
4
|
require 'fcntl'
|
3
5
|
|
4
6
|
module Riemann
|
5
7
|
class Client
|
6
|
-
|
8
|
+
# Socket: A specialized socket that has been configure
|
7
9
|
class TcpSocket
|
8
10
|
class Error < Riemann::Client::Error; end
|
9
11
|
class Timeout < Error; end
|
@@ -68,7 +70,6 @@ module Riemann
|
|
68
70
|
# connection dead and notifying the application layer.
|
69
71
|
attr_reader :keepalive_count
|
70
72
|
|
71
|
-
|
72
73
|
# Internal: Create and connect to the given location.
|
73
74
|
#
|
74
75
|
# options, same as Constructor
|
@@ -77,11 +78,11 @@ module Riemann
|
|
77
78
|
def self.connect(options = {})
|
78
79
|
s = new(options)
|
79
80
|
s.connect
|
80
|
-
|
81
|
+
s
|
81
82
|
end
|
82
83
|
|
83
84
|
# Internal: Creates a new KJess::Socket
|
84
|
-
def initialize(
|
85
|
+
def initialize(options = {})
|
85
86
|
@host = options[:host]
|
86
87
|
@port = options[:port]
|
87
88
|
|
@@ -107,27 +108,29 @@ module Riemann
|
|
107
108
|
# Using the options from the initializer, a new ::Socket is created that
|
108
109
|
# is:
|
109
110
|
#
|
110
|
-
# TCP,
|
111
|
+
# TCP, autoclosing on exit, nagle's algorithm is disabled and has
|
111
112
|
# TCP Keepalive options set if keepalive is supported.
|
112
113
|
#
|
113
|
-
# Returns a new ::Socket instance
|
114
|
-
def blank_socket
|
115
|
-
sock = ::Socket.new(::Socket::AF_INET, ::Socket::SOCK_STREAM, 0)
|
114
|
+
# Returns a new ::Socket instance for
|
116
115
|
|
117
|
-
|
118
|
-
sock.
|
116
|
+
def socket_factory(type)
|
117
|
+
sock = ::Socket.new(type, ::Socket::SOCK_STREAM, 0)
|
119
118
|
|
119
|
+
# close file descriptors if we exec
|
120
|
+
if Fcntl.constants.include?(:F_SETFD) && Fcntl.constants.include?(:FD_CLOEXEC)
|
121
|
+
sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
122
|
+
end
|
120
123
|
# Disable Nagle's algorithm
|
121
124
|
sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
122
125
|
|
123
|
-
if using_keepalive?
|
124
|
-
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE
|
125
|
-
sock.setsockopt(::Socket::SOL_TCP, ::Socket::TCP_KEEPIDLE
|
126
|
+
if using_keepalive?
|
127
|
+
sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true)
|
128
|
+
sock.setsockopt(::Socket::SOL_TCP, ::Socket::TCP_KEEPIDLE, keepalive_idle)
|
126
129
|
sock.setsockopt(::Socket::SOL_TCP, ::Socket::TCP_KEEPINTVL, keepalive_interval)
|
127
|
-
sock.setsockopt(::Socket::SOL_TCP, ::Socket::TCP_KEEPCNT
|
130
|
+
sock.setsockopt(::Socket::SOL_TCP, ::Socket::TCP_KEEPCNT, keepalive_count)
|
128
131
|
end
|
129
132
|
|
130
|
-
|
133
|
+
sock
|
131
134
|
end
|
132
135
|
|
133
136
|
# Internal: Return the connected raw Socket.
|
@@ -137,7 +140,8 @@ module Riemann
|
|
137
140
|
# Returns a ::Socket
|
138
141
|
def socket
|
139
142
|
return @socket unless closed?
|
140
|
-
|
143
|
+
|
144
|
+
@socket ||= connect
|
141
145
|
end
|
142
146
|
|
143
147
|
# Internal: Closes the internal ::Socket
|
@@ -152,7 +156,8 @@ module Riemann
|
|
152
156
|
def closed?
|
153
157
|
return true if @socket.nil?
|
154
158
|
return true if @socket.closed?
|
155
|
-
|
159
|
+
|
160
|
+
false
|
156
161
|
end
|
157
162
|
|
158
163
|
# Internal:
|
@@ -166,16 +171,17 @@ module Riemann
|
|
166
171
|
# Calculate our timeout deadline
|
167
172
|
deadline = Time.now.to_f + connect_timeout
|
168
173
|
|
169
|
-
# Lookup destination address, we only want
|
170
|
-
addrs = ::Socket.getaddrinfo(host, port,
|
174
|
+
# Lookup destination address, we only want TCP.
|
175
|
+
addrs = ::Socket.getaddrinfo(host, port, nil, ::Socket::SOCK_STREAM)
|
171
176
|
errors = []
|
172
|
-
conn_error =
|
177
|
+
conn_error = -> { raise errors.first }
|
173
178
|
sock = nil
|
174
179
|
|
175
|
-
|
176
|
-
|
180
|
+
# Sort it so we get AF_INET, IPv4
|
181
|
+
addrs.sort.find(conn_error) do |addr|
|
182
|
+
sock = connect_or_error(addr, deadline, errors)
|
177
183
|
end
|
178
|
-
|
184
|
+
sock
|
179
185
|
end
|
180
186
|
|
181
187
|
# Internal: Connect to the destination or raise an error.
|
@@ -192,13 +198,14 @@ module Riemann
|
|
192
198
|
# Should the connection fail, append the exception to the errors array and
|
193
199
|
# return false.
|
194
200
|
#
|
195
|
-
def connect_or_error(
|
201
|
+
def connect_or_error(addr, deadline, errors)
|
196
202
|
timeout = deadline - Time.now.to_f
|
197
203
|
raise Timeout, "Could not connect to #{host}:#{port}" if timeout <= 0
|
198
|
-
|
204
|
+
|
205
|
+
connect_nonblock(addr, timeout)
|
199
206
|
rescue Error => e
|
200
207
|
errors << e
|
201
|
-
|
208
|
+
false
|
202
209
|
end
|
203
210
|
|
204
211
|
# Internal: Connect to the give address within the timeout.
|
@@ -207,36 +214,47 @@ module Riemann
|
|
207
214
|
#
|
208
215
|
# Return the ::Socket when it is connected, or raise an Error if no
|
209
216
|
# connection was possible.
|
210
|
-
def connect_nonblock(
|
217
|
+
def connect_nonblock(addr, timeout)
|
211
218
|
sockaddr = ::Socket.pack_sockaddr_in(addr[1], addr[3])
|
212
|
-
sock =
|
213
|
-
sock.connect_nonblock(
|
214
|
-
|
219
|
+
sock = socket_factory(addr[4])
|
220
|
+
sock.connect_nonblock(sockaddr)
|
221
|
+
sock
|
215
222
|
rescue Errno::EINPROGRESS
|
216
223
|
if IO.select(nil, [sock], nil, timeout).nil?
|
217
|
-
|
224
|
+
begin
|
225
|
+
sock.close
|
226
|
+
rescue StandardError
|
227
|
+
nil
|
228
|
+
end
|
218
229
|
raise Timeout, "Could not connect to #{host}:#{port} within #{timeout} seconds"
|
219
230
|
end
|
220
|
-
|
221
|
-
rescue =>
|
222
|
-
|
223
|
-
|
231
|
+
connect_nonblock_finalize(sock, sockaddr)
|
232
|
+
rescue StandardError => e
|
233
|
+
begin
|
234
|
+
sock.close
|
235
|
+
rescue StandardError
|
236
|
+
nil
|
237
|
+
end
|
238
|
+
raise Error, "Could not connect to #{host}:#{port}: #{e.class}: #{e.message}", e.backtrace
|
224
239
|
end
|
225
240
|
|
226
|
-
|
227
241
|
# Internal: Make sure that a non-blocking connect has truely connected.
|
228
242
|
#
|
229
243
|
# Ensure that the given socket is actually connected to the given adddress.
|
230
244
|
#
|
231
245
|
# Returning the socket if it is and raising an Error if it isn't.
|
232
|
-
def connect_nonblock_finalize(
|
233
|
-
sock.connect_nonblock(
|
234
|
-
|
246
|
+
def connect_nonblock_finalize(sock, sockaddr)
|
247
|
+
sock.connect_nonblock(sockaddr)
|
248
|
+
sock
|
235
249
|
rescue Errno::EISCONN
|
236
|
-
|
237
|
-
rescue =>
|
238
|
-
|
239
|
-
|
250
|
+
sock
|
251
|
+
rescue StandardError => e
|
252
|
+
begin
|
253
|
+
sock.close
|
254
|
+
rescue StandardError
|
255
|
+
nil
|
256
|
+
end
|
257
|
+
raise Error, "Could not connect to #{host}:#{port}: #{e.class}: #{e.message}", e.backtrace
|
240
258
|
end
|
241
259
|
|
242
260
|
# Internal: say if we are using TCP Keep Alive or not
|
@@ -252,12 +270,12 @@ module Riemann
|
|
252
270
|
# Returns true or false
|
253
271
|
def using_keepalive?
|
254
272
|
using = false
|
255
|
-
if keepalive_active?
|
256
|
-
using = [
|
273
|
+
if keepalive_active?
|
274
|
+
using = %i[SOL_SOCKET SO_KEEPALIVE SOL_TCP TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT].all? do |c|
|
257
275
|
::Socket.const_defined? c
|
258
276
|
end
|
259
277
|
end
|
260
|
-
|
278
|
+
using
|
261
279
|
end
|
262
280
|
|
263
281
|
# Reads length bytes from the socket
|
@@ -271,18 +289,18 @@ module Riemann
|
|
271
289
|
outbuf.replace('')
|
272
290
|
buf = outbuf
|
273
291
|
else
|
274
|
-
buf =
|
292
|
+
buf = String.new
|
275
293
|
end
|
276
294
|
|
277
295
|
while buf.length < length
|
278
|
-
unless rb = readpartial(length - buf.length)
|
296
|
+
unless (rb = readpartial(length - buf.length))
|
279
297
|
break
|
280
298
|
end
|
281
299
|
|
282
300
|
buf << rb
|
283
301
|
end
|
284
302
|
|
285
|
-
|
303
|
+
buf
|
286
304
|
end
|
287
305
|
|
288
306
|
# Internal: Read up to a maxlen of data from the socket and store it in outbuf
|
@@ -292,13 +310,13 @@ module Riemann
|
|
292
310
|
#
|
293
311
|
# Returns the bytes read
|
294
312
|
def readpartial(maxlen, outbuf = nil)
|
295
|
-
|
313
|
+
socket.read_nonblock(maxlen, outbuf)
|
296
314
|
rescue Errno::EWOULDBLOCK, Errno::EAGAIN, Errno::ECONNRESET
|
297
|
-
|
298
|
-
retry
|
299
|
-
else
|
315
|
+
unless wait_readable(read_timeout)
|
300
316
|
raise Timeout, "Could not read from #{host}:#{port} in #{read_timeout} seconds"
|
301
317
|
end
|
318
|
+
|
319
|
+
retry
|
302
320
|
end
|
303
321
|
|
304
322
|
# Internal: Write the given data to the socket
|
@@ -310,16 +328,16 @@ module Riemann
|
|
310
328
|
#
|
311
329
|
# returns nothing
|
312
330
|
def write(buf)
|
313
|
-
until buf.nil?
|
331
|
+
until buf.nil? || buf.length.zero?
|
314
332
|
written = socket.write_nonblock(buf)
|
315
333
|
buf = buf[written, buf.length]
|
316
334
|
end
|
317
335
|
rescue Errno::EWOULDBLOCK, Errno::EINTR, Errno::EAGAIN, Errno::ECONNRESET
|
318
|
-
|
319
|
-
retry
|
320
|
-
else
|
336
|
+
unless wait_writable(write_timeout)
|
321
337
|
raise Timeout, "Could not write to #{host}:#{port} in #{write_timeout} seconds"
|
322
338
|
end
|
339
|
+
|
340
|
+
retry
|
323
341
|
end
|
324
342
|
|
325
343
|
def wait_writable(timeout = nil)
|
@@ -331,4 +349,4 @@ module Riemann
|
|
331
349
|
end
|
332
350
|
end
|
333
351
|
end
|
334
|
-
end
|
352
|
+
end
|
data/lib/riemann/client/udp.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Riemann
|
2
4
|
class Client
|
3
5
|
class UDP < Client
|
4
|
-
MAX_SIZE =
|
6
|
+
MAX_SIZE = 16_384
|
5
7
|
|
6
8
|
attr_accessor :host, :port, :max_size
|
7
9
|
|
8
|
-
def initialize(opts = {})
|
10
|
+
def initialize(opts = {}) # rubocop:disable Lint/MissingSuper
|
9
11
|
@host = opts[:host] || HOST
|
10
12
|
@port = opts[:port] || PORT
|
11
13
|
@max_size = opts[:max_size] || MAX_SIZE
|
@@ -13,6 +15,7 @@ module Riemann
|
|
13
15
|
|
14
16
|
def socket
|
15
17
|
return @socket if connected?
|
18
|
+
|
16
19
|
@socket = UDPSocket.new
|
17
20
|
end
|
18
21
|
|
@@ -26,17 +29,18 @@ module Riemann
|
|
26
29
|
end
|
27
30
|
|
28
31
|
# Read a message from a stream
|
29
|
-
def read_message(
|
32
|
+
def read_message(_socket)
|
30
33
|
raise Unsupported
|
31
34
|
end
|
32
35
|
|
33
|
-
def send_recv(
|
36
|
+
def send_recv(_message)
|
34
37
|
raise Unsupported
|
35
38
|
end
|
36
39
|
|
37
40
|
def send_maybe_recv(message)
|
38
41
|
encoded_string = message.encode.to_s
|
39
42
|
raise TooBig unless encoded_string.length < @max_size
|
43
|
+
|
40
44
|
socket.send(encoded_string, 0, @host, @port)
|
41
45
|
nil
|
42
46
|
end
|
data/lib/riemann/client.rb
CHANGED
@@ -1,104 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'riemann'
|
2
4
|
|
3
|
-
|
4
|
-
class
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
module Riemann
|
6
|
+
class Client
|
7
|
+
class Error < RuntimeError; end
|
8
|
+
class InvalidResponse < Error; end
|
9
|
+
class ServerError < Error; end
|
10
|
+
class Unsupported < Error; end
|
11
|
+
class TooBig < Unsupported; end
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
require 'time'
|
13
|
+
require 'socket'
|
14
|
+
require 'time'
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
HOST = '127.0.0.1'
|
17
|
+
PORT = 5555
|
18
|
+
TIMEOUT = 5
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
+
require 'riemann/client/tcp'
|
21
|
+
require 'riemann/client/udp'
|
20
22
|
|
21
|
-
|
23
|
+
attr_reader :tcp, :udp
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
def initialize(opts = {})
|
26
|
+
@options = opts.dup
|
27
|
+
@options[:host] ||= HOST
|
28
|
+
@options[:port] ||= PORT
|
29
|
+
@options[:timeout] ||= TIMEOUT
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
@udp = UDP.new(@options)
|
32
|
+
@tcp = TCP.new(@options)
|
33
|
+
return unless block_given?
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
35
|
+
begin
|
36
|
+
yield self
|
37
|
+
ensure
|
38
|
+
close
|
39
|
+
end
|
40
|
+
end
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
|
42
|
+
def host
|
43
|
+
@options[:host]
|
44
|
+
end
|
40
45
|
|
41
|
-
|
42
|
-
|
43
|
-
|
46
|
+
def port
|
47
|
+
@options[:port]
|
48
|
+
end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
# Create state
|
48
|
-
case event_opts
|
49
|
-
when Riemann::State
|
50
|
-
event = event_opts
|
51
|
-
when Riemann::Event
|
52
|
-
event = event_opts
|
53
|
-
else
|
54
|
-
unless event_opts.include? :host
|
55
|
-
event_opts[:host] = Socket.gethostname
|
56
|
-
end
|
57
|
-
event = Riemann::Event.new(event_opts)
|
50
|
+
def timeout
|
51
|
+
@options[:timeout]
|
58
52
|
end
|
59
53
|
|
60
|
-
|
54
|
+
# Send a state
|
55
|
+
def <<(event_opts)
|
56
|
+
# Create state
|
57
|
+
case event_opts
|
58
|
+
when Riemann::State
|
59
|
+
event = event_opts
|
60
|
+
when Riemann::Event
|
61
|
+
event = event_opts
|
62
|
+
else
|
63
|
+
event_opts[:host] = Socket.gethostname unless event_opts.include? :host
|
64
|
+
event = Riemann::Event.new(event_opts)
|
65
|
+
end
|
61
66
|
|
62
|
-
|
63
|
-
send_maybe_recv message
|
64
|
-
end
|
67
|
+
message = Riemann::Message.new events: [event]
|
65
68
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
(response.events || []) |
|
70
|
-
(response.states || [])
|
71
|
-
end
|
69
|
+
# Transmit
|
70
|
+
send_maybe_recv message
|
71
|
+
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
# Returns an array of states matching query.
|
74
|
+
def [](query)
|
75
|
+
response = query(query)
|
76
|
+
(response.events || []) |
|
77
|
+
(response.states || [])
|
78
|
+
end
|
77
79
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
end
|
80
|
+
def connect
|
81
|
+
# NOTE: connections are made automatically on send
|
82
|
+
warn 'Riemann client#connect is deprecated'
|
83
|
+
end
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
|
85
|
+
# Close both UDP and TCP sockets.
|
86
|
+
def close
|
87
|
+
@udp.close
|
88
|
+
@tcp.close
|
89
|
+
end
|
87
90
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
91
|
+
def connected?
|
92
|
+
tcp.connected? and udp.connected?
|
93
|
+
end
|
92
94
|
|
93
|
-
|
94
|
-
|
95
|
-
|
95
|
+
# Ask for states
|
96
|
+
def query(string = 'true')
|
97
|
+
send_recv Riemann::Message.new(query: Riemann::Query.new(string: string))
|
98
|
+
end
|
99
|
+
|
100
|
+
def send_recv(message)
|
101
|
+
@tcp.send_recv(message)
|
102
|
+
end
|
96
103
|
|
97
|
-
|
98
|
-
|
99
|
-
@udp.send_maybe_recv *a
|
104
|
+
def send_maybe_recv(message)
|
105
|
+
@udp.send_maybe_recv(message)
|
100
106
|
rescue TooBig
|
101
|
-
@tcp.send_maybe_recv
|
107
|
+
@tcp.send_maybe_recv(*a)
|
102
108
|
end
|
103
109
|
end
|
104
110
|
end
|