simple_monitor 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,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rspec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in simple_monitor.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ SimpleMonitor
2
+ =============
3
+
4
+ Send alerts based on simple monitored conditions in your app.
5
+
6
+ It provides a basic skeleton for writing unique but consistent
7
+ monitoring checks for your application. Examples of such checks
8
+ are a Delayed::Job queue that is too full, too many failed logins
9
+ in the last 5 minutes, or a remote service being unreachable.
10
+
11
+ Installation
12
+ ------------
13
+
14
+ install it via rubygems:
15
+
16
+ ```
17
+ gem install simple_monitor
18
+ ```
19
+
20
+ or put it in your Gemfile:
21
+
22
+ ```ruby
23
+ # Gemfile
24
+ gem 'simple_monitor'
25
+ ```
26
+
27
+ Usage
28
+ -----
29
+
30
+ SimpleMonitor should be mixed in to a SomeConditionMonitor class
31
+
32
+ ```ruby
33
+ require "simple_monitor"
34
+
35
+ class HighJobMonitor
36
+ include SimpleMonitor
37
+
38
+ def needs_alert?
39
+ Queue.jobs.count > options[:job_count_threshold]
40
+ end
41
+
42
+ def send_alert
43
+ # Alert sending method of your choice. SimpleMonitor
44
+ # leaves this up to you
45
+ Mailer.deliver_high_job_alert(Queue.jobs.count)
46
+ end
47
+ end
48
+
49
+ monitor = HighJobMonitor.new(:job_count_threshold => 99)
50
+ monitor.check
51
+ ```
52
+
53
+ For a typical application, it could be desireable to define an
54
+ AppMonitor class with a default send_alert method, and have your
55
+ individual monitor classes inherit from that.
56
+
57
+ A monitor class can take options on initialization; this is recommended
58
+ for passing in thresholds, email addresses, or other dependencies.
59
+
60
+ Logging
61
+ -------
62
+
63
+ SimpleMonitor defaults its logger to a new Logger instance, or
64
+ Rails.logger if that is defined. If you want to override this,
65
+ do so in your class or via the `logger=` instance method.
66
+
67
+ When running a `check`, the logger will be warned or provided
68
+ with info whether an alert was needed. Note this is in addition
69
+ to sending out an alert.
70
+
71
+ #### Copyright
72
+
73
+ Copyright (c) (2012) Brendon Murphy. See license.txt for details.
74
+
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,3 @@
1
+ module SimpleMonitor
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,92 @@
1
+ require "simple_monitor/version"
2
+
3
+ module SimpleMonitor
4
+ attr_reader :options
5
+ attr_accessor :logger
6
+
7
+ LOG_METHODS = %w[info warn error debug].freeze
8
+
9
+ def initialize(options = {})
10
+ @options = options
11
+ end
12
+
13
+ # Runs the check and sends an alert if needed
14
+ #
15
+ # Returns false if the check failed, true if passed
16
+ def check
17
+ if needs_alert?
18
+ warn_alert
19
+ send_alert
20
+ false
21
+ else
22
+ info_passed
23
+ true
24
+ end
25
+ end
26
+
27
+ def warn_alert
28
+ warn(alert_log_message)
29
+ end
30
+
31
+ # Public: Message to log in case of an alert
32
+ #
33
+ # Override this in your monitors to inject data
34
+ #
35
+ # Returns: String
36
+ def alert_log_message
37
+ "check generated an alert"
38
+ end
39
+
40
+ def info_passed
41
+ info(passed_log_message)
42
+ end
43
+
44
+ # Public: Message to log in case of a check passing
45
+ #
46
+ # Override this in your monitors to inject data
47
+ #
48
+ # Returns: String
49
+ def passed_log_message
50
+ "check passed"
51
+ end
52
+
53
+ # Public: Conditional method to check if the alert should be sent
54
+ #
55
+ # This should be overridden in your individual monitor classes
56
+ #
57
+ # Returns a boolean
58
+ def needs_alert?
59
+ false
60
+ end
61
+
62
+ # Public: Send out an alert
63
+ #
64
+ # This should be overridden in your individual monitor classes,
65
+ # or base monitor class. This might be to send an SMS, email
66
+ # or IRC message
67
+ def send_alert
68
+ #no-op
69
+ end
70
+
71
+ # A memoized logger.
72
+ #
73
+ # Returns: a logger that responds to warn, info, debug, and error
74
+ def logger
75
+ @logger ||=
76
+ if defined?(Rails)
77
+ Rails.logger
78
+ else
79
+ require "logger"
80
+ Logger.new(STDOUT)
81
+ end
82
+ end
83
+
84
+ # Generated methods delegated to the logger. This is for convenience
85
+ # as well as for prefixing the monitor class name into the message
86
+ LOG_METHODS.each do |method|
87
+ define_method method do |message|
88
+ message = [self.class.name, message.to_s].join(" -- ")
89
+ logger.send(method, message)
90
+ end
91
+ end
92
+ end
data/license.txt ADDED
@@ -0,0 +1,23 @@
1
+ licensed under MIT License:
2
+
3
+ Copyright (c) 2012 Brendon Murphy
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.
23
+
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "simple_monitor/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "simple_monitor"
7
+ s.version = SimpleMonitor::VERSION
8
+ s.authors = ["Brendon Murphy"]
9
+ s.email = ["xternal1+github@gmail.com"]
10
+ s.licenses = ["MIT"]
11
+ s.homepage = ""
12
+ s.summary = %q{Send alerts based on simple monitored conditions in your app}
13
+ s.description = s.description
14
+
15
+ s.rubyforge_project = "simple_monitor"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency "rake"
23
+ s.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ class TestMonitor
4
+ include SimpleMonitor
5
+
6
+ attr_reader :last_alert
7
+
8
+ def needs_alert?
9
+ options[:force_alert]
10
+ end
11
+
12
+ def send_alert
13
+ @last_alert = "Test Monitor Alert"
14
+ end
15
+ end
16
+
17
+ describe SimpleMonitor do
18
+ it "is initialized with optional options" do
19
+ monitor = TestMonitor.new
20
+ monitor = TestMonitor.new(:foo => :bar)
21
+ monitor.options[:foo].should == :bar
22
+ end
23
+ end
24
+
25
+ describe SimpleMonitor, "logger" do
26
+ subject { TestMonitor.new }
27
+
28
+ it "is defaulted to Logger.new(STDOUT)" do
29
+ subject.logger.should be_kind_of(Logger)
30
+ end
31
+
32
+ # Problem, what if its vendored and rails and run in a spec run
33
+ # that boots rails?
34
+ it "is defaulted to the Rails.logger if present" do
35
+ module Rails
36
+ def self.logger
37
+ :rails_logger
38
+ end
39
+ end
40
+
41
+ subject.logger.should == :rails_logger
42
+
43
+ Object.send(:remove_const, :Rails)
44
+ end
45
+
46
+ it "sends info, warn, error, and debug methods to it prefixed by the class name" do
47
+ stub_logger = stub('logger')
48
+ subject.logger = stub_logger
49
+ %w[info warn error debug].each do |log_method|
50
+ stub_logger.should_receive(log_method).with("TestMonitor -- #{log_method}")
51
+ subject.send(log_method, log_method)
52
+ end
53
+ end
54
+ end
55
+
56
+ describe SimpleMonitor, "running the check" do
57
+ subject { TestMonitor.new }
58
+ let(:logger) { stub('logger', :warn => nil, :info => nil) }
59
+ before { subject.logger = logger }
60
+
61
+ context "when an alert needs sending" do
62
+ before { subject.options[:force_alert] = true }
63
+
64
+ it "logs a warning that the check is in alert" do
65
+ logger.should_receive(:warn).with(/TestMonitor --.*alert/)
66
+ subject.check
67
+ end
68
+
69
+ it "sends an alert" do
70
+ subject.check
71
+ subject.last_alert.should == "Test Monitor Alert"
72
+ end
73
+
74
+ it "returns false" do
75
+ subject.check.should == false
76
+ end
77
+ end
78
+
79
+ context "when no alert needs sending" do
80
+ before { subject.options[:force_alert] = false }
81
+
82
+ it "logs info that the check passed" do
83
+ logger.should_receive(:info).with(/TestMonitor --.*passed/)
84
+ subject.check
85
+ end
86
+
87
+ it "doesn't send an alert" do
88
+ subject.check
89
+ subject.last_alert.should be_nil
90
+ end
91
+
92
+ it "returns true" do
93
+ subject.check.should == true
94
+ end
95
+ end
96
+ end
97
+
98
+ describe SimpleMonitor, "supports a class including SimpleMonitor" do
99
+ class ChildTestMonitor < TestMonitor
100
+ def needs_alert?
101
+ true
102
+ end
103
+
104
+ def send_alert
105
+ @last_alert = "CHILD HERE"
106
+ end
107
+ end
108
+
109
+ subject { ChildTestMonitor.new }
110
+ let(:logger) { stub('logger', :warn => nil, :info => nil) }
111
+ before { subject.logger = logger }
112
+
113
+ it "to be inherited" do
114
+ subject.check
115
+ subject.last_alert.should == "CHILD HERE"
116
+ end
117
+ end
@@ -0,0 +1,6 @@
1
+ require File.expand_path("../../lib/simple_monitor", __FILE__)
2
+
3
+ RSpec.configure do |config|
4
+ config.mock_with :rspec
5
+ end
6
+
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_monitor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Brendon Murphy
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-21 00:00:00.000000000 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ requirement: &2160677420 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *2160677420
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &2160677000 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *2160677000
37
+ description: ''
38
+ email:
39
+ - xternal1+github@gmail.com
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - README.md
47
+ - Rakefile
48
+ - lib/simple_monitor.rb
49
+ - lib/simple_monitor/version.rb
50
+ - license.txt
51
+ - simple_monitor.gemspec
52
+ - spec/simple_monitor_spec.rb
53
+ - spec/spec_helper.rb
54
+ has_rdoc: true
55
+ homepage: ''
56
+ licenses:
57
+ - MIT
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project: simple_monitor
76
+ rubygems_version: 1.6.2
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Send alerts based on simple monitored conditions in your app
80
+ test_files:
81
+ - spec/simple_monitor_spec.rb
82
+ - spec/spec_helper.rb