servicemonitor 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+ require 'monitor_type/threshold'
2
+ require 'helper_functions'
3
+
4
+ InvalidProcessNameError = Class.new(StandardError)
5
+
6
+ # A class for checking if a Process is running in Unix based systems
7
+ class MonitorTypeProcess < MonitorTypeThreshold
8
+ # Extract parameters
9
+ #
10
+ # @param [String] :process_name THe name of the process to monitor
11
+ def extract_params
12
+ if @params[:process_name].nil?
13
+ string = "*** Process Name parameter missing, process_name\n" \
14
+ '*** :process_name => <name of the process to ' \
15
+ 'be monitored>'
16
+ fail MonitorTypeParameterMissingError, string
17
+ end
18
+ @process_name = @params[:process_name]
19
+
20
+ log "#{@process_name}", "result: #{(@process_name =~ /^(.*\[{1}.+\]{1}.*)$|^(\w+)$/) == 0}"
21
+
22
+ unless (@process_name =~ /^(.*\[{1}.+\]{1}.*)$|^(\w+)$/) == 0
23
+ string = '*** Process Name parameter doest not match the required ' \
24
+ "pattern, #{@process_name}\n" \
25
+ "*** :process_name => <plain string, or a string " \
26
+ 'with one or more characters enclosed in square brackets, ' \
27
+ "i.e. 'foo', '[f]oo' or '[foo]'>"
28
+ fail InvalidProcessNameError, string
29
+ end
30
+
31
+ log '*** Min value will be ignored, setting to 1' unless (params[:min].nil? || params[:min] == 0)
32
+ @min = 1
33
+
34
+ log '*** Max value will be ignored, setting to nil' unless params[:max].nil?
35
+ @max = nil
36
+
37
+ @context_sentence = "Checking that process is running, #{@process_name}"
38
+ end
39
+
40
+ def setup
41
+ sanitise
42
+ rescue MonitorTypeExceptionHandled => e
43
+ puts e.message
44
+ abort
45
+ end
46
+
47
+ def sanitise
48
+ # Ensure that the process name contains a single character surrounded
49
+ # by square brackets
50
+ @process_name = @process_name.insert(0,'[').insert(2,']') unless @process_name =~ /^.*\[.+\].*/
51
+ end
52
+
53
+ def derived_value
54
+ `ps aux | grep #{@process_name}`.length
55
+ end
56
+ end
57
+
58
+ def process(params)
59
+ $a.add(MonitorTypeProcess.new(params))
60
+ end
@@ -0,0 +1,44 @@
1
+ require 'monitor_type'
2
+
3
+ # A base class for checking a number against a min and/or max value
4
+ class MonitorTypeThreshold < MonitorType
5
+ # See super method for generic description
6
+ def initialize(params)
7
+ @min = params[:min] ||= 0
8
+ @max = params[:max]
9
+ super(params)
10
+ end
11
+
12
+ # Get the context dependent value which is to be checked
13
+ def derived_value
14
+ fail 'Method needs to be overridden'
15
+ end
16
+
17
+ def process
18
+ if @block.nil?
19
+ value = derived_value
20
+ else
21
+ value = @block.call(@params)
22
+ string = "value: #{value}\n"
23
+ puts string
24
+ end
25
+
26
+ check(value)
27
+ end
28
+
29
+ # Provides the means to check a value against thresholds
30
+ def check(value)
31
+ context_sentence = @context_sentence.nil? ? '' : "#{@context_sentence}\n"
32
+ url = @url.nil? ? '' : "\n\n#{@url}\n"
33
+
34
+ value = value.to_i
35
+
36
+ alert("#{context_sentence}Minimum threshold exceeded. " \
37
+ "Minimum: #{@min}, " \
38
+ "Actual: #{value}#{url}") if !@min.nil? && value < @min
39
+
40
+ alert("#{context_sentence}Maximum threshold exceeded. " \
41
+ "Maximum: #{@max}, " \
42
+ "Actual: #{value}#{url}") if !@max.nil? && value > @max
43
+ end
44
+ end
@@ -0,0 +1,114 @@
1
+ require 'parse-cron'
2
+ # This is provided for reporting purposes.
3
+ # It essentially indicates if an error case was expected
4
+ #
5
+ # The idea is to provide clear direction to the user to fix the error, but
6
+ # not stop all monitors in case of a production issue.
7
+ class MonitorTypeExceptionHandled < StandardError
8
+ end
9
+
10
+ class MonitorTypeParameterMissingError < MonitorTypeExceptionHandled
11
+ end
12
+
13
+ class MonitorTypeMustHaveNameError < MonitorTypeParameterMissingError
14
+ end
15
+
16
+ class MonitorTypeMustHaveSenderEmailAddressForEmailAlertError < MonitorTypeParameterMissingError
17
+ end
18
+
19
+ # Base class for Monitors
20
+ #
21
+ # Given that this is a DSL, it extracts named parameters from a hash in order
22
+ # to provide more precise reporting of errors, without spewing syntax errors
23
+ # at a user
24
+ class MonitorType
25
+ # Check that all required parameters have been passed in
26
+ # Make sure that any errors encountered are reported in a way that
27
+ # fixing the error is made easier
28
+ def initialize(params)
29
+ if params[:name].nil?
30
+ string = '*** Monitor parameter missing, name' \
31
+ '*** :name => <name of monitor>'
32
+ fail MonitorTypeMustHaveNameError, string
33
+ end
34
+ @params = params
35
+ @block = params[:block] unless params[:block].nil?
36
+ @name = params[:name]
37
+ @email = params[:email]
38
+ @url = params[:url] unless params[:url].nil?
39
+
40
+ if !@email.nil?
41
+ # Sender email address from ENV allows for a single sender across all alerts
42
+ # Checking params before ENV allows a particular entry to be different
43
+ if params[:email_sender].nil?
44
+ if ENV['EMAIL_SENDER'].nil?
45
+ string = '*** Alert parameter missing, email_sender' \
46
+ '*** An email recipient has been specified for monitor, ' \
47
+ "#{@name}, but no email sender has been specified" \
48
+ '*** :email_sender => <email of sender>' \
49
+ '*** or, a catch all environment variable' \
50
+ '*** EMAIL_SENDER=<email of sender>'
51
+
52
+ fail MonitorTypeMustHaveSenderEmailAddressForEmailAlertError, string
53
+ else
54
+ @sender_email = ENV['EMAIL_SENDER']
55
+ end
56
+ else
57
+ @sender_email = params[:admin_email]
58
+ end
59
+ end
60
+
61
+ cron_string = params[:cron] || '0 1 * * *'
62
+ @cron = CronParser.new(cron_string)
63
+ @next = Time.now - 1
64
+
65
+ log "Loaded Monitor, #{@name}."
66
+ end
67
+
68
+ # Overload this method if any parameters should be checked in context
69
+ def extract_params
70
+ end
71
+
72
+ # Overload this method if any parameters should be checked in context
73
+ def setup
74
+ end
75
+
76
+ # Overload this method if any parameters should be checked in context
77
+ def teardown
78
+ end
79
+
80
+ # Check if the monitor has tripped
81
+ def process
82
+ fail 'Method needs to be overridden'
83
+ end
84
+
85
+ # An extention of the main run loop.
86
+ # Each monitor is responsible for knowing when it should run, so this function
87
+ # is called pretty much continuosuly.
88
+ def run
89
+ return unless Time.now > @next
90
+
91
+ @next = @cron.next(Time.now)
92
+ log "Monitor, #{@name}, next run time, #{@next}"
93
+ extract_params
94
+ setup
95
+ process
96
+ teardown
97
+ rescue MonitorTypeExceptionHandled => e
98
+ alert(e.message)
99
+ end
100
+
101
+ # Called when a monitor has been tripped
102
+ #
103
+ # @param [String] string A description of the trip that occurred
104
+ def alert(string)
105
+ body = "#{@name} tripped.\n#{string}"
106
+ puts '*** '
107
+ if !@email.nil?
108
+ AlertEmail.new(@sender_email, @email, body).Send
109
+ puts "Emailed, #{@email}"
110
+ else
111
+ puts body
112
+ end
113
+ end
114
+ end
metadata CHANGED
@@ -1,60 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servicemonitor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Guy Irvine
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2015-03-04 00:00:00.000000000 Z
11
+ date: 2016-08-16 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: parse-cron
16
- requirement: &70142485328220 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
- version_requirements: *70142485328220
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
25
27
  - !ruby/object:Gem::Dependency
26
28
  name: beanstalk-client
27
- requirement: &70142485327780 !ruby/object:Gem::Requirement
28
- none: false
29
+ requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
- - - ! '>='
31
+ - - '>='
31
32
  - !ruby/object:Gem::Version
32
33
  version: '0'
33
34
  type: :runtime
34
35
  prerelease: false
35
- version_requirements: *70142485327780
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
36
41
  - !ruby/object:Gem::Dependency
37
42
  name: fluiddb
38
- requirement: &70142485327360 !ruby/object:Gem::Requirement
39
- none: false
43
+ requirement: !ruby/object:Gem::Requirement
40
44
  requirements:
41
- - - ! '>='
45
+ - - '>='
42
46
  - !ruby/object:Gem::Version
43
47
  version: '0'
44
48
  type: :runtime
45
49
  prerelease: false
46
- version_requirements: *70142485327360
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
47
55
  - !ruby/object:Gem::Dependency
48
56
  name: rest-client
49
- requirement: &70142485326940 !ruby/object:Gem::Requirement
50
- none: false
57
+ requirement: !ruby/object:Gem::Requirement
51
58
  requirements:
52
- - - ! '>='
59
+ - - '>='
53
60
  - !ruby/object:Gem::Version
54
61
  version: '0'
55
62
  type: :runtime
56
63
  prerelease: false
57
- version_requirements: *70142485326940
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
58
69
  description: The fastest way to reliably monitor your system.
59
70
  email: guy@guyirvine.com
60
71
  executables:
@@ -62,44 +73,43 @@ executables:
62
73
  extensions: []
63
74
  extra_rdoc_files: []
64
75
  files:
65
- - lib/Alert/Email.rb
66
- - lib/Alert.rb
76
+ - lib/alert/email.rb
77
+ - lib/alert.rb
67
78
  - lib/helper_functions.rb
68
- - lib/MonitorManager.rb
69
- - lib/MonitorType/Beanstalk.rb
70
- - lib/MonitorType/Dir.rb
71
- - lib/MonitorType/Drive.rb
72
- - lib/MonitorType/FluidDb.rb
73
- - lib/MonitorType/HttpGetJsonList.rb
74
- - lib/MonitorType/Process.rb
75
- - lib/MonitorType/Threshold.rb
76
- - lib/MonitorType.rb
79
+ - lib/monitor_manager.rb
80
+ - lib/monitor_type/beanstalk.rb
81
+ - lib/monitor_type/dir.rb
82
+ - lib/monitor_type/drive.rb
83
+ - lib/monitor_type/fluiddb.rb
84
+ - lib/monitor_type/http_get_json_list.rb
85
+ - lib/monitor_type/process.rb
86
+ - lib/monitor_type/threshold.rb
87
+ - lib/monitor_type.rb
77
88
  - bin/servicemonitor
78
89
  - LICENSE
79
90
  - README.md
80
91
  homepage: http://rubygems.org/gems/servicemonitor
81
- licenses: []
92
+ licenses:
93
+ - LGPL-3.0
94
+ metadata: {}
82
95
  post_install_message:
83
96
  rdoc_options: []
84
97
  require_paths:
85
98
  - lib
86
99
  required_ruby_version: !ruby/object:Gem::Requirement
87
- none: false
88
100
  requirements:
89
- - - ! '>='
101
+ - - '>='
90
102
  - !ruby/object:Gem::Version
91
103
  version: '0'
92
104
  required_rubygems_version: !ruby/object:Gem::Requirement
93
- none: false
94
105
  requirements:
95
- - - ! '>='
106
+ - - '>='
96
107
  - !ruby/object:Gem::Version
97
108
  version: '0'
98
109
  requirements: []
99
110
  rubyforge_project:
100
- rubygems_version: 1.8.11
111
+ rubygems_version: 2.0.14.1
101
112
  signing_key:
102
- specification_version: 3
113
+ specification_version: 4
103
114
  summary: ServiceMonitor
104
115
  test_files: []
105
- has_rdoc:
data/lib/Alert/Email.rb DELETED
@@ -1,43 +0,0 @@
1
- require "net/smtp"
2
- require "Alert"
3
-
4
- #Email alert class
5
- #Uses localhost for sending email - Probably need to change this in the future.
6
- class Alert_Email
7
- def initialize( sender, destination, body )
8
- @sender = sender
9
- @body = body
10
-
11
- @smtp_address = ENV['smtp_address'].nil? ? 'localhost' : ENV['smtp_address']
12
- @smtp_port = ENV['smtp_port'].nil? ? 25 : ENV['smtp_port']
13
-
14
- @destination = destination
15
- if destination.is_a? Array then
16
- @destination_fmt = "<#{destination.join( ">,<" )}>"
17
- else
18
- @destination_fmt = destination
19
- end
20
- end
21
-
22
- def Send
23
- message = <<MESSAGE_END
24
- From: #{ENV['APP_NAME']} #{@sender}
25
- To: #{@destination_fmt}
26
- Subject: #{ENV['APP_NAME']} Alert
27
-
28
- #{@body}
29
- .
30
- MESSAGE_END
31
-
32
- Net::SMTP.start(@smtp_address,@smtp_port) do |smtp|
33
- smtp.send_message message, @sender,
34
- @destination
35
- end
36
-
37
- rescue Errno::ECONNREFUSED => e
38
- string = "*** Conection refused while attempting to connect to SMTP server\n"
39
- string = "#{string}*** Recipient, #{@destination}. Body,\n"
40
- string = "#{string}*** #{@body}\n"
41
- puts string
42
- end
43
- end
data/lib/Alert.rb DELETED
@@ -1,7 +0,0 @@
1
- #Base class / Interface for implementing alert types
2
- class Alert
3
-
4
- def Send( destination, body )
5
- raise "Method needs to be overridden"
6
- end
7
- end
@@ -1,36 +0,0 @@
1
-
2
- class MonitorManager
3
- def initialize
4
- @list = Array.new
5
- end
6
-
7
- def add( monitor )
8
- @list.push monitor
9
- end
10
-
11
- #The main run loop
12
- def run
13
- while true do
14
- @list.each do |m|
15
- begin
16
- m.run
17
- rescue MonitorTypeExceptionHandled => e
18
- m.alert( e.message )
19
- end
20
- end
21
- sleep 0.2
22
- end
23
-
24
- rescue Interrupt => e
25
- string = "Exiting on request ...\n"
26
- puts string
27
-
28
- rescue Exception => e
29
- string = "#{e.class.name}\n"
30
- string = "#{string}*** This is really unexpected.\n"
31
- string = "#{string}Message: #{e.message}\n"
32
- string = "#{string}e.backtrace\n"
33
- puts string
34
- end
35
- end
36
-