riemann-client 0.2.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d87901a4f9a48ce3fcae0940d204c36cdabd949d4495b99f2445735fb2deddd8
4
+ data.tar.gz: d64e574731d1a1dce475fb2227eaf2fdd4f3bf581bd20bae33fb92a22321adb2
5
+ SHA512:
6
+ metadata.gz: b75e2bd1256a168dc185ceaf53c80f045e2011fa1fa2e2717147e48c35d65b767df60182884a154575e09598b4305cda0e9cc16c0f5a2d3e0ab3218fc6d4380f
7
+ data.tar.gz: 1b5d7a51402e65c7994b91bd903f2dae9881390ee890058a881311c3bb57bfb12139065c1a0d466c76f2438677789ad8f3347351e26d1005f704f673f8c06025
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: CI
3
+
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+ pull_request:
9
+ branches:
10
+ - main
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ matrix:
17
+ ruby-version:
18
+ - 2.7
19
+ - 3.0
20
+ - 3.1
21
+ steps:
22
+ - uses: actions/checkout@v2
23
+ - name: Setup Ruby
24
+ uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: ${{ matrix.ruby-version }}
27
+ bundler-cache: true
28
+ - name: Install riemann
29
+ run: |
30
+ wget --quiet https://github.com/riemann/riemann/releases/download/0.3.8/riemann_0.3.8_all.deb
31
+ sudo dpkg -i riemann_0.3.8_all.deb
32
+
33
+ sudo systemctl stop riemann
34
+
35
+ sudo openssl genrsa -out /etc/riemann/riemann_server.key 4096
36
+ sudo openssl pkcs8 -topk8 -nocrypt -in /etc/riemann/riemann_server.key -out /etc/riemann/riemann_server.pkcs8
37
+ sudo openssl req -x509 -new -nodes -key /etc/riemann/riemann_server.key -days 7 -out /etc/riemann/riemann_server.crt -subj '/CN=localhost'
38
+ sudo chmod +r /etc/riemann/riemann_server.pkcs8
39
+ sudo cp -v spec/riemann.config /etc/riemann/
40
+
41
+ sudo systemctl start riemann
42
+
43
+ while ! nc -z localhost 5555; do sleep 1; done
44
+ - name: Run the test suite
45
+ run: bundle exec bacon spec/*.rb
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ pkg/
2
+ ._*
3
+ *~
4
+ .DS_Store
5
+ .*.swp
6
+ *.log
7
+ .bundle/
8
+ bin/
9
+ vendor/
10
+ Gemfile.lock
data/CHANGELOG.md ADDED
@@ -0,0 +1,76 @@
1
+ # Changelog
2
+
3
+ ## [1.0.0](https://github.com/riemann/riemann-ruby-client/tree/1.0.0) (2022-06-16)
4
+
5
+ [Full Changelog](https://github.com/riemann/riemann-ruby-client/compare/0.2.6...1.0.0)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Add support for micro-seconds resolution [\#34](https://github.com/riemann/riemann-ruby-client/pull/34) ([smortex](https://github.com/smortex))
10
+ - Add support for TLS [\#33](https://github.com/riemann/riemann-ruby-client/pull/33) ([smortex](https://github.com/smortex))
11
+ - Add support for IPv6 addresses [\#30](https://github.com/riemann/riemann-ruby-client/pull/30) ([dch](https://github.com/dch))
12
+
13
+ **Merged pull requests:**
14
+
15
+ - Fix race conditions in CI [\#35](https://github.com/riemann/riemann-ruby-client/pull/35) ([smortex](https://github.com/smortex))
16
+ - Modernize and setup CI [\#32](https://github.com/riemann/riemann-ruby-client/pull/32) ([smortex](https://github.com/smortex))
17
+ - Bump beefcake dependency [\#29](https://github.com/riemann/riemann-ruby-client/pull/29) ([dch](https://github.com/dch))
18
+
19
+ ## [0.2.6](https://github.com/riemann/riemann-ruby-client/tree/0.2.6) (2015-11-18)
20
+
21
+ [Full Changelog](https://github.com/riemann/riemann-ruby-client/compare/0.2.5...0.2.6)
22
+
23
+ **Merged pull requests:**
24
+
25
+ - Client should yield self [\#22](https://github.com/riemann/riemann-ruby-client/pull/22) ([agile](https://github.com/agile))
26
+ - Allow TCP sockets to work on Windows [\#21](https://github.com/riemann/riemann-ruby-client/pull/21) ([sgran](https://github.com/sgran))
27
+ - README hash syntax fix [\#20](https://github.com/riemann/riemann-ruby-client/pull/20) ([squarism](https://github.com/squarism))
28
+
29
+ ## [0.2.5](https://github.com/riemann/riemann-ruby-client/tree/0.2.5) (2015-02-05)
30
+
31
+ [Full Changelog](https://github.com/riemann/riemann-ruby-client/compare/0.2.4...0.2.5)
32
+
33
+ ## [0.2.4](https://github.com/riemann/riemann-ruby-client/tree/0.2.4) (2015-02-03)
34
+
35
+ [Full Changelog](https://github.com/riemann/riemann-ruby-client/compare/0.2.2...0.2.4)
36
+
37
+ **Merged pull requests:**
38
+
39
+ - Tightening beefcake requirement [\#19](https://github.com/riemann/riemann-ruby-client/pull/19) ([aphyr](https://github.com/aphyr))
40
+ - Fix for \#17, plus test and connection refactor [\#18](https://github.com/riemann/riemann-ruby-client/pull/18) ([RKelln](https://github.com/RKelln))
41
+ - Ensure that we close the connection if we got an error back [\#16](https://github.com/riemann/riemann-ruby-client/pull/16) ([eric](https://github.com/eric))
42
+ - String\#clear doesn't exist in 1.8 [\#15](https://github.com/riemann/riemann-ruby-client/pull/15) ([eric](https://github.com/eric))
43
+ - Tcp client with timeouts [\#14](https://github.com/riemann/riemann-ruby-client/pull/14) ([eric](https://github.com/eric))
44
+
45
+ ## [0.2.2](https://github.com/riemann/riemann-ruby-client/tree/0.2.2) (2013-05-28)
46
+
47
+ [Full Changelog](https://github.com/riemann/riemann-ruby-client/compare/0.2.0...0.2.2)
48
+
49
+ **Merged pull requests:**
50
+
51
+ - Update README with timeout information [\#11](https://github.com/riemann/riemann-ruby-client/pull/11) ([gsandie](https://github.com/gsandie))
52
+ - Add tcp socket timeouts [\#10](https://github.com/riemann/riemann-ruby-client/pull/10) ([gsandie](https://github.com/gsandie))
53
+ - Socket can not be opened in method connected? [\#9](https://github.com/riemann/riemann-ruby-client/pull/9) ([vadv](https://github.com/vadv))
54
+
55
+ ## [0.2.0](https://github.com/riemann/riemann-ruby-client/tree/0.2.0) (2013-04-02)
56
+
57
+ [Full Changelog](https://github.com/riemann/riemann-ruby-client/compare/version-0.0.7...0.2.0)
58
+
59
+ **Merged pull requests:**
60
+
61
+ - Get and set attributes using hash-style accessors [\#8](https://github.com/riemann/riemann-ruby-client/pull/8) ([jegt](https://github.com/jegt))
62
+ - Add extra attributes added to the Event constructor to the event as Attribute instances [\#7](https://github.com/riemann/riemann-ruby-client/pull/7) ([jegt](https://github.com/jegt))
63
+ - Change attribute name to attribute key [\#6](https://github.com/riemann/riemann-ruby-client/pull/6) ([b](https://github.com/b))
64
+ - Arbitrary attributes on events [\#5](https://github.com/riemann/riemann-ruby-client/pull/5) ([b](https://github.com/b))
65
+
66
+ ## [version-0.0.7](https://github.com/riemann/riemann-ruby-client/tree/version-0.0.7) (2012-04-16)
67
+
68
+ [Full Changelog](https://github.com/riemann/riemann-ruby-client/compare/fe25a3b01681612defc39250006748069e06a172...version-0.0.7)
69
+
70
+ **Merged pull requests:**
71
+
72
+ - Add support for ruby 1.8 [\#1](https://github.com/riemann/riemann-ruby-client/pull/1) ([eric](https://github.com/eric))
73
+
74
+
75
+
76
+ \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'github_changelog_generator'
data/README.markdown CHANGED
@@ -48,8 +48,8 @@ faster than TCP, but you will not know if the server is down or encountered an
48
48
  error. You can specify what transport to use by selecting a subclient:
49
49
 
50
50
  ``` ruby
51
- c.udp << { :state "ok" } # => nil
52
- c.tcp << { :state "ok" } # => #<Message ...>
51
+ c.udp << { :state => "ok" } # => nil
52
+ c.tcp << { :state => "ok" } # => #<Message ...>
53
53
  c.tcp["true"] # => [#<Event ... >, ...]
54
54
  c.udp["true"] # => raise Riemann::Client::Unsupported
55
55
  ```
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'riemann'
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ require 'github_changelog_generator/task'
6
+
7
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
8
+ config.user = 'riemann'
9
+ config.project = 'riemann-ruby-client'
10
+ config.future_release = Riemann::VERSION
11
+ config.add_issues_wo_labels = false
12
+ end
@@ -0,0 +1,91 @@
1
+ require 'openssl'
2
+ require_relative 'tcp_socket'
3
+
4
+ module Riemann
5
+ class Client
6
+ # Socket: A specialized socket that has been configure
7
+ class SSLSocket < TcpSocket
8
+
9
+ def initialize(options = {})
10
+ super(options)
11
+ @key_file = options[:key_file]
12
+ @cert_file = options[:cert_file]
13
+ @ca_file = options[:ca_file]
14
+ @ssl_verify = options[:ssl_verify]
15
+ end
16
+
17
+ def ssl_context
18
+ @ssl_context ||= OpenSSL::SSL::SSLContext.new.tap do |ctx|
19
+ ctx.key = OpenSSL::PKey::RSA.new(open(@key_file) {|f| f.read})
20
+ ctx.cert = OpenSSL::X509::Certificate.new(open(@cert_file) {|f| f.read})
21
+ ctx.ca_file = @ca_file if @ca_file
22
+ ctx.ssl_version = :TLSv1_2
23
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER if @ssl_verify
24
+ end
25
+ end
26
+
27
+ # Internal: Connect to the give address within the timeout.
28
+ #
29
+ # Make an attempt to connect to a single address within the given timeout.
30
+ #
31
+ # Return the ::Socket when it is connected, or raise an Error if no
32
+ # connection was possible.
33
+ def connect_nonblock( addr, timeout )
34
+ sock = super(addr, timeout)
35
+ ssl_socket = OpenSSL::SSL::SSLSocket.new(sock, ssl_context)
36
+ ssl_socket.sync = true
37
+
38
+ begin
39
+ ssl_socket.connect_nonblock
40
+ rescue IO::WaitReadable
41
+ if IO.select([ssl_socket], nil, nil, timeout)
42
+ retry
43
+ else
44
+ raise Timeout, "Could not read from #{host}:#{port} in #{timeout} seconds"
45
+ end
46
+ rescue IO::WaitWritable
47
+ if IO.select(nil, [ssl_socket], nil, timeout)
48
+ retry
49
+ else
50
+ raise Timeout, "Could not write to #{host}:#{port} in #{timeout} seconds"
51
+ end
52
+ end
53
+ ssl_socket
54
+ end
55
+
56
+ # Internal: Read up to a maxlen of data from the socket and store it in outbuf
57
+ #
58
+ # maxlen - the maximum number of bytes to read from the socket
59
+ # outbuf - the buffer in which to store the bytes.
60
+ #
61
+ # Returns the bytes read
62
+ def readpartial(maxlen, outbuf = nil)
63
+ return super(maxlen, outbuf)
64
+ rescue OpenSSL::SSL::SSLErrorWaitReadable
65
+ if wait_readable(read_timeout)
66
+ retry
67
+ else
68
+ raise Timeout, "Could not read from #{host}:#{port} in #{read_timeout} seconds"
69
+ end
70
+ end
71
+
72
+ # Internal: Write the given data to the socket
73
+ #
74
+ # buf - the data to write to the socket.
75
+ #
76
+ # Raises an error if it is unable to write the data to the socket within the
77
+ # write_timeout.
78
+ #
79
+ # returns nothing
80
+ def write(buf)
81
+ super(buf)
82
+ rescue OpenSSL::SSL::SSLErrorWaitWritable
83
+ if wait_writable(write_timeout)
84
+ retry
85
+ else
86
+ raise Timeout, "Could not write to #{host}:#{port} in #{write_timeout} seconds"
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,5 +1,6 @@
1
1
  require 'monitor'
2
2
  require 'riemann/client/tcp_socket'
3
+ require 'riemann/client/ssl_socket'
3
4
 
4
5
  module Riemann
5
6
  class Client
@@ -14,7 +15,13 @@ module Riemann
14
15
 
15
16
  # Public: Return a socket factory
16
17
  def self.socket_factory
17
- @socket_factory || proc { |options| TcpSocket.connect(options) }
18
+ @socket_factory || proc { |options|
19
+ if options[:ssl]
20
+ SSLSocket.connect(options)
21
+ else
22
+ TcpSocket.connect(options)
23
+ end
24
+ }
18
25
  end
19
26
 
20
27
  def initialize(options = {})
@@ -107,16 +107,18 @@ module Riemann
107
107
  # Using the options from the initializer, a new ::Socket is created that
108
108
  # is:
109
109
  #
110
- # TCP, IPv4 only, autoclosing on exit, nagle's algorithm is disabled and has
110
+ # TCP, autoclosing on exit, nagle's algorithm is disabled and has
111
111
  # TCP Keepalive options set if keepalive is supported.
112
112
  #
113
- # Returns a new ::Socket instance
114
- def blank_socket
115
- sock = ::Socket.new(::Socket::AF_INET, ::Socket::SOCK_STREAM, 0)
113
+ # Returns a new ::Socket instance for
116
114
 
117
- # close file descriptors if we exec
118
- sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
115
+ def socket_factory(type)
116
+ sock = ::Socket.new(type, ::Socket::SOCK_STREAM, 0)
119
117
 
118
+ # close file descriptors if we exec
119
+ if Fcntl.constants.include?(:F_SETFD) && Fcntl.constants.include?(:FD_CLOEXEC)
120
+ sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
121
+ end
120
122
  # Disable Nagle's algorithm
121
123
  sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
122
124
 
@@ -166,13 +168,14 @@ module Riemann
166
168
  # Calculate our timeout deadline
167
169
  deadline = Time.now.to_f + connect_timeout
168
170
 
169
- # Lookup destination address, we only want IPv4 , TCP
170
- addrs = ::Socket.getaddrinfo(host, port, ::Socket::AF_INET, ::Socket::SOCK_STREAM )
171
+ # Lookup destination address, we only want TCP.
172
+ addrs = ::Socket.getaddrinfo(host, port, nil, ::Socket::SOCK_STREAM )
171
173
  errors = []
172
174
  conn_error = lambda { raise errors.first }
173
175
  sock = nil
174
176
 
175
- addrs.find( conn_error ) do |addr|
177
+ # Sort it so we get AF_INET, IPv4
178
+ addrs.sort.find( conn_error ) do |addr|
176
179
  sock = connect_or_error( addr, deadline, errors )
177
180
  end
178
181
  return sock
@@ -209,7 +212,7 @@ module Riemann
209
212
  # connection was possible.
210
213
  def connect_nonblock( addr, timeout )
211
214
  sockaddr = ::Socket.pack_sockaddr_in(addr[1], addr[3])
212
- sock = blank_socket()
215
+ sock = self.socket_factory( addr[4] )
213
216
  sock.connect_nonblock( sockaddr )
214
217
  return sock
215
218
  rescue Errno::EINPROGRESS
@@ -331,4 +334,4 @@ module Riemann
331
334
  end
332
335
  end
333
336
  end
334
- end
337
+ end
@@ -28,6 +28,13 @@ class Riemann::Client
28
28
 
29
29
  @udp = UDP.new(@options)
30
30
  @tcp = TCP.new(@options)
31
+ if block_given?
32
+ begin
33
+ yield self
34
+ ensure
35
+ close
36
+ end
37
+ end
31
38
  end
32
39
 
33
40
  def host
data/lib/riemann/event.rb CHANGED
@@ -11,6 +11,7 @@ module Riemann
11
11
  repeated :tags, :string, 7
12
12
  optional :ttl, :float, 8
13
13
  repeated :attributes, Attribute, 9
14
+ optional :time_micros, :int64, 10
14
15
 
15
16
  optional :metric_sint64, :sint64, 13
16
17
  optional :metric_d, :double, 14
@@ -27,6 +28,10 @@ module Riemann
27
28
  set << field
28
29
  end
29
30
 
31
+ def self.now
32
+ (Time.now.to_f * 1_000_000).to_i
33
+ end
34
+
30
35
  # Average a set of states together. Chooses the mean metric, the mode
31
36
  # state, mode service, and the mean time. If init is provided, its values
32
37
  # override (where present) the computed ones.
@@ -51,12 +56,12 @@ module Riemann
51
56
  init.service ||= mode states.map(&:service)
52
57
 
53
58
  # Time
54
- init.time = begin
55
- times = states.map(&:time).compact
59
+ init.time_micros = begin
60
+ times = states.map(&:time_micros).compact
56
61
  (times.inject(:+) / times.size).to_i
57
62
  rescue
58
63
  end
59
- init.time ||= Time.now.to_i
64
+ init.time_micros ||= now
60
65
 
61
66
  init
62
67
  end
@@ -85,12 +90,12 @@ module Riemann
85
90
  init.service ||= mode states.map(&:service)
86
91
 
87
92
  # Time
88
- init.time = begin
89
- times = states.map(&:time).compact
93
+ init.time_micros = begin
94
+ times = states.map(&:time_micros).compact
90
95
  (times.inject(:+) / times.size).to_i
91
96
  rescue
92
97
  end
93
- init.time ||= Time.now.to_i
98
+ init.time_micros ||= now
94
99
 
95
100
  init
96
101
  end
@@ -119,12 +124,12 @@ module Riemann
119
124
  end
120
125
 
121
126
  # Time
122
- init.time = begin
123
- times = states.map(&:time).compact
127
+ init.time_micros = begin
128
+ times = states.map(&:time_micros).compact
124
129
  (times.inject(:+) / times.size).to_i
125
130
  rescue
126
131
  end
127
- init.time ||= Time.now.to_i
132
+ init.time_micros ||= now
128
133
 
129
134
  init
130
135
  end
@@ -186,7 +191,7 @@ module Riemann
186
191
  super()
187
192
  end
188
193
 
189
- @time ||= Time.now.to_i
194
+ @time_micros ||= self.class.now unless @time
190
195
  end
191
196
 
192
197
  def metric
@@ -1,3 +1,3 @@
1
1
  module Riemann
2
- VERSION = '0.2.4'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'riemann/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'riemann-client'
8
+ spec.version = Riemann::VERSION
9
+ spec.author = 'Kyle Kingsbury'
10
+ spec.email = 'aphyr@aphyr.com'
11
+ spec.summary = 'Client for the distributed event system Riemann.'
12
+ spec.description = 'Client for the distributed event system Riemann.'
13
+ spec.homepage = 'https://github.com/aphyr/riemann-ruby-client'
14
+ spec.license = 'MIT'
15
+ spec.platform = Gem::Platform::RUBY
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.required_ruby_version = '>= 2.7.0'
23
+
24
+ spec.add_development_dependency 'bundler', '>= 1.3'
25
+ spec.add_development_dependency 'bacon'
26
+ spec.add_development_dependency 'timecop'
27
+
28
+ spec.add_dependency 'beefcake', ['>= 1.0.0 ']
29
+ spec.add_dependency 'mtrc', '>= 0.0.4'
30
+ end
data/spec/client.rb ADDED
@@ -0,0 +1,384 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # How to run the bacon tests:
4
+ # 1. Start Riemann using the config from riemann.config
5
+ # 2. $ bundle exec bacon spec/client.rb
6
+
7
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'riemann'))
8
+ require 'riemann/client'
9
+ require 'bacon'
10
+ require 'set'
11
+ require 'timecop'
12
+
13
+ Bacon.summary_on_exit
14
+
15
+ include Riemann
16
+
17
+ INACTIVITY_TIME = 5
18
+
19
+ def wait_for(&block)
20
+ tries = 0
21
+ while tries < 30
22
+ tries += 1
23
+ begin
24
+ res = block.call
25
+ return res if res
26
+ rescue NoMethodError
27
+ # If a query returns no result (#query retruns nil or #[] returns []),
28
+ # calling #first on it will raise a NoMethodError. We can ignore it for
29
+ # these tests.
30
+ end
31
+ sleep(0.1)
32
+ end
33
+
34
+ raise "wait_for condition never realized"
35
+ end
36
+
37
+ def roundtrip_metric(m)
38
+ @client_with_transport << {
39
+ :service => 'metric-test',
40
+ :metric => m
41
+ }
42
+
43
+ wait_for {@client["service = \"metric-test\" and metric = #{m}"].first }.
44
+ metric.should.equal m
45
+ end
46
+
47
+ def truthy
48
+ lambda { |obj| !(obj.nil? || obj == false) }
49
+ end
50
+
51
+ def falsey
52
+ lambda { |obj| obj.nil? || obj == false }
53
+ end
54
+
55
+ shared "a riemann client" do
56
+
57
+ should 'yield itself to given block' do
58
+ client = nil
59
+ Client.new(:host => "localhost", :port => 5555) do |c|
60
+ client = c
61
+ end
62
+ client.should.be.kind_of?(Client)
63
+ client.should.not.be.connected
64
+ end
65
+
66
+ should 'close sockets if given a block that raises' do
67
+ client = nil
68
+ begin
69
+ Client.new(:host => "localhost", :port => 5555) do |c|
70
+ client = c
71
+ raise "The Boom"
72
+ end
73
+ rescue
74
+ # swallow the exception
75
+ end
76
+ client.should.be.kind_of?(Client)
77
+ client.should.not.be.connected
78
+ end
79
+
80
+ should 'be connected after sending' do
81
+ @client_with_transport.connected?.should.be falsey
82
+ @client.connected?.should.be falsey
83
+ @client_with_transport << {:state => 'ok', :service => 'connected check' }
84
+ @client_with_transport.connected?.should.be truthy
85
+ # NOTE: only single transport connected at this point, @client.connected? is still false until all transports used
86
+ end
87
+
88
+ should 'send longs' do
89
+ roundtrip_metric(0)
90
+ roundtrip_metric(-3)
91
+ roundtrip_metric(5)
92
+ roundtrip_metric(-(2**63))
93
+ roundtrip_metric(2**63 - 1)
94
+ end
95
+
96
+ should 'send doubles' do
97
+ roundtrip_metric 0.0
98
+ roundtrip_metric 12.0
99
+ roundtrip_metric 1.2300000190734863
100
+ end
101
+
102
+ should 'send custom attributes' do
103
+ event = Event.new(
104
+ :service => 'custom',
105
+ :state => 'ok',
106
+ :cats => 'meow',
107
+ :env => 'prod'
108
+ )
109
+ event[:sneak] = 'attack'
110
+ @client_with_transport << event
111
+ event2 = wait_for { @client['service = "custom"'].first }
112
+ event2.service.should.equal 'custom'
113
+ event2.state.should.equal 'ok'
114
+ event2[:cats].should.equal 'meow'
115
+ event2[:env].should.equal 'prod'
116
+ event2[:sneak].should.equal 'attack'
117
+ end
118
+
119
+ should 'send a state with a time' do
120
+ Timecop.freeze do
121
+ t = (Time.now - 10).to_i
122
+ @client_with_transport << {
123
+ :state => 'ok',
124
+ :service => 'test',
125
+ :time => t
126
+ }
127
+ wait_for { @client.query('service = "test"').events.first.time == t }
128
+ e = @client.query('service = "test"').events.first
129
+ e.time.should.equal t
130
+ e.time_micros.should.equal t * 1_000_000
131
+ end
132
+ end
133
+
134
+ should 'send a state with a time_micros' do
135
+ Timecop.freeze do
136
+ t = ((Time.now - 10).to_f * 1_000_000).to_i
137
+ @client_with_transport << {
138
+ :state => 'ok',
139
+ :service => 'test',
140
+ :time_micros => t
141
+ }
142
+ wait_for { @client.query('service = "test"').events.first.time_micros == t }
143
+ e = @client.query('service = "test"').events.first
144
+ e.time.should.equal (Time.now - 10).to_i
145
+ e.time_micros.should.equal t
146
+ end
147
+ end
148
+
149
+ should 'send a state without time nor time_micros' do
150
+ time_before = (Time.now.to_f * 1_000_000).to_i
151
+ @client_with_transport << {
152
+ :state => 'ok',
153
+ :service => 'timeless test'
154
+ }
155
+ wait_for { @client.query('service = "timeless test"').events.first.time_micros >= time_before }
156
+ e = @client.query('service = "timeless test"').events.first
157
+ time_after = (Time.now.to_f * 1_000_000).to_i
158
+
159
+ [time_before, e.time_micros, time_after].sort.should.equal([time_before, e.time_micros, time_after])
160
+ end
161
+
162
+ should "query states" do
163
+ @client_with_transport << { :state => 'critical', :service => '1' }
164
+ @client_with_transport << { :state => 'warning', :service => '2' }
165
+ @client_with_transport << { :state => 'critical', :service => '3' }
166
+ wait_for { @client.query('service = "3"').events.first }
167
+ @client.query.events.
168
+ map(&:service).to_set.should.superset ['1', '2', '3'].to_set
169
+ @client.query('state = "critical" and (service = "1" or service = "2" or service = "3")').events.
170
+ map(&:service).to_set.should.equal ['1', '3'].to_set
171
+ end
172
+
173
+ it '[]' do
174
+ # @client['state = "critical"'].should == []
175
+ @client_with_transport << {:state => 'critical'}
176
+ wait_for { @client['state = "critical"'].first }.state.should.equal 'critical'
177
+ end
178
+
179
+ should 'query quickly' do
180
+ t1 = Time.now
181
+ total = 1000
182
+ total.times do |i|
183
+ @client.query('state = "critical"')
184
+ end
185
+ t2 = Time.now
186
+
187
+ rate = total / (t2 - t1)
188
+ puts "\n #{"%.2f" % rate} queries/sec (#{"%.2f" % (1000/rate)}ms per query)"
189
+ rate.should > 100
190
+ end
191
+
192
+ should 'be threadsafe' do
193
+ concurrency = 10
194
+ per_thread = 200
195
+ total = concurrency * per_thread
196
+
197
+ t1 = Time.now
198
+ (0...concurrency).map do |i|
199
+ Thread.new do
200
+ per_thread.times do
201
+ @client_with_transport.<<({
202
+ :state => 'ok',
203
+ :service => 'test',
204
+ :description => 'desc',
205
+ :metric_f => 1.0
206
+ })
207
+ end
208
+ end
209
+ end.each do |t|
210
+ t.join
211
+ end
212
+ t2 = Time.now
213
+
214
+ rate = total / (t2 - t1)
215
+ puts "\n #{"%.2f" % rate} inserts/sec (#{"%.2f" % (1000/rate)}ms per insert)"
216
+ rate.should > @expected_rate
217
+ end
218
+
219
+ end
220
+
221
+ describe "Riemann::Client (TLS transport)" do
222
+ before do
223
+ @client = Client.new(:host => "localhost", :port => 5554, :ssl => true, :key_file => '/etc/riemann/riemann_server.pkcs8', :cert_file => '/etc/riemann/riemann_server.crt', :ca_file => '/etc/riemann/riemann_server.crt', :ssl_verify => true)
224
+ @client_with_transport = @client.tcp
225
+ @expected_rate = 100
226
+ end
227
+ behaves_like "a riemann client"
228
+
229
+ should 'send a state' do
230
+ res = @client_with_transport << {
231
+ :state => 'ok',
232
+ :service => 'test',
233
+ :description => 'desc',
234
+ :metric_f => 1.0
235
+ }
236
+
237
+ res.ok.should.be truthy
238
+ wait_for { @client['service = "test"'].first }.state.should.equal 'ok'
239
+ end
240
+
241
+ should 'survive inactivity' do
242
+ @client_with_transport.<<({
243
+ :state => 'warning',
244
+ :service => 'survive TCP inactivity',
245
+ })
246
+ wait_for { @client['service = "survive TCP inactivity"'].first.state == 'warning' }
247
+
248
+ sleep INACTIVITY_TIME
249
+
250
+ @client_with_transport.<<({
251
+ :state => 'ok',
252
+ :service => 'survive TCP inactivity',
253
+ }).ok.should.be truthy
254
+ wait_for { @client['service = "survive TCP inactivity"'].first.state == 'ok' }
255
+ end
256
+
257
+ should 'survive local close' do
258
+ @client_with_transport.<<({
259
+ :state => 'warning',
260
+ :service => 'survive TCP local close',
261
+ }).ok.should.be truthy
262
+ wait_for { @client['service = "survive TCP local close"'].first .state == 'warning' }
263
+
264
+ @client.close
265
+
266
+ @client_with_transport.<<({
267
+ :state => 'ok',
268
+ :service => 'survive TCP local close',
269
+ }).ok.should.be truthy
270
+ wait_for { @client['service = "survive TCP local close"'].first.state == 'ok' }
271
+ end
272
+ end
273
+
274
+ describe "Riemann::Client (TCP transport)" do
275
+ before do
276
+ @client = Client.new(:host => "localhost", :port => 5555)
277
+ @client_with_transport = @client.tcp
278
+ @expected_rate = 100
279
+ end
280
+ behaves_like "a riemann client"
281
+
282
+ should 'send a state' do
283
+ res = @client_with_transport << {
284
+ :state => 'ok',
285
+ :service => 'test',
286
+ :description => 'desc',
287
+ :metric_f => 1.0
288
+ }
289
+
290
+ res.ok.should.be truthy
291
+ wait_for { @client['service = "test"'].first }.state.should.equal 'ok'
292
+ end
293
+
294
+ should 'survive inactivity' do
295
+ @client_with_transport.<<({
296
+ :state => 'warning',
297
+ :service => 'survive TCP inactivity',
298
+ })
299
+ wait_for { @client['service = "survive TCP inactivity"'].first.state == 'warning' }
300
+
301
+ sleep INACTIVITY_TIME
302
+
303
+ @client_with_transport.<<({
304
+ :state => 'ok',
305
+ :service => 'survive TCP inactivity',
306
+ }).ok.should.be truthy
307
+ wait_for { @client['service = "survive TCP inactivity"'].first.state == 'ok' }
308
+ end
309
+
310
+ should 'survive local close' do
311
+ @client_with_transport.<<({
312
+ :state => 'warning',
313
+ :service => 'survive TCP local close',
314
+ }).ok.should.be truthy
315
+ wait_for { @client['service = "survive TCP local close"'].first.state == 'warning' }
316
+
317
+ @client.close
318
+
319
+ @client_with_transport.<<({
320
+ :state => 'ok',
321
+ :service => 'survive TCP local close',
322
+ }).ok.should.be truthy
323
+ wait_for { @client['service = "survive TCP local close"'].first.state == 'ok' }
324
+ end
325
+ end
326
+
327
+ describe "Riemann::Client (UDP transport)" do
328
+ before do
329
+ @client = Client.new(:host => "localhost", :port => 5555)
330
+ @client_with_transport = @client.udp
331
+ @expected_rate = 1000
332
+ end
333
+ behaves_like "a riemann client"
334
+
335
+ should 'send a state' do
336
+ res = @client_with_transport << {
337
+ :state => 'ok',
338
+ :service => 'test',
339
+ :description => 'desc',
340
+ :metric_f => 1.0
341
+ }
342
+
343
+ res.should.be.nil
344
+ wait_for { @client['service = "test"'].first }.state.should.equal 'ok'
345
+ end
346
+
347
+ should 'survive inactivity' do
348
+ @client_with_transport.<<({
349
+ :state => 'warning',
350
+ :service => 'survive UDP inactivity',
351
+ }).should.be.nil
352
+ wait_for { @client['service = "survive UDP inactivity"'].first.state == 'warning' }
353
+
354
+ sleep INACTIVITY_TIME
355
+
356
+ @client_with_transport.<<({
357
+ :state => 'ok',
358
+ :service => 'survive UDP inactivity',
359
+ }).should.be.nil
360
+ wait_for { @client['service = "survive UDP inactivity"'].first.state == 'ok' }
361
+ end
362
+
363
+ should 'survive local close' do
364
+ @client_with_transport.<<({
365
+ :state => 'warning',
366
+ :service => 'survive UDP local close',
367
+ }).should.be.nil
368
+ wait_for { @client['service = "survive UDP local close"'].first.state == 'warning' }
369
+
370
+ @client.close
371
+
372
+ @client_with_transport.<<({
373
+ :state => 'ok',
374
+ :service => 'survive UDP local close',
375
+ }).should.be.nil
376
+ wait_for { @client['service = "survive UDP local close"'].first.state == 'ok' }
377
+ end
378
+
379
+ should "raise Riemann::Client::Unsupported exception on query" do
380
+ should.raise(Riemann::Client::Unsupported) { @client_with_transport['service = "test"'] }
381
+ should.raise(Riemann::Client::Unsupported) { @client_with_transport.query('service = "test"') }
382
+ end
383
+
384
+ end
@@ -0,0 +1,30 @@
1
+ ; -*- mode: clojure; -*-
2
+ ; vim: filetype=clojure
3
+
4
+ (logging/init {:file "/var/log/riemann/riemann.log"})
5
+
6
+ ; Listen on the local interface over TCP (5555), UDP (5555), websockets
7
+ ; (5556) and TLS (5554)
8
+ (let [host "127.0.0.1"]
9
+ (tcp-server {:host host})
10
+ (udp-server {:host host})
11
+ (ws-server {:host host})
12
+ (tcp-server {:host host :port 5554 :tls? true :key "/etc/riemann/riemann_server.pkcs8" :cert "/etc/riemann/riemann_server.crt" :ca-cert "/etc/riemann/riemann_server.crt"}))
13
+
14
+ ; Expire old events from the index every 5 seconds.
15
+ (periodically-expire 5)
16
+
17
+ (let [index (index)]
18
+ ; Inbound events will be passed to these streams:
19
+ (streams
20
+ (default :ttl 60
21
+ ; Index all events immediately.
22
+ ;index
23
+
24
+ ; Index all events after a delay.
25
+ (batch 1000 1/10
26
+ (sflatten index))
27
+
28
+ ; Log expired events.
29
+ (expired
30
+ (fn [event] (info "expired" event))))))
metadata CHANGED
@@ -1,74 +1,103 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riemann-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
5
- prerelease:
4
+ version: 1.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Kyle Kingsbury
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2015-02-03 00:00:00.000000000 Z
11
+ date: 2022-06-16 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: beefcake
14
+ name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
- version: 0.3.5
22
- type: :runtime
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bacon
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
23
35
  prerelease: false
24
36
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
37
  requirements:
27
- - - ! '>='
38
+ - - ">="
28
39
  - !ruby/object:Gem::Version
29
- version: 0.3.5
40
+ version: '0'
30
41
  - !ruby/object:Gem::Dependency
31
- name: trollop
42
+ name: timecop
32
43
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
44
  requirements:
35
- - - ! '>='
45
+ - - ">="
36
46
  - !ruby/object:Gem::Version
37
- version: 1.16.2
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: beefcake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.0.0
38
62
  type: :runtime
39
63
  prerelease: false
40
64
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
65
  requirements:
43
- - - ! '>='
66
+ - - ">="
44
67
  - !ruby/object:Gem::Version
45
- version: 1.16.2
68
+ version: 1.0.0
46
69
  - !ruby/object:Gem::Dependency
47
70
  name: mtrc
48
71
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
72
  requirements:
51
- - - ! '>='
73
+ - - ">="
52
74
  - !ruby/object:Gem::Version
53
75
  version: 0.0.4
54
76
  type: :runtime
55
77
  prerelease: false
56
78
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
79
  requirements:
59
- - - ! '>='
80
+ - - ">="
60
81
  - !ruby/object:Gem::Version
61
82
  version: 0.0.4
62
- description:
83
+ description: Client for the distributed event system Riemann.
63
84
  email: aphyr@aphyr.com
64
85
  executables: []
65
86
  extensions: []
66
87
  extra_rdoc_files: []
67
88
  files:
89
+ - ".github/workflows/ci.yml"
90
+ - ".gitignore"
91
+ - CHANGELOG.md
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.markdown
95
+ - Rakefile
68
96
  - lib/riemann.rb
69
97
  - lib/riemann/attribute.rb
70
98
  - lib/riemann/auto_state.rb
71
99
  - lib/riemann/client.rb
100
+ - lib/riemann/client/ssl_socket.rb
72
101
  - lib/riemann/client/tcp.rb
73
102
  - lib/riemann/client/tcp_socket.rb
74
103
  - lib/riemann/client/udp.rb
@@ -78,30 +107,32 @@ files:
78
107
  - lib/riemann/query.rb
79
108
  - lib/riemann/state.rb
80
109
  - lib/riemann/version.rb
81
- - LICENSE
82
- - README.markdown
110
+ - riemann-client.gemspec
111
+ - spec/client.rb
112
+ - spec/riemann.config
83
113
  homepage: https://github.com/aphyr/riemann-ruby-client
84
- licenses: []
114
+ licenses:
115
+ - MIT
116
+ metadata: {}
85
117
  post_install_message:
86
118
  rdoc_options: []
87
119
  require_paths:
88
120
  - lib
89
121
  required_ruby_version: !ruby/object:Gem::Requirement
90
- none: false
91
122
  requirements:
92
- - - ! '>='
123
+ - - ">="
93
124
  - !ruby/object:Gem::Version
94
- version: 1.8.7
125
+ version: 2.7.0
95
126
  required_rubygems_version: !ruby/object:Gem::Requirement
96
- none: false
97
127
  requirements:
98
- - - ! '>='
128
+ - - ">="
99
129
  - !ruby/object:Gem::Version
100
130
  version: '0'
101
131
  requirements: []
102
- rubyforge_project: riemann-client
103
- rubygems_version: 1.8.25
132
+ rubygems_version: 3.2.5
104
133
  signing_key:
105
- specification_version: 3
134
+ specification_version: 4
106
135
  summary: Client for the distributed event system Riemann.
107
- test_files: []
136
+ test_files:
137
+ - spec/client.rb
138
+ - spec/riemann.config