kingkong 0.0.3 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rbenv-version +1 -0
- data/Gemfile +1 -14
- data/README.md +30 -11
- data/kingkong.gemspec +10 -4
- data/lib/kingkong.rb +7 -2
- data/lib/kingkong/ping.rb +13 -2
- data/lib/kingkong/pinger.rb +13 -11
- data/lib/kingkong/processor.rb +76 -0
- data/lib/kingkong/runner.rb +33 -18
- data/lib/kingkong/version.rb +2 -2
- data/spec/lib/kingkong/ping_spec.rb +4 -0
- data/spec/lib/kingkong/runner_spec.rb +18 -5
- data/spec/spec_helper.rb +26 -0
- metadata +145 -34
- data/.rvmrc +0 -1
- data/bin/kingkong-munin +0 -18
- data/bin/kingkong-server +0 -10
- data/lib/kingkong/aggregator.rb +0 -71
- data/lib/kingkong/reporting.rb +0 -37
- data/lib/kingkong/server.rb +0 -24
- data/spec/lib/kingkong/aggregator_spec.rb +0 -32
checksums.yaml
ADDED
@@ -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
|
data/.rbenv-version
ADDED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
48
|
+
ping.start
|
49
|
+
google = EventMachine::HttpRequest.new('http://google.com/').get
|
43
50
|
google.callback { ping.stop }
|
44
|
-
google.errback
|
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
|
-
|
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
|
-
|
75
|
+
I'm working on this!
|
data/kingkong.gemspec
CHANGED
@@ -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
|
-
|
22
|
-
|
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
|
data/lib/kingkong.rb
CHANGED
@@ -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 :
|
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
|
data/lib/kingkong/ping.rb
CHANGED
@@ -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
|
data/lib/kingkong/pinger.rb
CHANGED
@@ -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
|
-
#
|
29
|
-
def
|
30
|
-
@
|
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}
|
41
|
-
|
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}
|
46
|
-
|
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
|
data/lib/kingkong/runner.rb
CHANGED
@@ -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
|
-
|
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
|
-
#
|
12
|
-
def
|
13
|
-
@
|
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 ||=
|
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
|
data/lib/kingkong/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module KingKong
|
2
|
-
VERSION = "
|
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.
|
12
|
-
|
13
|
-
|
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
|
-
|
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
|
|
data/spec/spec_helper.rb
CHANGED
@@ -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:
|
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:
|
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:
|
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:
|
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
|
-
- .
|
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/
|
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
|
-
|
84
|
-
rubygems_version: 1.6.2
|
201
|
+
rubygems_version: 3.1.2
|
85
202
|
signing_key:
|
86
|
-
specification_version:
|
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
|
data/bin/kingkong-munin
DELETED
@@ -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)
|
data/bin/kingkong-server
DELETED
data/lib/kingkong/aggregator.rb
DELETED
@@ -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
|
data/lib/kingkong/reporting.rb
DELETED
@@ -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
|
data/lib/kingkong/server.rb
DELETED
@@ -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
|