what 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +2 -0
- data/bin/what +28 -0
- data/example/what.yml +27 -0
- data/lib/what/config.rb +43 -0
- data/lib/what/helpers.rb +20 -0
- data/lib/what/modules/base.rb +26 -0
- data/lib/what/modules/unicorn.rb +22 -0
- data/lib/what/modules.rb +19 -0
- data/lib/what/monitor.rb +30 -0
- data/lib/what/server.rb +14 -0
- data/lib/what/status.rb +15 -0
- data/lib/what/version.rb +3 -0
- data/lib/what.rb +14 -0
- data/what.gemspec +26 -0
- metadata +114 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
data/bin/what
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'optparse'
|
3
|
+
require 'what'
|
4
|
+
|
5
|
+
opts = OptionParser.new do |opts|
|
6
|
+
opts.banner = "Usage: what [options]"
|
7
|
+
opts.separator ""
|
8
|
+
|
9
|
+
opts.on('-c', '--config FILE', 'Specify the location of the YAML config file.') do |fn|
|
10
|
+
What::Config.load(fn)
|
11
|
+
end
|
12
|
+
|
13
|
+
opts.on_tail('-h', '--help', 'Show this message.') do
|
14
|
+
puts opts
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
end
|
18
|
+
opts.parse!(ARGV)
|
19
|
+
|
20
|
+
unless What::Config.loaded?
|
21
|
+
puts opts
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
|
25
|
+
Thin::Server.start('0.0.0.0', 8164) do
|
26
|
+
run What::Server.new
|
27
|
+
end
|
28
|
+
|
data/example/what.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Config file for the What monitoring system.
|
2
|
+
|
3
|
+
### Set the polling interval for all services.
|
4
|
+
interval: 10
|
5
|
+
|
6
|
+
### Specify paths containing custom modules to load, relative to this file.
|
7
|
+
# module_paths:
|
8
|
+
# - modules
|
9
|
+
|
10
|
+
### List all modules to be monitored.
|
11
|
+
modules:
|
12
|
+
- unicorn
|
13
|
+
# - ram
|
14
|
+
# - redis
|
15
|
+
# - dir
|
16
|
+
# - whatever
|
17
|
+
|
18
|
+
### Pass parameters into modules.
|
19
|
+
# module_config:
|
20
|
+
# ram:
|
21
|
+
# min: nil
|
22
|
+
# dir:
|
23
|
+
# path: '/mnt/datastore'
|
24
|
+
|
25
|
+
### Specify any other config files to load.
|
26
|
+
# configs:
|
27
|
+
# - more_config/stuff.yml
|
data/lib/what/config.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
class What::Config
|
2
|
+
@config = {}
|
3
|
+
|
4
|
+
def self.load(fn)
|
5
|
+
load_primary(fn)
|
6
|
+
load_secondary(@config['configs'])
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.load_primary(fn)
|
10
|
+
@config = YAML.load_file(fn)
|
11
|
+
@config['base'] ||= File.expand_path(File.dirname(fn))
|
12
|
+
@loaded = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.load_secondary(fns)
|
16
|
+
return if !fns
|
17
|
+
|
18
|
+
fns.each do |fn|
|
19
|
+
path = if fn.match(/^\//)
|
20
|
+
fn
|
21
|
+
else
|
22
|
+
File.join(@config['base'], fn)
|
23
|
+
end
|
24
|
+
@config.merge!(YAML.load_file(path))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.loaded?
|
29
|
+
@loaded
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.[](attr)
|
33
|
+
@config[attr]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.[]=(attr, val)
|
37
|
+
@config[attr] = val
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.all
|
41
|
+
@config
|
42
|
+
end
|
43
|
+
end
|
data/lib/what/helpers.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module What::Helpers
|
2
|
+
# Stolen from Rails (http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html)
|
3
|
+
def self.camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
|
4
|
+
if first_letter_in_uppercase
|
5
|
+
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
6
|
+
else
|
7
|
+
lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.underscore(camel_cased_word)
|
12
|
+
word = camel_cased_word.to_s.dup
|
13
|
+
word.gsub!(/::/, '/')
|
14
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
15
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
16
|
+
word.tr!("-", "_")
|
17
|
+
word.downcase!
|
18
|
+
word
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class What::Modules::Base
|
2
|
+
def initialize
|
3
|
+
@config = What::Config[self.name]
|
4
|
+
end
|
5
|
+
|
6
|
+
def name
|
7
|
+
What::Helpers.underscore(self.class.name.split('::').last)
|
8
|
+
end
|
9
|
+
|
10
|
+
def check!
|
11
|
+
raise "Module #{self.class.name} doesn't override 'check!'"
|
12
|
+
end
|
13
|
+
|
14
|
+
def status
|
15
|
+
{ :health => health }.merge(details)
|
16
|
+
end
|
17
|
+
|
18
|
+
def health
|
19
|
+
raise "Module #{self.class.name} doesn't override 'health'"
|
20
|
+
end
|
21
|
+
|
22
|
+
def details
|
23
|
+
{}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class What::Modules::Unicorn < What::Modules::Base
|
2
|
+
@unicorns = []
|
3
|
+
|
4
|
+
def check!
|
5
|
+
@unicorns = `ps aux`.grep(/unicorn_rails worker/).map do |ln|
|
6
|
+
ln =~ /^\w+\s+(\d+).*(\d+:\d\d(?:\.\d\d)?) unicorn/
|
7
|
+
{:pid => $1, :cpu_time => $2}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def health
|
12
|
+
if @unicorns.count > 0
|
13
|
+
:ok
|
14
|
+
else
|
15
|
+
:alert
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def details
|
20
|
+
{:workers => @unicorns.count, :details => @unicorns}
|
21
|
+
end
|
22
|
+
end
|
data/lib/what/modules.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module What::Modules
|
2
|
+
# load all modules defined in what/modules, in addition to any paths
|
3
|
+
# specified in the config file.
|
4
|
+
def self.load_all
|
5
|
+
globs = [File.join(File.dirname(__FILE__), 'modules', '*.rb')]
|
6
|
+
|
7
|
+
if What::Config['module_paths']
|
8
|
+
What::Config['module_paths'].each do |module_path|
|
9
|
+
globs << File.join(What::Config['base'], module_path, '*.rb')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
globs.each do |glob|
|
14
|
+
Dir[glob].each do |fn|
|
15
|
+
require fn
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/what/monitor.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
class What::Monitor
|
2
|
+
def self.go!
|
3
|
+
@modules = What::Config['modules'].map do |m|
|
4
|
+
name = What::Helpers.camelize(m)
|
5
|
+
What::Modules.const_get(name).new
|
6
|
+
end
|
7
|
+
|
8
|
+
Thread.abort_on_exception = true
|
9
|
+
@thread = Thread.new(@modules) { |modules| self.do_it(modules) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.do_it(modules)
|
13
|
+
loop do
|
14
|
+
overall = :ok
|
15
|
+
modules.each do |mod|
|
16
|
+
mod.check!
|
17
|
+
case mod.health
|
18
|
+
when :ok
|
19
|
+
when :warning
|
20
|
+
overall = :warning if overall != :alert
|
21
|
+
else
|
22
|
+
overall = :alert
|
23
|
+
end
|
24
|
+
What::Status[mod.name] = mod.status
|
25
|
+
end
|
26
|
+
What::Status[:health] = overall
|
27
|
+
sleep What::Config['interval']
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/what/server.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class What::Server
|
2
|
+
def initialize
|
3
|
+
What::Modules.load_all
|
4
|
+
What::Monitor.go!
|
5
|
+
end
|
6
|
+
|
7
|
+
def call(_)
|
8
|
+
[
|
9
|
+
What::Status[:health] != :alert ? 200 : 503,
|
10
|
+
{'Content-Type' => 'application/json'},
|
11
|
+
JSON.unparse(What::Status.all) + "\n"
|
12
|
+
]
|
13
|
+
end
|
14
|
+
end
|
data/lib/what/status.rb
ADDED
data/lib/what/version.rb
ADDED
data/lib/what.rb
ADDED
data/what.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "what/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "what"
|
7
|
+
s.version = What::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ryan Lower", "Ryan Fitzgerald"]
|
10
|
+
s.email = ["team@academia.edu"]
|
11
|
+
s.homepage = "http://academia.edu/"
|
12
|
+
s.summary = %q{Modular server monitoring with JSON endpoint}
|
13
|
+
s.description = %q{What runs a Thin server which returns a JSON object representing
|
14
|
+
the state of services running on a machine. It currently only includes a
|
15
|
+
module for monitoring Unicorn workers, but it's easy to add custom modules.}
|
16
|
+
|
17
|
+
s.rubyforge_project = "what"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
|
24
|
+
s.add_dependency("thin")
|
25
|
+
s.add_dependency("json")
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: what
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ryan Lower
|
14
|
+
- Ryan Fitzgerald
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-05-10 00:00:00 -07:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: thin
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: json
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
version: "0"
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
description: |-
|
51
|
+
What runs a Thin server which returns a JSON object representing
|
52
|
+
the state of services running on a machine. It currently only includes a
|
53
|
+
module for monitoring Unicorn workers, but it's easy to add custom modules.
|
54
|
+
email:
|
55
|
+
- team@academia.edu
|
56
|
+
executables:
|
57
|
+
- what
|
58
|
+
extensions: []
|
59
|
+
|
60
|
+
extra_rdoc_files: []
|
61
|
+
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- Gemfile
|
65
|
+
- Rakefile
|
66
|
+
- bin/what
|
67
|
+
- example/what.yml
|
68
|
+
- lib/what.rb
|
69
|
+
- lib/what/config.rb
|
70
|
+
- lib/what/helpers.rb
|
71
|
+
- lib/what/modules.rb
|
72
|
+
- lib/what/modules/base.rb
|
73
|
+
- lib/what/modules/unicorn.rb
|
74
|
+
- lib/what/monitor.rb
|
75
|
+
- lib/what/server.rb
|
76
|
+
- lib/what/status.rb
|
77
|
+
- lib/what/version.rb
|
78
|
+
- what.gemspec
|
79
|
+
has_rdoc: true
|
80
|
+
homepage: http://academia.edu/
|
81
|
+
licenses: []
|
82
|
+
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 3
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
hash: 3
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
version: "0"
|
106
|
+
requirements: []
|
107
|
+
|
108
|
+
rubyforge_project: what
|
109
|
+
rubygems_version: 1.5.1
|
110
|
+
signing_key:
|
111
|
+
specification_version: 3
|
112
|
+
summary: Modular server monitoring with JSON endpoint
|
113
|
+
test_files: []
|
114
|
+
|