servicemonitor 0.1.4 → 0.2.0

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.
@@ -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
-