kingkong 0.0.3 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4bfaec9396fa86c7c0484de4dd88affae2e9c035bb0d852b636c17984ed1cc75
4
+ data.tar.gz: 65422b13ae9bc35a30142fd6122f1e39ff7bdf6c54540a0883b782df2dba55c7
5
+ SHA512:
6
+ metadata.gz: f12defa32b00eb145534d1e646fc75ccf4b8c3e2303fb83df711b7c3d93e0a5e42c202d54de491a3b48b85b38e2ef299def35fe3985e2474b05439784ae469d1
7
+ data.tar.gz: 7b5a3082d15e447ae822880d2b510e43afd52ebd6e236d948848814f4df0cc3230162a4a9008ce8d608136dd6cdd5b893256e7620fccee9fcb6f548651ce252c
@@ -0,0 +1 @@
1
+ 1.9.2-p290
data/Gemfile CHANGED
@@ -1,17 +1,4 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in kingkong.gemspec
4
- gemspec
5
-
6
- gem 'em-http-request'
7
- gem 'json'
8
-
9
- group :test, :development do
10
- gem 'rspec'
11
- gem 'guard-rspec'
12
- gem 'growl'
13
- gem 'rb-fsevent'
14
- gem 'em-ventually'
15
- gem 'timecop'
16
- gem 'ruby-debug19'
17
- end
4
+ gemspec
data/README.md CHANGED
@@ -30,27 +30,46 @@
30
30
 
31
31
  KingKong makes it easy to build full-stack ping-pong health checks so you can keep an eye on crucial input/outputs and make sure things stay nice and fast. You might need this to check and graph out the response time on your website, Twitter application, SMS gateway, or whatever else you'd connect to a network.
32
32
 
33
- When its done, it will look something like this:
34
-
33
+ ## Getting Started
34
+
35
+ Install the KingKong gem.
36
+
37
+ gem install kingkong
38
+
39
+ Then implement your ping checks in Ruby.
40
+
35
41
  require 'kingkong'
36
42
  require 'em-http-request'
37
-
38
- KingKing::Runner.start {
43
+
44
+ KingKong.start {
39
45
  socket '/tmp/king_kong.socket' # Check this socket with Munin and make a graph!
40
-
46
+
41
47
  ping(:google).every(3).seconds do |ping|
42
- google = EventMachine::HttpRequest.new('http://google.com/')
48
+ ping.start
49
+ google = EventMachine::HttpRequest.new('http://google.com/').get
43
50
  google.callback { ping.stop }
44
- google.errback { ping.fail }
45
- ping.start and google.get
51
+ google.errback { ping.fail }
46
52
  end
47
-
53
+
48
54
  ping(:twitter).every(10).seconds do |ping|
49
55
  # Wire up your own thing in here that tweets
50
56
  # .. and when you pick that up, end the pong!
51
57
  end
58
+
59
+ ping(:verizon).every(2).seconds do |ping|
60
+ # Hook your machine up to a GSM serial modem
61
+ # and perform regular SMS pings against your app.
62
+ end
52
63
  }
53
64
 
54
- and its going to aggregate stats so you can plug it into munin and get all sorts of graphing goodness.
65
+ Save the file and run it! You'll see some crazy log output right now, but eventually its going to be prettier.
66
+
67
+ You can see the stat aggregates of the pings by looking into the socket:
68
+
69
+ watch cat /tmp/king_kong.socket
70
+
71
+ If you don't understand EventMachine, you might have a little trouble getting this stuff working. Eventually I'd like to hook up Em::Syncrony and a nicer DSL for common tasks, like HTTP checks, to keep things simple.
72
+
73
+ ## Using KingKong with Munin graphs
55
74
 
56
- Stay tuned, I'm still working out the ping DSL and reporting infrastructure!
75
+ I'm working on this!
@@ -11,14 +11,20 @@ Gem::Specification.new do |s|
11
11
  s.summary = %q{Build complex network application health checks with Ruby and EventMachine}
12
12
  s.description = %q{Have you ever wanted to shoot a message throught Twitter, have your app pick it up, do some work on it, and report how long it takes? KingKong makes it slightly easier to do this with a DSL for writing custom pings and by providing basic reporting facilities that plug into graphing applications like Munin.}
13
13
 
14
- s.rubyforge_project = "kingkong"
15
-
16
14
  s.files = `git ls-files`.split("\n")
17
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
17
  s.require_paths = ["lib"]
20
18
 
21
- # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
19
+ s.add_development_dependency 'rspec'
20
+ s.add_development_dependency 'guard-rspec'
21
+ s.add_development_dependency 'growl'
22
+ s.add_development_dependency 'rb-fsevent'
23
+ s.add_development_dependency 'em-ventually'
24
+ s.add_development_dependency 'timecop'
25
+
23
26
  s.add_runtime_dependency "eventmachine"
27
+ s.add_runtime_dependency "nosey"
28
+ s.add_runtime_dependency "yajl-ruby"
29
+ s.add_runtime_dependency "em-http-request"
24
30
  end
@@ -4,17 +4,22 @@ module KingKong
4
4
  autoload :Ping, 'kingkong/ping'
5
5
  autoload :Pinger, 'kingkong/pinger'
6
6
  autoload :Runner, 'kingkong/runner'
7
- autoload :Server, 'kingkong/server'
8
7
  autoload :Logging, 'kingkong/logging'
9
8
  autoload :Aggregator, 'kingkong/aggregator'
10
- autoload :Reporting, 'kingkong/reporting'
9
+ autoload :Processor, 'kingkong/processor'
11
10
 
12
11
  # Default logger for KingKong.
13
12
  def self.logger
14
13
  @logger ||= Logger.new($stdout)
15
14
  end
16
15
 
16
+ # Want to override the default logger? Its cool, change it up here.
17
17
  def self.logger=(logger)
18
18
  @logger = logger
19
19
  end
20
+
21
+ # Shortcut for starting a runner
22
+ def self.start(*args)
23
+ Runner.new(*args)
24
+ end
20
25
  end
@@ -70,7 +70,7 @@ module KingKong
70
70
  end
71
71
 
72
72
  def to_s
73
- "Ping(#{id}, :#{status})"
73
+ "Ping(#{id}, :#{status}#{", #{latency}s" if completed?})"
74
74
  end
75
75
 
76
76
  # Generates ids for pings
@@ -83,6 +83,17 @@ module KingKong
83
83
  30 # 30 seconds that is!
84
84
  end
85
85
 
86
+ # Bust out a hash so that we can encode it into JSON and make some magic happen.
87
+ def to_hash
88
+ {
89
+ 'status' => status,
90
+ 'latency' => latency,
91
+ 'start_time' => (start_time.iso8601 if start_time),
92
+ 'end_time' => (end_time.iso8601 if end_time),
93
+ 'ttl' => ttl
94
+ }
95
+ end
96
+
86
97
  private
87
98
  # Give us the current time in seconds
88
99
  def current_time
@@ -108,7 +119,7 @@ module KingKong
108
119
 
109
120
  private
110
121
  # Spits out a key and run for a result
111
- def key(count=count)
122
+ def key(count=count())
112
123
  "#{count}:#{run}"
113
124
  end
114
125
  end
@@ -1,9 +1,14 @@
1
1
  require 'eventmachine'
2
+ require 'nosey'
3
+ require 'em-http-request'
4
+ require 'yajl'
5
+ require 'time'
2
6
 
3
7
  module KingKong
8
+ # Executes pings within a specificed duration.
4
9
  class Pinger
5
10
  include Logging
6
-
11
+ include EventMachine::Deferrable
7
12
  attr_reader :wait
8
13
 
9
14
  def initialize(wait=5,&block)
@@ -25,27 +30,24 @@ module KingKong
25
30
  @timer.cancel if @timer
26
31
  end
27
32
 
28
- # Gather up all the numbers we need for reporting later on
29
- def aggregator
30
- @aggregatore ||= Aggregator.new
33
+ # Fire this if when a ping completes
34
+ def on_ping(&block)
35
+ @on_ping = block
31
36
  end
32
37
 
33
38
  private
34
39
  # Add all of the instrumentation callbacks into the ping so we can aggregate it later
35
40
  def ping
36
41
  ping = Ping::Deferrable.new(Ping.default_ttl, sequencer)
37
-
38
42
  # Register the aggregator to process the ping
39
43
  ping.callback {
40
- logger.debug "Ping #{ping} successful"
41
- aggregator.process ping
44
+ logger.debug "Ping #{ping}"
45
+ @on_ping.call(ping) if @on_ping
42
46
  }
43
-
44
47
  ping.errback {
45
- logger.debug "Ping #{ping} error (probably a timeout)"
46
- aggregator.process ping
48
+ logger.debug "Ping #{ping}"
49
+ @on_ping.call(ping) if @on_ping
47
50
  }
48
-
49
51
  # Now pass the ping into the block so we can start/stop it
50
52
  @block.call(ping, self)
51
53
  end
@@ -0,0 +1,76 @@
1
+ require 'nosey'
2
+
3
+ module KingKong
4
+ module Processor
5
+ # Base class for processing pings
6
+ class Base
7
+ # Enable block configurations
8
+ def initialize(&block)
9
+ block.call(self) if block_given?
10
+ self
11
+ end
12
+
13
+ def process(ping)
14
+ raise 'Not Implemented'
15
+ end
16
+ end
17
+
18
+ class Nosey < Base
19
+ def initialize(host='/tmp/kingkong.socket',port=nil)
20
+ EventMachine::Nosey::SocketServer.start(nosey.report, host, port)
21
+ end
22
+
23
+ def process(ping,name)
24
+ nosey.increment "#{name}_ping_count"
25
+ case ping.status
26
+ when :timed_out
27
+ nosey.increment "#{name}_ping_timed_out_count"
28
+ when :completed
29
+ nosey.increment "#{name}_ping_completed_count"
30
+ nosey.avg "#{name}_ping_avg_latency", ping.latency
31
+ nosey.min "#{name}_ping_min_latency", ping.latency
32
+ nosey.max "#{name}_ping_max_latency", ping.latency
33
+ end
34
+ end
35
+
36
+ def nosey
37
+ @nosey ||= ::Nosey::Probe::Set.new('pinger')
38
+ end
39
+ end
40
+
41
+ class Cube < Base
42
+ include Logging
43
+
44
+ attr_accessor :url
45
+
46
+ # TODO use web sockets ...
47
+ def process(ping, name)
48
+ http = EM::HttpRequest.new(url).post({
49
+ :body => Yajl::Encoder.encode([cube_hash(ping, name)]),
50
+ :head => {'content-type' => 'application/json'}
51
+ })
52
+ http.callback{
53
+ case http.response_header.status
54
+ when 200..204
55
+ logger.debug "Successfully reported to Cube at #{url}"
56
+ else
57
+ logger.error "Could not report to Cube server: HTTP #{http.response_header.status} : #{http.response}"
58
+ end
59
+ }
60
+ http.errback{
61
+ logger.error "Could not connect to Cube at #{url}"
62
+ }
63
+ end
64
+
65
+ private
66
+ # Bust out a hash that cube will understand as JSON
67
+ def cube_hash(ping, name)
68
+ {
69
+ 'type' => name.to_s,
70
+ 'time' => Time.now.iso8601,
71
+ 'data' => ping.to_hash
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,21 +1,32 @@
1
+ require 'nosey'
2
+
1
3
  module KingKong
2
4
  # Configure multiple pingers to run
3
5
  class Runner
4
6
  include Logging
5
7
 
6
8
  # Array of pingers that we're running
7
- def ping(name)
8
- pinger_configurations[name]
9
+ def ping(name, &block)
10
+ DSL::Pinger.new(&block).completed do |pinger|
11
+ pinger.on_ping do |ping|
12
+ process ping, name
13
+ end
14
+ pingers << pinger
15
+ end
16
+ end
17
+
18
+ # We use this method to pass our pings through a processor
19
+ def process(ping, name)
20
+ @processor.call(ping,name) if @processor
9
21
  end
10
22
 
11
- # Setup the socket that this thing will write stats out to
12
- def socket(host=KingKong::Reporting::Server::Host, port=KingKong::Reporting::Server::Port)
13
- @socket_host , @socket_port = host, port
23
+ # Configure the processor that we use to report pings
24
+ def on_pong(&block)
25
+ @processor = block
14
26
  end
15
27
 
16
28
  # Start all of the pingers given the configurations
17
29
  def start
18
- start_socket
19
30
  start_pingers
20
31
  end
21
32
 
@@ -45,25 +56,14 @@ module KingKong
45
56
  end
46
57
 
47
58
  private
48
- # Fire up the reporting server if a socket (and port, optionally) are given
49
- def start_socket
50
- Reporting::Server.start(pingers.map(&:aggregator), @socket_host, @socket_port) if @socket_host
51
- end
52
-
53
59
  # Fire up all the pingers
54
60
  def start_pingers
55
61
  pingers.each(&:start)
56
62
  end
57
63
 
58
- # Hang onto pinger configuration so that we can configure pinger instances and fire them
59
- # off. We'll also be using this for writing reports.
60
- def pinger_configurations
61
- @pinger_configurations ||= Hash.new{|hash,val| hash[val] = DSL::Pinger.new }
62
- end
63
-
64
64
  # Create instances of pingers from the configurations that we setup in the runner
65
65
  def pingers
66
- @pingers ||= pinger_configurations.values.map(&:pinger)
66
+ @pingers ||= []
67
67
  end
68
68
 
69
69
  def self.ensure_running_reactor(&block)
@@ -92,18 +92,21 @@ module KingKong
92
92
  # Configure duration as seconds
93
93
  def seconds(&block)
94
94
  unitize Unit::Second, &block
95
+ complete
95
96
  end
96
97
  alias :second :seconds
97
98
 
98
99
  # Configure the duration as minutes
99
100
  def minutes(&block)
100
101
  unitize Unit::Minute, &block
102
+ complete
101
103
  end
102
104
  alias :minute :minutes
103
105
 
104
106
  # Configure the ping duration as hours
105
107
  def hours(&block)
106
108
  unitize Unit::Hour, &block
109
+ complete
107
110
  end
108
111
  alias :hour :hours
109
112
 
@@ -117,6 +120,12 @@ module KingKong
117
120
  KingKong::Pinger.new(duration, &@block)
118
121
  end
119
122
 
123
+ # Callback when we've completed the configuration of this thing.
124
+ def completed(&block)
125
+ @completed_blk = block
126
+ self
127
+ end
128
+
120
129
  private
121
130
  # Figures out the number of seconds that we multply by the units
122
131
  def unitize(units, &block)
@@ -124,6 +133,12 @@ module KingKong
124
133
  @block = block
125
134
  self
126
135
  end
136
+
137
+ # Yay! Its complete!
138
+ def complete
139
+ @completed_blk.call(pinger) if @completed_blk
140
+ self
141
+ end
127
142
  end
128
143
  end
129
144
  end
@@ -1,3 +1,3 @@
1
1
  module KingKong
2
- VERSION = "0.0.3"
3
- end
2
+ VERSION = "1.0.2"
3
+ end
@@ -6,6 +6,10 @@ describe KingKong::Ping do
6
6
  KingKong::Ping.new.ttl.should eql(KingKong::Ping.default_ttl)
7
7
  end
8
8
 
9
+ it "should return hash" do
10
+ KingKong::Ping.new.to_hash.keys.should include(*%w[status latency start_time end_time ttl])
11
+ end
12
+
9
13
  context "active" do
10
14
  before(:each) do
11
15
  @ping = KingKong::Ping.new # Open up a pinger
@@ -8,13 +8,15 @@ describe KingKong::Runner do
8
8
  @@google_pinged = @@twitter_pinged = false
9
9
 
10
10
  @runner = KingKong::Runner.configure do |runner|
11
- runner.socket '/tmp/king_kong.socket'
12
-
13
- runner.ping(:google).every(0.1).seconds do
11
+ runner.ping(:google).every(0.1).seconds do |ping|
12
+ ping.start
13
+ ping.stop
14
14
  @@google_pinged = true
15
15
  end
16
16
 
17
- runner.ping(:twitter).every(2).seconds do
17
+ runner.ping(:twitter).every(2).seconds do |ping|
18
+ ping.start
19
+ ping.stop
18
20
  @@twitter_pinged = true
19
21
  end
20
22
  end
@@ -26,8 +28,19 @@ describe KingKong::Runner do
26
28
  end
27
29
 
28
30
  it "should write data to socket" do
31
+ nosey = KingKong::Processor::Nosey.new('/tmp/king_kong_test.socket')
32
+
33
+ @runner.on_pong do |ping, name|
34
+ nosey.process ping, name
35
+ end
36
+
29
37
  @runner.start
30
- # puts UNIXSocket.new('/tmp/king_kong.socket').gets("\n\n")
38
+ c = KingKong::Test::ReadSocket.start('/tmp/king_kong_test.socket')
39
+ c.send_data("READ\nQUIT\n")
40
+ c.callback{|data|
41
+ @data = data
42
+ }
43
+ ly{ @data }.test{|data| data =~ /max/ }
31
44
  end
32
45
  end
33
46
 
@@ -8,5 +8,31 @@ RSpec.configure do |config|
8
8
  config.mock_framework = :rspec
9
9
  end
10
10
 
11
+ module KingKong
12
+ module Test
13
+ # Read data from a socket and then kill it right away.
14
+ class ReadSocket < EventMachine::Connection
15
+ include EventMachine::Deferrable
16
+
17
+ def receive_data(data)
18
+ buffer << data
19
+ end
20
+
21
+ def unbind
22
+ succeed buffer
23
+ end
24
+
25
+ def self.start(host,port=nil)
26
+ EventMachine::connect host, port, self
27
+ end
28
+
29
+ private
30
+ def buffer
31
+ @buffer ||= ""
32
+ end
33
+ end
34
+ end
35
+ end
36
+
11
37
  # Squelch the logger so we can see our specs passing
12
38
  KingKong.logger = Logger.new('/dev/null')
metadata CHANGED
@@ -1,94 +1,205 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kingkong
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
5
- prerelease:
4
+ version: 1.0.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Brad Gessler
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2011-09-13 00:00:00.000000000 -07:00
13
- default_executable:
11
+ date: 2020-09-23 00:00:00.000000000 Z
14
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
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: guard-rspec
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: growl
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
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: rb-fsevent
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: em-ventually
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: timecop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
15
97
  - !ruby/object:Gem::Dependency
16
98
  name: eventmachine
17
- requirement: &70233419803860 !ruby/object:Gem::Requirement
18
- none: false
99
+ requirement: !ruby/object:Gem::Requirement
19
100
  requirements:
20
- - - ! '>='
101
+ - - ">="
21
102
  - !ruby/object:Gem::Version
22
103
  version: '0'
23
104
  type: :runtime
24
105
  prerelease: false
25
- version_requirements: *70233419803860
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: nosey
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: yajl-ruby
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: em-http-request
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
26
153
  description: Have you ever wanted to shoot a message throught Twitter, have your app
27
154
  pick it up, do some work on it, and report how long it takes? KingKong makes it
28
155
  slightly easier to do this with a DSL for writing custom pings and by providing
29
156
  basic reporting facilities that plug into graphing applications like Munin.
30
157
  email:
31
158
  - brad@bradgessler.com
32
- executables:
33
- - kingkong-munin
34
- - kingkong-server
159
+ executables: []
35
160
  extensions: []
36
161
  extra_rdoc_files: []
37
162
  files:
38
- - .gitignore
39
- - .rvmrc
163
+ - ".gitignore"
164
+ - ".rbenv-version"
40
165
  - Gemfile
41
166
  - Guardfile
42
167
  - README.md
43
168
  - Rakefile
44
- - bin/kingkong-munin
45
- - bin/kingkong-server
46
169
  - kingkong.gemspec
47
170
  - lib/kingkong.rb
48
- - lib/kingkong/aggregator.rb
49
171
  - lib/kingkong/cli.rb
50
172
  - lib/kingkong/logging.rb
51
173
  - lib/kingkong/ping.rb
52
174
  - lib/kingkong/pinger.rb
53
- - lib/kingkong/reporting.rb
175
+ - lib/kingkong/processor.rb
54
176
  - lib/kingkong/runner.rb
55
- - lib/kingkong/server.rb
56
177
  - lib/kingkong/version.rb
57
- - spec/lib/kingkong/aggregator_spec.rb
58
178
  - spec/lib/kingkong/ping_spec.rb
59
179
  - spec/lib/kingkong/pinger_spec.rb
60
180
  - spec/lib/kingkong/runner_spec.rb
61
181
  - spec/lib/kingkong_spec.rb
62
182
  - spec/spec_helper.rb
63
- has_rdoc: true
64
183
  homepage: ''
65
184
  licenses: []
185
+ metadata: {}
66
186
  post_install_message:
67
187
  rdoc_options: []
68
188
  require_paths:
69
189
  - lib
70
190
  required_ruby_version: !ruby/object:Gem::Requirement
71
- none: false
72
191
  requirements:
73
- - - ! '>='
192
+ - - ">="
74
193
  - !ruby/object:Gem::Version
75
194
  version: '0'
76
195
  required_rubygems_version: !ruby/object:Gem::Requirement
77
- none: false
78
196
  requirements:
79
- - - ! '>='
197
+ - - ">="
80
198
  - !ruby/object:Gem::Version
81
199
  version: '0'
82
200
  requirements: []
83
- rubyforge_project: kingkong
84
- rubygems_version: 1.6.2
201
+ rubygems_version: 3.1.2
85
202
  signing_key:
86
- specification_version: 3
203
+ specification_version: 4
87
204
  summary: Build complex network application health checks with Ruby and EventMachine
88
- test_files:
89
- - spec/lib/kingkong/aggregator_spec.rb
90
- - spec/lib/kingkong/ping_spec.rb
91
- - spec/lib/kingkong/pinger_spec.rb
92
- - spec/lib/kingkong/runner_spec.rb
93
- - spec/lib/kingkong_spec.rb
94
- - spec/spec_helper.rb
205
+ test_files: []
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm use --create --install 1.9.2@kingkong
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'socket'
4
- require 'yaml'
5
-
6
- puts case ARGV.first
7
- when /config/
8
- %(graph_title Result latency
9
- graph_category App
10
- graph_vlabel load
11
- load.label load)
12
- else
13
- stats = YAML.load UNIXSocket.new("/tmp/kingkong.socket").gets("\r\n")
14
- %(load.value #{stats[:avg]})
15
- end
16
-
17
- # TODO - Message throughput
18
- # TODO - Message latency (min/max/avg)
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rubygems'
4
- require 'bundler/setup'
5
- require 'kingkong'
6
-
7
- EventMachine::run do
8
- trap('TERM') { EM.stop }
9
- trap('INT') { EM.stop }
10
- end
@@ -1,71 +0,0 @@
1
- module KingKong
2
- # Processes and aggregates samples for reporting. These stats will probably
3
- # be accessed throug the KingKong::Server UNIX socket.
4
- class Aggregator
5
- attr_reader :sum, :timed_out_count, :count, :started_at, :min, :max
6
-
7
- def initialize
8
- reset
9
- end
10
-
11
- # Accept a ping message, keep a running total, and make sure we stay within the
12
- # size of the number of samples that we want to keep around.
13
- def process(*pings)
14
- pings.each do |ping|
15
- @count+=1
16
- case ping.status
17
- when :timed_out
18
- @timed_out_count+=1
19
- else
20
- # This happens on our first ping before we have a min/max
21
- @min = @max = ping.latency if @min.nil? and @max.nil?
22
- # Cool! Lets do some math
23
- @min = ping.latency if ping.latency < @min
24
- @max = ping.latency if ping.latency > @max
25
- # We need to sum latency to calculate avgs
26
- @sum += ping.latency
27
- end
28
- end
29
- end
30
-
31
- # avg latency of samples
32
- def avg
33
- count.zero? ? 0 : sum / count
34
- end
35
-
36
- # What percentage of requests are timed out?
37
- def timed_out_percentage
38
- timed_out_count > 0 ? timed_out_count / count : 0
39
- end
40
-
41
- # Basic statistical summary of ping latency
42
- def to_hash
43
- {
44
- 'started_at' => started_at,
45
- 'avg' => avg,
46
- 'sum' => sum,
47
- 'min' => min,
48
- 'max' => max,
49
- 'count' => count,
50
- 'timed_out_count' => timed_out_count,
51
- 'successful_count' => count - timed_out_count
52
- }
53
- end
54
-
55
- # Print out a string for this that is suitable for flushing out to a socket
56
- def to_s
57
- to_hash.to_yaml
58
- end
59
-
60
- # Reset all of the counts to 0 and start sampling it all again!
61
- def reset
62
- @sum = 0.0
63
- @min = nil
64
- @max = nil
65
- @count = 0
66
- @timed_out_count = 0
67
- @samples = Array.new
68
- @started_at = Time.now
69
- end
70
- end
71
- end
@@ -1,37 +0,0 @@
1
- require 'eventmachine'
2
-
3
- module KingKong
4
- # Provides access to the pinger via a Socket or TCP port so that other
5
- # services, like Munin for example, can graph the data.
6
- module Reporting
7
- class Server < EventMachine::Connection
8
- Terminator = "\n\n"
9
- Host = '/tmp/king_kong.socket'
10
- Port = nil
11
-
12
- attr_accessor :aggregators
13
-
14
- # Accept a collection of aggregators that we'll use to report our stats.
15
- def initialize(*aggregators)
16
- @aggregators = aggregators
17
- end
18
-
19
- # Dump out the stats and close down the connection
20
- def post_init
21
- begin
22
- send_data "#{aggregators.each(&:to_s).join("\n")}#{Terminator}"
23
- rescue => e
24
- send_data "Exception! #{e}\n#{e.backtrace}"
25
- ensure
26
- close_connection
27
- end
28
- end
29
-
30
- # A nice short-cut for peeps who aren't familar with EM to fire up
31
- # an Reporting server with an array of aggregators, host, and a port.
32
- def self.start(aggregators, host=Socket::Host, port=Socket::Port)
33
- EventMachine::start_server(host, port, self, aggregators)
34
- end
35
- end
36
- end
37
- end
@@ -1,24 +0,0 @@
1
- module KingKong
2
- # Opens a UNIX socket to report pinger statistics
3
- class Server < EventMachine::Connection
4
- Frame = "\r\n"
5
-
6
- def initialize(pinger)
7
- @pinger = pinger
8
- end
9
-
10
- def post_init
11
- send_data frame @pinger.aggregator.to_hash.to_yaml
12
- end
13
-
14
- # Start an instance of the aggregator server on a unix port
15
- def self.start(pinger, host='/tmp/kingkong.socket', port=nil)
16
- EM.start_server host, port, self, pinger
17
- end
18
-
19
- private
20
- def frame(message)
21
- "#{message}#{Frame}"
22
- end
23
- end
24
- end
@@ -1,32 +0,0 @@
1
- require 'spec_helper'
2
- require "rspec/mocks/standalone"
3
-
4
- describe KingKong::Aggregator do
5
- before(:all) do
6
- @agg = KingKong::Aggregator.new
7
-
8
- @pings = (1..3).map do |n|
9
- ping = KingKong::Ping.new
10
- ping.stub(:latency){ n.to_f }
11
- ping
12
- end
13
-
14
- @agg.process *@pings
15
- end
16
-
17
- it "should calculate avg" do
18
- @agg.avg.should eql(2.0)
19
- end
20
-
21
- it "should calculate sum" do
22
- @agg.sum.should eql(6.0)
23
- end
24
-
25
- it "should calculate max" do
26
- @agg.max.should eql(3.0)
27
- end
28
-
29
- it "should calculate min" do
30
- @agg.min.should eql(1.0)
31
- end
32
- end