what 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in what.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,15 @@
1
+ class What::Status
2
+ @status = {}
3
+
4
+ def self.[](attr)
5
+ @status[attr]
6
+ end
7
+
8
+ def self.[]=(attr, val)
9
+ @status[attr] = val
10
+ end
11
+
12
+ def self.all
13
+ @status
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module What
2
+ VERSION = "0.0.1"
3
+ end
data/lib/what.rb ADDED
@@ -0,0 +1,14 @@
1
+ module What
2
+ end
3
+
4
+ require 'json'
5
+ require 'yaml'
6
+ require 'thin'
7
+
8
+ require 'what/version'
9
+ require 'what/helpers'
10
+ require 'what/config'
11
+ require 'what/status'
12
+ require 'what/modules'
13
+ require 'what/monitor'
14
+ require 'what/server'
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
+