system_health 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 96a950da89a77567a3adbde6e62909067be4f278
4
+ data.tar.gz: fd3e339d39b4d856d53146082098332936499b77
5
+ SHA512:
6
+ metadata.gz: 3ba4232c8569ff43d3744a1eabba6d1e5e8057dbf6823dd9f279a28164fd1c64e4e502bbf85534c5a9b84530d4e900883e2279ebaad41aacaf3a08f850dd1d78
7
+ data.tar.gz: 225c639c4bb66d66ef166255657dd637c65c0721c6ac3a745df0280f4ad89634e4223df46da6fe8a376cc9144bfae9b175409d270b6897957ac4210cc95a6637
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ system_health
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in system_health.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Stirling Olson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # System Health
2
+
3
+ The System Health gem can be added to your Rails application to provide
4
+ a convenient way to regularly look for bad data or other system health
5
+ indicators. It provides a single endpoint that will generate and error
6
+ count and enumerate error messages. This count and the messages can be
7
+ collected by external monitoring tools the look for the HTTP status code
8
+ (200 when there are no errors or 500 when there is at least one error)
9
+ and/or inspect the JSON payload that is returned.
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'system_health'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install system_health
24
+
25
+ and then...
26
+
27
+ 1. create an initializer in config/initializers/system_health.rb
28
+
29
+ ```ruby
30
+ SystemHealth.configure do |config|
31
+ config.monitor_classes = [
32
+ SystemHealth::Monitors::BadData
33
+ ]
34
+ end
35
+ ```
36
+
37
+ This should define the SYSTEM_HEALTH_MONITOR_CLASSES array with all
38
+ your monitor classes. There can be as many monitor classes as you wish.
39
+
40
+ 2. Create your monitor classes
41
+
42
+ In lib/system_health/monitors/bad_data.rb create:
43
+
44
+ ```ruby
45
+ module SystemHealth
46
+ module Monitors
47
+ class BadData < Base
48
+ def error_messages
49
+ ['some error message here'] if bad_data?
50
+ end
51
+
52
+ private
53
+
54
+ def bad_data?
55
+ # logic here
56
+ end
57
+ end
58
+ end
59
+ end
60
+ ```
61
+
62
+ Each monitor should define a public instance method for `error_messages`
63
+ as an array. If that array is empty then the data is good. When the
64
+ data is bad, one or more error messages can be placed in that array.
65
+ That is it!
66
+
67
+ 3. Define the environment variables
68
+
69
+ For applications hosted on Heroku, this might be something like:
70
+
71
+ ```bash
72
+ heroku config:add SYSTEM_HEALTH_MONITOR_USERNAME=somenamehere
73
+ heroku config:add SYSTEM_HEALTH_MONITOR_PASSWORD=somesecrethere
74
+ ```
75
+
76
+ on other environments, you'll need to define these elsewhere.
77
+
78
+ ## Usage
79
+
80
+ The System Health gem exposes a single controller endpoint at:
81
+ /system_health/monitor
82
+
83
+ It will return a 200 HTTP status code if there are no errors and a 500
84
+ HTTP status code if there are any errors. It also returns a JSON
85
+ payload with data like this:
86
+
87
+ ```json
88
+ {
89
+ "error_count": 2,
90
+ "messages": ["some error message here", "another error message"]
91
+ }
92
+ ```
93
+
94
+ ## To do?
95
+
96
+ 1. Consider how to deal with long running monitors that may fail with
97
+ page load limits (e.g. Heroku's 30 second timeout)
98
+ 2. Add ability to run different health monitors at different times or
99
+ possibly call monitors individually
100
+ 3. Add the ability to generate error notifications directly from System
101
+ Health instead of relying on external monitoring tools to send these
102
+
103
+ ## Contributing
104
+
105
+ 1. Fork it ( https://github.com/[my-github-username]/system_health/fork )
106
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
107
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
108
+ 4. Push to the branch (`git push origin my-new-feature`)
109
+ 5. Create a new Pull Request
110
+
111
+ ## About Foraker Labs
112
+
113
+ [![Foraker Logo](http://assets.foraker.com/attribution_logo.png)](https://www.foraker.com/)
114
+
115
+ [Foraker Labs](https://www.foraker.com/) builds exciting web and mobile apps in Boulder, CO. Our work powers a wide variety of businesses with many different needs. We love open source software, and we're proud to contribute where we can. Interested to learn more? [Contact us today](https://www.foraker.com/contact-us).
116
+
117
+ This project is maintained by Foraker Labs. The names and logos of Foraker Labs are fully owned and copyright Foraker Design, LLC.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,21 @@
1
+ module SystemHealth
2
+ class MonitorsController < ApplicationController
3
+ http_basic_authenticate_with \
4
+ name: ENV['SYSTEM_HEALTH_USERNAME'],
5
+ password: ENV['SYSTEM_HEALTH_PASSWORD']
6
+
7
+ def show
8
+ render json: monitor.as_json, status: monitor.http_status
9
+ end
10
+
11
+ private
12
+
13
+ def monitor
14
+ @monitor ||= SystemHealth::Monitor.new(monitor_classes)
15
+ end
16
+
17
+ def monitor_classes
18
+ SystemHealth.configuration.monitor_classes
19
+ end
20
+ end
21
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ namespace :system_health do
3
+ resource :monitor, :only => :show
4
+ end
5
+ end
@@ -0,0 +1,19 @@
1
+ require 'system_health/configuration'
2
+ require 'system_health/engine'
3
+ require 'system_health/monitor'
4
+ require 'system_health/version'
5
+ require 'system_health/monitors/base'
6
+
7
+ module SystemHealth
8
+ class << self
9
+ attr_writer :configuration
10
+ end
11
+
12
+ def self.configuration
13
+ @configuration ||= Configuration.new
14
+ end
15
+
16
+ def self.configure
17
+ yield(configuration)
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ module SystemHealth
2
+ class Configuration
3
+ attr_accessor :monitor_classes
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module SystemHealth
2
+ class Engine < Rails::Engine; end
3
+ end
@@ -0,0 +1,33 @@
1
+ module SystemHealth
2
+ class Monitor
3
+ def initialize(monitor_classes)
4
+ @monitor_classes = monitor_classes
5
+ end
6
+
7
+ def as_json(options = nil)
8
+ {
9
+ error_count: error_count,
10
+ messages: messages
11
+ }
12
+ end
13
+
14
+ def http_status
15
+ error_count > 0 ? 500 : 200
16
+ end
17
+
18
+ private
19
+ attr_reader :monitor_classes
20
+
21
+ def error_count
22
+ monitors.sum(&:error_count)
23
+ end
24
+
25
+ def messages
26
+ monitors.flat_map(&:error_messages)
27
+ end
28
+
29
+ def monitors
30
+ @monitors ||= monitor_classes.map(&:new)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,9 @@
1
+ module SystemHealth
2
+ module Monitors
3
+ class Base
4
+ def error_count
5
+ error_messages.count
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module SystemHealth
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,57 @@
1
+ require 'active_support/all'
2
+ require_relative '../../../lib/system_health/monitor'
3
+ require_relative '../../../lib/system_health/monitors/base'
4
+
5
+ module SystemHealth
6
+ describe Monitor do
7
+
8
+ class MonitorDouble < Monitors::Base
9
+ def error_messages
10
+ []
11
+ end
12
+ end
13
+
14
+ let(:monitor_classes) { [MonitorDouble] }
15
+ let(:monitor) { described_class.new(monitor_classes) }
16
+
17
+ context 'when errors' do
18
+ before do
19
+ allow_any_instance_of(MonitorDouble).
20
+ to receive(:error_messages).
21
+ and_return(['something broke'])
22
+ end
23
+
24
+ describe '#as_json' do
25
+ it 'returns error_count and messages' do
26
+ expect(monitor.as_json).to eq({
27
+ error_count: 1,
28
+ messages: ['something broke']
29
+ })
30
+ end
31
+ end
32
+
33
+ describe '#http_status' do
34
+ it 'returns 500' do
35
+ expect(monitor.http_status).to eq 500
36
+ end
37
+ end
38
+ end
39
+
40
+ context 'when no errors' do
41
+ describe '#as_json' do
42
+ it 'returns error_count and messages' do
43
+ expect(monitor.as_json).to eq({
44
+ error_count: 0,
45
+ messages: []
46
+ })
47
+ end
48
+ end
49
+
50
+ describe '#http_status' do
51
+ it 'returns 200 when no errors' do
52
+ expect(monitor.http_status).to eq 200
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'system_health/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "system_health"
8
+ spec.version = SystemHealth::VERSION
9
+ spec.authors = ["Stirling Olson"]
10
+ spec.email = ["seo@foraker.com"]
11
+ spec.summary = %q{System health monitor for Rails apps}
12
+ spec.description = %q{}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "rails"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: system_health
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Stirling Olson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
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: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
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: rspec
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
+ description: ''
70
+ email:
71
+ - seo@foraker.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".ruby-gemset"
78
+ - ".ruby-version"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - app/controllers/system_health/monitors_controller.rb
84
+ - config/routes.rb
85
+ - lib/system_health.rb
86
+ - lib/system_health/configuration.rb
87
+ - lib/system_health/engine.rb
88
+ - lib/system_health/monitor.rb
89
+ - lib/system_health/monitors/base.rb
90
+ - lib/system_health/version.rb
91
+ - spec/lib/system_health/monitor_spec.rb
92
+ - system_health.gemspec
93
+ homepage: ''
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.4.5.1
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: System health monitor for Rails apps
117
+ test_files:
118
+ - spec/lib/system_health/monitor_spec.rb