status_cat 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +161 -0
  4. data/Rakefile +31 -0
  5. data/app/assets/javascripts/status-cat/application.js +15 -0
  6. data/app/assets/stylesheets/status-cat/application.css +13 -0
  7. data/app/controllers/status_cat/status_controller.rb +26 -0
  8. data/app/helpers/status_cat/status_helper.rb +105 -0
  9. data/app/mailers/status_cat/status_mailer.rb +12 -0
  10. data/app/views/status_cat/status/index.html.erb +4 -0
  11. data/app/views/status_cat/status_mailer/failure.html.erb +9 -0
  12. data/app/views/status_cat/status_mailer/failure.text.erb +1 -0
  13. data/config/locales/en.yml +7 -0
  14. data/config/routes.rb +4 -0
  15. data/lib/status_cat/checkers/action_mailer.rb +31 -0
  16. data/lib/status_cat/checkers/active_record.rb +24 -0
  17. data/lib/status_cat/checkers/base.rb +36 -0
  18. data/lib/status_cat/checkers/delayed_job.rb +28 -0
  19. data/lib/status_cat/checkers/s3.rb +17 -0
  20. data/lib/status_cat/checkers/stripe.rb +19 -0
  21. data/lib/status_cat/config.rb +33 -0
  22. data/lib/status_cat/engine.rb +5 -0
  23. data/lib/status_cat/status.rb +37 -0
  24. data/lib/status_cat/version.rb +3 -0
  25. data/lib/status_cat.rb +22 -0
  26. data/lib/tasks/status_cat.rake +14 -0
  27. data/spec/controllers/status_cat/status_controller_spec.rb +36 -0
  28. data/spec/coverage_spec.rb +22 -0
  29. data/spec/data/report.txt +10 -0
  30. data/spec/data/report.txt.tmp +10 -0
  31. data/spec/data/status_report_format.txt +1 -0
  32. data/spec/data/status_report_format.txt.tmp +1 -0
  33. data/spec/dummy/README.rdoc +261 -0
  34. data/spec/dummy/Rakefile +7 -0
  35. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  36. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  37. data/spec/dummy/app/checkers/dummy.rb +10 -0
  38. data/spec/dummy/app/controllers/application_controller.rb +10 -0
  39. data/spec/dummy/app/controllers/root_controller.rb +20 -0
  40. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  41. data/spec/dummy/app/views/layouts/admin.html.erb +14 -0
  42. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  43. data/spec/dummy/app/views/root/index.html.erb +8 -0
  44. data/spec/dummy/app/views/root/mail.html.erb +1 -0
  45. data/spec/dummy/config/application.rb +54 -0
  46. data/spec/dummy/config/boot.rb +10 -0
  47. data/spec/dummy/config/database.yml +25 -0
  48. data/spec/dummy/config/environment.rb +5 -0
  49. data/spec/dummy/config/environments/development.rb +32 -0
  50. data/spec/dummy/config/environments/production.rb +69 -0
  51. data/spec/dummy/config/environments/test.rb +33 -0
  52. data/spec/dummy/config/initializers/action_mailer.rb +16 -0
  53. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  54. data/spec/dummy/config/initializers/inflections.rb +15 -0
  55. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  56. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  57. data/spec/dummy/config/initializers/session_store.rb +8 -0
  58. data/spec/dummy/config/initializers/status_cat.rb +17 -0
  59. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  60. data/spec/dummy/config/locales/en.yml +5 -0
  61. data/spec/dummy/config/passwords.yml +5 -0
  62. data/spec/dummy/config/passwords.yml.sample +5 -0
  63. data/spec/dummy/config/routes.rb +11 -0
  64. data/spec/dummy/config.ru +4 -0
  65. data/spec/dummy/db/development.sqlite3 +0 -0
  66. data/spec/dummy/db/production.sqlite3 +0 -0
  67. data/spec/dummy/db/schema.rb +16 -0
  68. data/spec/dummy/db/test.sqlite3 +0 -0
  69. data/spec/dummy/log/development.log +889 -0
  70. data/spec/dummy/log/test.log +2474 -0
  71. data/spec/dummy/public/404.html +26 -0
  72. data/spec/dummy/public/422.html +26 -0
  73. data/spec/dummy/public/500.html +25 -0
  74. data/spec/dummy/public/favicon.ico +0 -0
  75. data/spec/dummy/script/rails +6 -0
  76. data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  77. data/spec/dummy/tmp/cache/assets/D03/1A0/sprockets%2F9007913fce90a3c1766dc0d8282bd10b +0 -0
  78. data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  79. data/spec/dummy/tmp/cache/assets/D37/670/sprockets%2Fe230d6e60a0226de8748d1e26ee741cb +0 -0
  80. data/spec/dummy/tmp/cache/assets/D3D/4E0/sprockets%2F999ebb6862b2b7ca1b20b765f12704ed +0 -0
  81. data/spec/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  82. data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  83. data/spec/dummy/tmp/cache/assets/DCB/210/sprockets%2Fdf0a443455a9d359be2e931ba70ecdfe +0 -0
  84. data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  85. data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  86. data/spec/dummy/tmp/cache/assets/development/sprockets/0891c389c9f47b48b695b65602d93a57 +0 -0
  87. data/spec/dummy/tmp/cache/assets/development/sprockets/0edf8c53de2ee6fe74108f1ecc87e457 +0 -0
  88. data/spec/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  89. data/spec/dummy/tmp/cache/assets/development/sprockets/264f02aaf3a74cd5a91b5575c69b784a +0 -0
  90. data/spec/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  91. data/spec/dummy/tmp/cache/assets/development/sprockets/31c22cfbb3b5f7f9e1e9a013997ad8aa +0 -0
  92. data/spec/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  93. data/spec/dummy/tmp/cache/assets/development/sprockets/400d7aa6ca317151fe36fc9f02ccfc4e +0 -0
  94. data/spec/dummy/tmp/cache/assets/development/sprockets/40da66d7323888023264d2f06b7525d4 +0 -0
  95. data/spec/dummy/tmp/cache/assets/development/sprockets/4bddf542ba5114155847240380cf6e7c +0 -0
  96. data/spec/dummy/tmp/cache/assets/development/sprockets/572759e0267736e8961ff1fad85cfe47 +0 -0
  97. data/spec/dummy/tmp/cache/assets/development/sprockets/6cec2a8a17b78e61daecff44044e1179 +0 -0
  98. data/spec/dummy/tmp/cache/assets/development/sprockets/952a706f512b208187110eff045a0e66 +0 -0
  99. data/spec/dummy/tmp/cache/assets/development/sprockets/c7d1ab26b0b22ab011a9d30f44014f06 +0 -0
  100. data/spec/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  101. data/spec/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  102. data/spec/dummy/tmp/cache/assets/development/sprockets/f1ebb0ab4631911fbbdf496685d8b7a0 +0 -0
  103. data/spec/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  104. data/spec/dummy/tmp/pids/server.pid +1 -0
  105. data/spec/helpers/status_cat/status_helper_spec.rb +101 -0
  106. data/spec/lib/status_cat/checkers/action_mailer_spec.rb +72 -0
  107. data/spec/lib/status_cat/checkers/active_record_spec.rb +45 -0
  108. data/spec/lib/status_cat/checkers/base_spec.rb +56 -0
  109. data/spec/lib/status_cat/checkers/delayed_job_spec.rb +15 -0
  110. data/spec/lib/status_cat/checkers/s3_spec.rb +15 -0
  111. data/spec/lib/status_cat/checkers/stripe_spec.rb +15 -0
  112. data/spec/lib/status_cat/config_spec.rb +133 -0
  113. data/spec/lib/status_cat/engine_spec.rb +9 -0
  114. data/spec/lib/status_cat/status_spec.rb +120 -0
  115. data/spec/lib/status_cat/version_spec.rb +11 -0
  116. data/spec/lib/status_cat_spec.rb +21 -0
  117. data/spec/lib/tasks/status_cat.rake_spec.rb +32 -0
  118. data/spec/mailers/status_cat/status_mailer_spec.rb +38 -0
  119. data/spec/spec_helper.rb +50 -0
  120. data/spec/support/shared/checker.rb +25 -0
  121. data/spec/views/status_cat/status/index.html.erb_spec.rb +25 -0
  122. data/spec/views/status_cat/status_mailer/failure.html.erb_spec.rb +16 -0
  123. data/spec/views/status_cat/status_mailer/failure.text.erb_spec.rb +15 -0
  124. metadata +373 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b4d7e541b0764d848791a7a4b5d56e20de702db5
4
+ data.tar.gz: d072d488b05aa95fb5c2de5b6f166e81c169418d
5
+ SHA512:
6
+ metadata.gz: 8db8481cfa3edcd43bfb3b369a6ae5a63f2d0201f99d95ceca48ef129a57bbd7d96f946ab2343dde8b8da7b8ee71d918c1dc2a883a8658cf34fc88cb59ffac71
7
+ data.tar.gz: 4bc2df86a682d5c0e1ad4567c269878345f4bffb9657c5552e33ce2da9779ca3c35c8045073c4d0e1c874c24995a6377f8f3d19e8b65158bab5679053ab381b4
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 SchrodingersBox.com
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # schrodingersbox/status_cat README
2
+
3
+ This engine makes monitoring the status of your Rails environment easier.
4
+
5
+ It provides a Rails action with a green light / red light list of configured services,
6
+ such as:
7
+
8
+ * ActionMailer
9
+ * ActiveRecord
10
+ * AWS S3
11
+ * Delayed Job
12
+ * Stripe
13
+
14
+ ## Getting Started
15
+
16
+ 1. Add this to your `Gemfile` and `bundle install`
17
+
18
+ gem 'status_cat', :git => 'https://github.com/schrodingersbox/status_cat.git'
19
+
20
+ 2. Add this to your `config/routes.rb`
21
+
22
+ mount StatusCat::Engine => '/status_cat'
23
+
24
+ 3. Restart your Rails server
25
+
26
+ 4. Run `rake status_cat:check` for a text status report
27
+
28
+ 5. Visit http://yourapp/status_cat in a browser for an HTML status report
29
+
30
+ ## Configuration
31
+
32
+ All configuration should go in `config/initializers/status_cat.rb`.
33
+
34
+ Status.configure do |config|
35
+
36
+ config.authenticate_with do
37
+ authenticate!
38
+ end
39
+
40
+ config.authorize_with do
41
+ authorize!
42
+ end
43
+
44
+ config.layout = 'admin'
45
+
46
+ config.noreply = 'noreply@schrodingersbox.com'
47
+ config.to = 'ops@schrodingersbox.com'
48
+ config.from = 'ops@schrodingersbox.com'
49
+ config.subject = "#{Rails.env.upcase} StatusCat Failure"
50
+
51
+ end
52
+
53
+ ## How To
54
+
55
+ ### Configure Enabled Checkers
56
+
57
+ By default, all subclasses of StatusCat::Checkers::Base will be run. Do the following if you would like to limit or reorder the set of checkers
58
+
59
+ Create or add to `config/initializers/status_cat.rb`
60
+
61
+ StatusCat.configure do |config|
62
+ config.enabled = [ :action_mailer, :active_record ]
63
+ end
64
+
65
+ ### Configure Email Settings
66
+
67
+ Create or add to `config/initializers/status_cat.rb`
68
+
69
+ StatusCat.configure do |config|
70
+ config.noreply = 'noreply@schrodingersbox.com'
71
+ config.to = 'ops@schrodingersbox.com'
72
+ config.from = 'ops@schrodingersbox.com'
73
+ config.subject = "#{Rails.env.upcase} StatusCat Failure"
74
+ end
75
+
76
+ ### Run Status Checks From A Cron
77
+
78
+ 1. Run `rake status_cat:cron` from a cron job or other scheduling system.
79
+
80
+ PLEASE NOTE: The :action_mailer checker will attempt to send a test email to your `StatusCat.config.noreply` email address. This could cause unwanted spam or incur charges if you're using a metered mail transfer agent, like SendGrid.
81
+
82
+ ### Add New Checkers
83
+
84
+ You can place new checkers anywhere you like, but `app/checkers` is the recommended location.
85
+
86
+ 1. Add the following to `config/application.rb`
87
+
88
+ Dir[Rails.root + 'app/checkers/**/*.rb'].each { |path| require path }
89
+
90
+ 2. Create a new subclass of `StatusCat::Checkers::Base` that sets `@value` and `@status` instance variables.
91
+
92
+ module StatusCat
93
+ module Checkers
94
+ class Dummy < Base
95
+ def initialize
96
+ @value = 'dummy'
97
+ @status = 'fail'
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ ### Require authentication
104
+
105
+ Create or add to `config/initializers/status_cat.rb`
106
+
107
+ StatusCat.configure do |config|
108
+ config.authenticate_with do
109
+ warden.authenticate! scope: :user
110
+ end
111
+ end
112
+
113
+ ### Require authorization
114
+
115
+ Create or add to `config/initializers/status_cat.rb`
116
+
117
+ StatusCat.configure do |config|
118
+ config.authorize_with do
119
+ redirect_to main_app.root_path unless current_user.try(:admin?)
120
+ end
121
+ end
122
+
123
+ ### Apply a custom layout
124
+
125
+ Create or add to `config/initializers/status_cat.rb`
126
+
127
+ StatusCat.configure do |config|
128
+ config.layout = 'admin'
129
+ end
130
+
131
+ ## Reference
132
+
133
+ * [Getting Started with Engines](http://edgeguides.rubyonrails.org/engines.html)
134
+ * [Testing Rails Engines With Rspec](http://whilefalse.net/2012/01/25/testing-rails-engines-rspec/)
135
+ * [How do I write a Rails 3.1 engine controller test in rspec?](http://stackoverflow.com/questions/5200654/how-do-i-write-a-rails-3-1-engine-controller-test-in-rspec)
136
+ * [Best practice for specifying dependencies that cannot be put in gemspec?](https://groups.google.com/forum/?fromgroups=#!topic/ruby-bundler/U7FMRAl3nJE)
137
+ * [Clarifying the Roles of the .gemspec and Gemfile](http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/)
138
+ * [The Semi-Isolated Rails Engine](http://bibwild.wordpress.com/2012/05/10/the-semi-isolated-rails-engine/)
139
+ * [config.reload_plugins = true only works in environment.rb](https://rails.lighthouseapp.com/projects/8994/tickets/2324-configreload_plugins-true-only-works-in-environmentrb?spam=1)
140
+ * [describe vs. context in rspec](http://lmws.net/describe-vs-context-in-rspec)
141
+ * [Add Achievement Badges to Your Gem README](http://elgalu.github.io/2013/add-achievement-badges-to-your-gem-readme/)
142
+ * [Publishing your gem](http://guides.rubygems.org/publishing/)
143
+
144
+ ## History
145
+
146
+ Version 0.0.2 = Rails 3 compatible
147
+ Version 0.0.3 = Rails 4 compatible
148
+
149
+ ## TODO
150
+
151
+ * Add disk space checker with externally configurable limit
152
+ * Add Zencoder checker?
153
+ * Add NewRelic checker?
154
+
155
+ * Dynamically create rake tasks for each checker
156
+
157
+ * Doc
158
+ * General checker concept
159
+ * Shared spec
160
+
161
+ * Publish as gem
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ begin
9
+ require 'rdoc/task'
10
+ rescue LoadError
11
+ require 'rdoc/rdoc'
12
+ require 'rake/rdoctask'
13
+ RDoc::Task = Rake::RDocTask
14
+ end
15
+
16
+ RDoc::Task.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'StatusCat'
19
+ rdoc.options << '--line-numbers'
20
+ rdoc.rdoc_files.include('README.rdoc')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
25
+ load 'rails/tasks/engine.rake'
26
+
27
+
28
+
29
+ Bundler::GemHelper.install_tasks
30
+
31
+ load 'tasks/spec_cat.rake'
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,26 @@
1
+ class StatusCat::StatusController < ApplicationController
2
+
3
+ layout :set_layout
4
+
5
+ before_filter :_authenticate!
6
+ before_filter :_authorize!
7
+
8
+ def index
9
+ @checkers = StatusCat::Status.all
10
+ end
11
+
12
+ private
13
+
14
+ def set_layout
15
+ return StatusCat.config.layout
16
+ end
17
+
18
+ def _authenticate!
19
+ instance_eval( &StatusCat.config.authenticate_with )
20
+ end
21
+
22
+ def _authorize!
23
+ instance_eval( &StatusCat.config.authorize_with )
24
+ end
25
+
26
+ end
@@ -0,0 +1,105 @@
1
+ module StatusCat::StatusHelper
2
+
3
+ # Constructs an HTML table header
4
+
5
+ def status_header
6
+ content_tag( :tr ) do
7
+ concat content_tag( :th, t( :name, :scope => :status_cat ) )
8
+ concat content_tag( :th, t( :value, :scope => :status_cat ) )
9
+ concat content_tag( :th, t( :status, :scope => :status_cat ) )
10
+ end
11
+ end
12
+
13
+ # Constructs an HTML table row
14
+
15
+ def status_row( checker )
16
+ content_tag( :tr ) do
17
+ concat content_tag( :td, checker.name, :style => status_style( checker ) )
18
+ concat content_tag( :td, checker.value )
19
+ concat status_cell(checker.status || t( :ok, :scope => :status_cat ))
20
+ end
21
+ end
22
+
23
+ def status_cell( status )
24
+ if status.kind_of?(Array)
25
+ return content_tag( :td ) do
26
+ content_tag( :table ) do
27
+ rows = nil
28
+ status.each do |s|
29
+ row = content_tag( :tr ) do
30
+ content_tag( :td, s )
31
+ end
32
+
33
+ if rows == nil
34
+ rows = row
35
+ else
36
+ rows += row
37
+ end
38
+ end
39
+ rows
40
+ end
41
+ end
42
+ end
43
+
44
+ return content_tag( :td, status )
45
+ end
46
+
47
+ # Returns an HTML style for the status table cell
48
+
49
+ def status_style( checker )
50
+ "background-color: #{checker.status.nil? ? :green : :red}"
51
+ end
52
+
53
+ # Returns an HTML table
54
+
55
+ def status_table( checkers )
56
+ content_tag( :table, :border => 1 ) do
57
+ concat status_header
58
+ checkers.each { |checker| concat status_row( checker ) }
59
+ end
60
+ end
61
+
62
+ # Returns an HTML title
63
+
64
+ def status_title
65
+ content_tag( :h1, t( :h1, :scope => :status_cat ) )
66
+ end
67
+
68
+ # Constructs a text status report
69
+
70
+ def status_report( checkers )
71
+ format, format_length = status_report_format( checkers )
72
+ header = status_report_header( format )
73
+ length = [ format_length, header.length ].max
74
+ separator = ( '-' * length ) + "\n"
75
+
76
+ result = separator + header + separator
77
+ checkers.each { |checker| result << checker.to_s( format ) }
78
+ result << separator
79
+
80
+ return result
81
+ end
82
+
83
+ # Generate a format string to justify all values
84
+
85
+ def status_report_format( checkers )
86
+ name_max = checkers.map { |c| c.name.to_s.length }.max
87
+ value_max = checkers.map { |c| c.value.to_s.length }.max
88
+ status_max = checkers.map { |c| c.status.to_s.length }.max
89
+
90
+ format = "%#{name_max}s | %#{value_max}s | %#{status_max}s\n"
91
+ length = name_max + 3 + value_max + 3 + status_max
92
+
93
+ return format, length
94
+ end
95
+
96
+ # Generate a header string
97
+
98
+ def status_report_header( format = StatusCat::Checkers::Base::FORMAT )
99
+ name = I18n.t( :name, :scope => :status_cat )
100
+ value = I18n.t( :value, :scope => :status_cat )
101
+ status = I18n.t( :status, :scope => :status_cat )
102
+ return sprintf( format, name, value, status )
103
+ end
104
+
105
+ end
@@ -0,0 +1,12 @@
1
+ class StatusCat::StatusMailer < ActionMailer::Base
2
+
3
+ add_template_helper( StatusCat::StatusHelper )
4
+
5
+ def failure( checkers )
6
+ @checkers = checkers
7
+
8
+ config = StatusCat.config
9
+ mail( :to => config.to, :from => config.from, :subject => config.subject )
10
+ end
11
+
12
+ end
@@ -0,0 +1,4 @@
1
+ <div class="status_cat">
2
+ <%= status_title %>
3
+ <%= status_table( @checkers ) %>
4
+ </div>
@@ -0,0 +1,9 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
5
+ </head>
6
+ <body>
7
+ <%= status_table( @checkers ) %>
8
+ </body>
9
+ </html>
@@ -0,0 +1 @@
1
+ <%= status_report( @checkers ) %>
@@ -0,0 +1,7 @@
1
+ en:
2
+ status_cat:
3
+ h1: Status Report
4
+ name: Name
5
+ value: Value
6
+ status: Status
7
+ ok: OK
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ StatusCat::Engine.routes.draw do
2
+ root :to => 'status#index'
3
+ get '/status' => 'status#index'
4
+ end
@@ -0,0 +1,31 @@
1
+ module StatusCat
2
+ module Checkers
3
+ class ActionMailer < Base
4
+
5
+ def initialize
6
+ @value = "#{config[ :address ]}:#{config[ :port ]}"
7
+
8
+ unless ::ActionMailer::Base.delivery_method == :test
9
+ @status = fail_on_exception do
10
+ address = config[ :address ]
11
+ port = config[ :port ]
12
+ domain = config[ :domain ]
13
+ user_name = config[ :user_name ]
14
+ password = config[ :password ]
15
+ authentication = config[ :authentication ]
16
+
17
+ Net::SMTP.start( address, port, domain, user_name, password, authentication ) do |smtp|
18
+ smtp.send_message( '', StatusCat.config.from, StatusCat.config.noreply )
19
+ end
20
+ nil
21
+ end
22
+ end
23
+ end
24
+
25
+ def config
26
+ @config ||= ::ActionMailer::Base.smtp_settings
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ module StatusCat
2
+ module Checkers
3
+ class ActiveRecord < Base
4
+
5
+ def initialize
6
+ @value = "#{config[ :adapter ]}:#{config[ :username ]}@#{config[ :database ]}"
7
+
8
+ @status = fail_on_exception do
9
+ ::ActiveRecord::Base.connection.execute( "select max(version) from schema_migrations" )
10
+ nil
11
+ end
12
+ end
13
+
14
+ def config
15
+ unless @config
16
+ yaml = YAML::load( ERB.new( IO.read( File.join( Rails.root, 'config', 'database.yml' ) ) ).result )
17
+ @config = yaml[ Rails.env ].symbolize_keys!
18
+ end
19
+ return @config
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ module StatusCat
2
+ module Checkers
3
+ class Base
4
+ extend ActiveSupport::DescendantsTracker
5
+
6
+ FORMAT = "%s | %s | %s\n"
7
+
8
+ attr_reader :value, :status
9
+
10
+ def self.class_to_name( klass )
11
+ klass.to_s.split( '::' ).last.underscore.to_sym
12
+ end
13
+
14
+ def name
15
+ Base.class_to_name( self.class )
16
+ #self.class.to_s.split( '::' ).last.underscore.to_sym
17
+ end
18
+
19
+ def to_s( format = FORMAT )
20
+ sprintf( format, name, value, status || I18n.t( :ok, :scope => :status_cat ) )
21
+ end
22
+
23
+ protected
24
+
25
+ def fail_on_exception
26
+ begin
27
+ return yield
28
+ rescue Exception => e
29
+ return e
30
+ end
31
+
32
+ return nil
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ module StatusCat
2
+ module Checkers
3
+
4
+ class DelayedJob < Base
5
+ include ActionView::Helpers::DateHelper
6
+
7
+ def initialize
8
+ if !defined?( ::Delayed )
9
+ @status = 'delayed_job gem not installed'
10
+ else
11
+ @status = fail_on_exception do
12
+ sql = 'select count(*) from delayed_jobs'
13
+ result = ::ActiveRecord::Base.connection.execute( sql ).first
14
+ @value = result.is_a?( Hash ) ? result[ 'count' ] : result[ 0 ]
15
+
16
+ expires = 1.day.ago
17
+ sql = "select count(*) from delayed_jobs where created_at < '#{expires.to_s( :db )}'"
18
+ result = ::ActiveRecord::Base.connection.execute( sql ).first
19
+ value = result.is_a?( Hash ) ? result[ 'count' ] : result[ 0 ]
20
+
21
+ ( value.to_i == 0 ) ? nil : "#{value} jobs more than #{time_ago_in_words( expires )} old"
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module StatusCat
2
+ module Checkers
3
+ class S3 < Base
4
+ def initialize
5
+ if !defined?( ::AWS )
6
+ @status = 'aws-sdk gem not installed'
7
+ else
8
+ @value = AWS.config.access_key_id
9
+ @status = fail_on_exception do
10
+ s3 = AWS::S3.new
11
+ ( s3.buckets.count > 0 ) ? nil : 'no buckets'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ module StatusCat
2
+ module Checkers
3
+
4
+ class Stripe < Base
5
+ def initialize
6
+ if !defined?( ::Stripe )
7
+ @status = 'stripe gem not installed'
8
+ else
9
+ @status = fail_on_exception do
10
+ account = ::Stripe::Account.retrieve()
11
+ @value = account.email
12
+ account.charge_enabled ? nil : 'Charge is not enabled'
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ require 'singleton'
2
+
3
+ module StatusCat
4
+
5
+ class Config
6
+ include Singleton
7
+
8
+ NIL_PROC = proc {}
9
+
10
+ attr_accessor :enabled
11
+ attr_accessor :authenticate, :authorize
12
+ attr_accessor :from, :to, :subject, :noreply
13
+ attr_accessor :layout
14
+
15
+ def initialize
16
+ @enabled = StatusCat::Checkers::Base.descendants.map { |klass|
17
+ StatusCat::Checkers::Base.class_to_name( klass )
18
+ }.sort
19
+ end
20
+
21
+ def authenticate_with(&blk)
22
+ @authenticate = blk if blk
23
+ @authenticate || NIL_PROC
24
+ end
25
+
26
+ def authorize_with(&block)
27
+ @authorize = block if block
28
+ @authorize || NIL_PROC
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,5 @@
1
+ module StatusCat
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace StatusCat
4
+ end
5
+ end
@@ -0,0 +1,37 @@
1
+ module StatusCat
2
+
3
+ class Status
4
+
5
+ # Returns an array of instances of StatusCat::Checkers::Base subclasses
6
+ def self.all
7
+ StatusCat::Config.instance.enabled.map { |name| factory( name ) }
8
+ end
9
+
10
+ # By default, returns all checkers
11
+ # If given a list of checker names, returns an array of those checkers
12
+ # If given a single checker name, just returns that checker
13
+ def self.check( which = :all )
14
+ return all if which == :all
15
+ return factory( which ) unless which.is_a?( Array )
16
+ return which.map { |name| factory( name ) }
17
+ end
18
+
19
+ # Emails ::failed list if it is not empty
20
+ def self.cron
21
+ checkers = self.failed
22
+ StatusCat::StatusMailer.failure( checkers ).deliver unless checkers.empty?
23
+ end
24
+
25
+ # Constructs a checker instance given it's name
26
+ def self.factory( name )
27
+ ( 'StatusCat::Checkers::' + name.to_s.classify ).constantize.new
28
+ end
29
+
30
+ # Returns an array of failed instances of ::all
31
+ def self.failed
32
+ self.all.map { |checker| checker.status.nil? ? nil : checker }.compact
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,3 @@
1
+ module StatusCat
2
+ VERSION = '0.0.8'
3
+ end