servicemonitor 0.0.16 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -7,7 +7,7 @@ Foundation (FSF), version {3.0}[http://www.gnu.org/licenses/gpl-3.0.txt]
7
7
  or version {2.0}[http://www.gnu.org/licenses/gpl-2.0.txt]
8
8
  or the Ruby-specific license terms (see below).
9
9
 
10
- The rservicebus project leader (Guy Irvine) reserves the right to add future
10
+ The ServiceMonitor project leader (Guy Irvine) reserves the right to add future
11
11
  versions of the GPL (and no other licenses) as published by the FSF to
12
12
  the licensing terms.
13
13
 
data/bin/servicemonitor CHANGED
@@ -11,20 +11,14 @@ require "MonitorType/Threshold"
11
11
  require "MonitorType/Beanstalk"
12
12
  require "MonitorType/Dir"
13
13
  require "MonitorType/FluidDb"
14
+ require "MonitorType/Process"
14
15
  require "MonitorManager"
16
+ require "helper_functions"
17
+
15
18
 
16
19
  #Don't buffer stdout
17
20
  $stdout.sync = true
18
21
 
19
- def log( string, verbose=false )
20
- type = verbose ? "VERB" : "INFO"
21
- if !ENV["VERBOSE"].nil? || verbose==false then
22
- timestamp = Time.new.strftime( "%Y-%m-%d %H:%M:%S" )
23
- puts "[#{type}] #{timestamp} :: #{string}"
24
- end
25
- end
26
-
27
-
28
22
  if ARGV.length == 1 then
29
23
  dslName = ARGV[0]
30
24
  else
@@ -47,7 +41,7 @@ begin
47
41
  rescue SystemExit=>e
48
42
  # rescue SIGTERM=>e
49
43
  rescue Exception=>e
44
+ puts "What the ..."
50
45
  puts e.class.name
51
46
  puts e.message
52
47
  end
53
-
data/lib/Alert/Email.rb CHANGED
@@ -7,6 +7,9 @@ class Alert_Email
7
7
  def initialize( sender, destination, body )
8
8
  @sender = sender
9
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']
10
13
 
11
14
  if destination.is_a? Array then
12
15
  @destination = "<#{destination.join( ">,<" )}>"
@@ -25,15 +28,16 @@ Subject: #{ENV['APP_NAME']} Alert
25
28
  .
26
29
  MESSAGE_END
27
30
 
28
- Net::SMTP.start('localhost') do |smtp|
31
+ Net::SMTP.start(@smtp_address,@smtp_port) do |smtp|
29
32
  smtp.send_message message, @sender,
30
33
  @destination
31
34
  end
32
35
 
33
36
  rescue Errno::ECONNREFUSED => e
34
- puts "*** Conection refused while attempting to connect to SMTP server"
35
- puts "*** Recipient, #{@destination}. Body,"
36
- puts "*** #{@body}"
37
+ string = "*** Conection refused while attempting to connect to SMTP server\n"
38
+ string = "#{string}*** Recipient, #{@destination}. Body,\n"
39
+ string = "#{string}*** #{@body}\n"
40
+ puts string
37
41
  end
38
42
  end
39
43
 
@@ -13,7 +13,6 @@ class MonitorManager
13
13
  while true do
14
14
  @list.each do |m|
15
15
  begin
16
- m.sanitise
17
16
  m.run
18
17
  rescue MonitorTypeExceptionHandled => e
19
18
  m.alert( e.message )
@@ -23,14 +22,15 @@ class MonitorManager
23
22
  end
24
23
 
25
24
  rescue Interrupt => e
26
- puts "Exiting on request ..."
25
+ string = "Exiting on request ...\n"
26
+ puts string
27
27
 
28
28
  rescue Exception => e
29
- puts e.class.name
30
- puts "*** This is really unexpected."
31
- messageLoop = false
32
- puts "Message: " + e.message
33
- puts e.backtrace
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
34
  end
35
35
  end
36
36
 
data/lib/MonitorType.rb CHANGED
@@ -1,66 +1,86 @@
1
1
  require 'parse-cron'
2
2
 
3
3
  #This is provided for reporting purposes.
4
- # If this is raised on startup, the process will fail, and stop running.
5
- # If this is raised after startup, the process will report, but keep running.
4
+ # It essentially indicates if an error case was expected
6
5
  #
7
6
  #The idea is to provide clear direction to the user to fix the error, but
8
7
  # not stop all monitors in case of a production issue.
9
8
  class MonitorTypeExceptionHandled<StandardError
10
9
  end
11
10
 
11
+ class MonitorTypeParameterMissingError<MonitorTypeExceptionHandled
12
+ end
13
+
14
+ class MonitorTypeMustHaveNameError<MonitorTypeParameterMissingError
15
+ end
16
+
17
+ class MonitorTypeMustHaveSenderEmailAddressForEmailAlertError<MonitorTypeParameterMissingError
18
+ end
19
+
20
+
12
21
  #Base class for Monitors
13
22
  #
14
23
  #Given that this is a DSL, it extracts named parameters from a hash in order to provide
15
24
  #more precise reporting of errors, without spewing syntax errors at a user
16
25
  class MonitorType
17
-
26
+
18
27
  #Check that all required parameters have been passed in
19
28
  #Make sure that any errors encountered are reported in a way that
20
29
  # fixing the error is made easier
21
30
  def initialize( params )
22
31
  if params[:name].nil? then
23
- puts "*** Monitor parameter missing, name"
24
- puts "*** :name => <name of monitor>"
25
- abort
32
+ string = "*** Monitor parameter missing, name"
33
+ string = "#{string}*** :name => <name of monitor>"
34
+ raise MonitorTypeMustHaveNameError.new(string)
26
35
  end
27
36
  @params = params
28
37
  @block = params[:block] if !params[:block].nil?
29
38
  @name = params[:name]
30
39
  @email = params[:email]
31
40
  if !@email.nil? then
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
32
43
  if params[:email_sender].nil? then
33
44
  if ENV["EMAIL_SENDER"].nil? then
34
- puts "*** Alert parameter missing, email_sender"
35
- puts "*** An email recipient has been specified for monitor, #{@name}, but no email sender has been specified"
36
- puts "*** :email_sender => <email of sender>"
37
- puts "*** or, a catch all environment variable"
38
- puts "*** EMAIL_SENDER=<email of sender>"
39
- abort
40
- else
45
+ string = "*** Alert parameter missing, email_sender"
46
+ string = "#[string}*** An email recipient has been specified for monitor, #{@name}, but no email sender has been specified"
47
+ string = "#[string}*** :email_sender => <email of sender>"
48
+ string = "#[string}*** or, a catch all environment variable"
49
+ string = "#[string}*** EMAIL_SENDER=<email of sender>"
50
+
51
+ raise MonitorTypeMustHaveSenderEmailAddressForEmailAlertError.new(string)
52
+ else
41
53
  @sender_email = ENV["EMAIL_SENDER"]
42
54
  end
43
- else
55
+ else
44
56
  @sender_email = params[:admin_email]
45
57
  end
46
58
  end
47
-
59
+
48
60
  cron_string = params[:cron] || "0 1 * * *"
49
61
  @cron = CronParser.new(cron_string)
50
62
  @next = Time.now - 1
51
-
63
+
52
64
  log "Loaded Monitor, #{@name}."
53
65
  end
54
66
 
55
67
  #Overload this method if any parameters should be checked in context
56
- def sanitise
68
+ def extractParams
69
+ end
70
+
71
+ #Overload this method if any parameters should be checked in context
72
+ def setup
73
+ end
74
+
75
+ #Overload this method if any parameters should be checked in context
76
+ def teardown
57
77
  end
58
78
 
59
79
  #Check if the monitor has tripped
60
80
  def process
61
81
  raise "Method needs to be overridden"
62
82
  end
63
-
83
+
64
84
  #An extention of the main run loop.
65
85
  #Each monitor is responsible for knowing when it should run, so this function
66
86
  #is called pretty much continuosuly.
@@ -70,8 +90,10 @@ class MonitorType
70
90
  begin
71
91
  @next = @cron.next( Time.now )
72
92
  log "Monitor, #{@name}, next run time, #{@next}"
73
- self.sanitise
93
+ self.extractParams
94
+ self.setup
74
95
  self.process
96
+ self.teardown
75
97
  rescue MonitorTypeExceptionHandled => e
76
98
  self.alert( e.message )
77
99
  end
@@ -3,42 +3,38 @@ require "MonitorType/Threshold"
3
3
 
4
4
  #A Beanstalk class for checking how many msgs are in a Queue
5
5
  class MonitorType_Beanstalk<MonitorType_Threshold
6
-
7
- def sanitise
8
- @beanstalk = Beanstalk::Pool.new([@connection_string])
9
- end
10
6
 
11
- #Constructor: Extract parameters
7
+ #Extract parameters
12
8
  #
13
9
  # @param [String] beanstalk Optional connection string. Default to local
14
10
  # @param [String] queue Name of queue to monitor
15
- def initialize( params )
16
- super( params )
17
- @connection_string = params[:beanstalk] || "localhost:11300"
11
+ def extractParams()
12
+ @connection_string = @params[:beanstalk] || "localhost:11300"
18
13
 
19
- if params[:queue].nil? then
20
- puts "*** Beanstalk parameter missing, queue"
21
- puts "*** :queue => <queue name>"
22
- abort
14
+ if @params[:queue].nil? then
15
+ string = "*** Beanstalk parameter missing, queue\n"
16
+ string = "#{string}*** :queue => <queue name>"
17
+ raise MonitorTypeParameterMissingError.new(string)
23
18
  end
24
- @queue = params[:queue]
19
+ @queue = @params[:queue]
25
20
 
26
21
  @context_sentence = "Checking number of jobs in queue, #{@queue}"
27
-
28
- self.sanitise
29
- rescue MonitorTypeExceptionHandled => e
30
- puts e.message
31
- abort()
22
+
32
23
  end
33
24
 
25
+ def setup
26
+ @beanstalk = Beanstalk::Pool.new([@connection_string])
27
+ end
28
+
29
+
34
30
  def getValue
35
31
  count = 0
36
32
  begin
37
- tubeStats = @beanstalk.stats_tube(@queue)
38
- count = tubeStats["current-jobs-ready"]
39
- rescue Beanstalk::NotFoundError=>e
33
+ tubeStats = @beanstalk.stats_tube(@queue)
34
+ count = tubeStats["current-jobs-ready"]
35
+ rescue Beanstalk::NotFoundError=>e
40
36
  end
41
-
37
+
42
38
  return count
43
39
  end
44
40
  end
@@ -3,14 +3,26 @@ require "MonitorType/Threshold"
3
3
  #A directory class for checking how many files are in a directory
4
4
  class MonitorType_Dir<MonitorType_Threshold
5
5
 
6
- def sanitise
7
- inputDir = Dir.new( @path )
8
- @path = inputDir.path
9
- if !File.writable?( @path ) then
10
- puts "*** Warning. Directory is not writable, #{@path}."
11
- puts "*** Warning. Make the directory, #{@path}, writable and try again."
6
+ #Extract parameters
7
+ #
8
+ # @param [String] path Path to directory to check
9
+ def extractParams()
10
+ if @params[:path].nil? then
11
+ string = "*** Dir parameter missing, path\n"
12
+ string = "#{string}*** :path => <path to directory to be monitored>"
13
+ raise MonitorTypeParameterMissingError.new(string)
12
14
  end
15
+ @path = @params[:path]
16
+
17
+ @context_sentence = "Checking number of files in, #{@path}"
18
+ end
13
19
 
20
+
21
+ def setup
22
+ inputDir = Dir.new( @path )
23
+ @path = inputDir.path
24
+ @params[:dir] = inputDir
25
+
14
26
  rescue Errno::ENOENT => e
15
27
  string = "***** Directory does not exist, #{@path}.\n"
16
28
  string = "#{string}***** Create the directory, #{@path}, and try again.\n"
@@ -22,27 +34,7 @@ class MonitorType_Dir<MonitorType_Threshold
22
34
  string = "#{string}***** eg, rm #{@path} && mkdir #{@path}"
23
35
  raise MonitorTypeExceptionHandled.new(string)
24
36
  end
25
-
26
- #Constructor: Extract parameters
27
- #
28
- # @param [String] path Path to directory to check
29
- def initialize( params )
30
- super( params )
31
- if params[:path].nil? then
32
- puts "*** Dir parameter missing, path"
33
- puts "*** :path => <path to directory to be monitored>"
34
- abort
35
- end
36
- @path = params[:path]
37
-
38
- @context_sentence = "Checking number of files in, #{@path}"
39
-
40
- self.sanitise
41
- rescue MonitorTypeExceptionHandled => e
42
- puts e.message
43
- abort()
44
- end
45
-
37
+
46
38
  def getValue
47
39
  return Dir.glob( "#{@path}/*" ).length
48
40
  end
@@ -9,66 +9,62 @@ require "MonitorType/Threshold"
9
9
 
10
10
  class MonitorType_FluidDb<MonitorType_Threshold
11
11
 
12
- #Create the connection to the db, and get the value
13
- #This ensures that all params are correct.
14
- def sanitise
15
- begin
16
- @fluidDb = FluidDb.Db( @uri )
17
- rescue Exception=>e
18
- puts "*** FluidDb encountered an error while connecting to the db"
19
- puts "*** Error: #{e.message}"
20
- puts "*** uri: #{@uri}"
21
- puts "*** Please fix the error and run again"
22
- abort()
23
- end
24
-
25
- begin
26
- value = @fluidDb.queryForValue( @sql, [] )
27
- rescue Exception=>e
28
- puts "*** FluidDb encountered an error while running the sql"
29
- puts "*** sql: #{@sql}"
30
- puts "*** Please fix the query and run again"
31
- abort()
32
- end
33
- end
34
-
35
- #Constructor: Extract parameters
12
+ #Extract parameters
36
13
  #
37
14
  # @param [String] uri Connection string to db
38
15
  # @param [String] sql SQL statement to gather a single value
39
- def initialize( params )
40
- super( params )
41
- if params[:uri].nil? then
42
- puts "*** FluidDb parameter missing, uri"
43
- puts "*** :uri => <uri pointing to db to be monitored>"
44
- abort
16
+ def extractParams
17
+ if @params[:uri].nil? then
18
+ string = "*** FluidDb parameter missing, uri\n"
19
+ string = "#{string}*** :uri => <uri pointing to db to be monitored>"
20
+ raise MonitorTypeParameterMissingError.new(string)
45
21
  end
46
22
  begin
47
- @uri = URI.parse( params[:uri] )
48
- rescue URI::InvalidURIError=>e
49
- puts "*** FluidDb encountered an error while parsing the uri"
50
- puts "*** uri: #{params[:uri]}"
51
- puts "*** Please fix the uri and run again"
52
- abort()
23
+ @uri = URI.parse( @params[:uri] )
24
+ rescue URI::InvalidURIError=>e
25
+ string = "*** FluidDb encountered an error while parsing the uri"
26
+ string = "#{string}*** uri: #{@params[:uri]}"
27
+ string = "#{string}*** Please fix the uri and run again"
28
+ raise MonitorTypeParameterMissingError.new(string)
53
29
  end
54
30
 
55
- if params[:sql].nil? then
56
- puts "*** FluidDb parameter missing, sql"
57
- puts "*** :sql => <sql statement, producing a single column, single row which yeidls a number>"
58
- abort
31
+ if @params[:sql].nil? then
32
+ string = "*** FluidDb parameter missing, sql"
33
+ string = "#{string}*** :sql => <sql statement, producing a single column, single row which yeidls a number>"
34
+ raise MonitorTypeParameterMissingError.new(string)
59
35
  end
60
- @sql = params[:sql]
61
-
36
+ @sql = @params[:sql]
37
+
62
38
  @context_sentence = "Checking result of sql query, #{@sql}"
39
+
40
+ end
41
+
42
+ #Create the connection to the db, and get the value
43
+ #This ensures that all params are correct.
44
+ def setup
63
45
 
64
- self.sanitise
65
- rescue MonitorTypeExceptionHandled => e
66
- puts e.message
67
- abort()
46
+ begin
47
+ @fluidDb = FluidDb.Db( @uri )
48
+ rescue Exception=>e
49
+ string = "*** FluidDb encountered an error while connecting to the db\n"
50
+ string = "#{string}*** Error: #{e.message}\n"
51
+ string = "#{string}*** uri: #{@uri}\n"
52
+ string = "#{string}*** Please 3fix the error and run again\n"
53
+ raise MonitorTypeExceptionHandled.new(string)
54
+ end
55
+
56
+ @params[:fluidDb] = @fluidDb
68
57
  end
69
58
 
70
59
  def getValue
71
- return @fluidDb.queryForValue( @sql, [] )
60
+ begin
61
+ return @fluidDb.queryForValue( @sql, [] )
62
+ rescue Exception=>e
63
+ string = "*** FluidDb encountered an error while running the sql\n"
64
+ string = "#{string}*** sql: #{@sql}\n"
65
+ string = "#{string}*** Please fix the query and run again\n"
66
+ raise MonitorTypeExceptionHandled.new(string)
67
+ end
72
68
  end
73
69
  end
74
70
 
@@ -0,0 +1,51 @@
1
+ require "MonitorType/Threshold"
2
+
3
+ #A class for checking if a Process is running in Unix based systems
4
+ class MonitorType_Process<MonitorType_Threshold
5
+
6
+ def sanitise
7
+ #Ensure that the process name contains a single character surrounded by square brackets
8
+ @process_name = @process_name.insert(0,'[').insert(2,']') unless @process_name =~ /^.*\[.+\].*/
9
+ end
10
+
11
+ def initialize(params)
12
+ super(params)
13
+
14
+ if params[:process_name].nil? then
15
+ puts "*** Process Name parameter missing, process_name"
16
+ puts "*** :process_name => <name of the process to be monitored>"
17
+ abort
18
+ end
19
+ @process_name = params[:process_name]
20
+
21
+ puts "#{@process_name}", "result: #{(@process_name =~ /^(.*\[{1}.+\]{1}.*)$|^(\w+)$/) == 0}"
22
+
23
+ unless (@process_name =~ /^(.*\[{1}.+\]{1}.*)$|^(\w+)$/) == 0 then
24
+ puts "*** Process Name parameter doest not match the required pattern, #{@process_name}"
25
+ puts "*** :process_name => <plain string, or a string with one or more characters enclosed in square brackets, i.e. 'foo', '[f]oo' or '[foo]'>"
26
+ abort
27
+ end
28
+
29
+ puts "*** Min value will be ignored, setting to 1" unless (params[:min].nil? || params[:min] == 0)
30
+ @min = 1
31
+
32
+ puts "*** Max value will be ignored, setting to nil" unless params[:max].nil?
33
+ @max = nil
34
+
35
+ @context_sentence = "Checking that process is running, #{@process_name}"
36
+
37
+ self.sanitise
38
+ rescue MonitorTypeExceptionHandled => e
39
+ puts e.message
40
+ abort
41
+ end
42
+
43
+ def getValue
44
+ return `ps aux | grep #{@process_name}`.length
45
+ end
46
+
47
+ end
48
+
49
+ def process(params)
50
+ $a.add(MonitorType_Process.new(params))
51
+ end
@@ -19,9 +19,10 @@ class MonitorType_Threshold<MonitorType
19
19
  value = self.getValue
20
20
  else
21
21
  value = @block.call( @params )
22
- puts "value: #{value}"
22
+ string = "value: #{value}\n"
23
+ puts string
23
24
  end
24
-
25
+
25
26
  self.check( value )
26
27
  end
27
28
 
@@ -0,0 +1,11 @@
1
+ def log( string, verbose=false )
2
+ return if ENV["TESTING"]=="true"
3
+
4
+ type = verbose ? "VERB" : "INFO"
5
+ if !ENV["VERBOSE"].nil? || verbose==false then
6
+ timestamp = Time.new.strftime( "%Y-%m-%d %H:%M:%S" )
7
+ puts "[#{type}] #{timestamp} :: #{string}"
8
+ end
9
+ end
10
+
11
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servicemonitor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.16
4
+ version: 0.0.18
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,9 +9,9 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-02 00:00:00.000000000 Z
12
+ date: 2013-12-30 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: Monitor various parts of the system
14
+ description: The fastest way to reliably monitor your system.
15
15
  email: guy@guyirvine.com
16
16
  executables:
17
17
  - servicemonitor
@@ -20,10 +20,12 @@ extra_rdoc_files: []
20
20
  files:
21
21
  - lib/Alert/Email.rb
22
22
  - lib/Alert.rb
23
+ - lib/helper_functions.rb
23
24
  - lib/MonitorManager.rb
24
25
  - lib/MonitorType/Beanstalk.rb
25
26
  - lib/MonitorType/Dir.rb
26
27
  - lib/MonitorType/FluidDb.rb
28
+ - lib/MonitorType/Process.rb
27
29
  - lib/MonitorType/Threshold.rb
28
30
  - lib/MonitorType.rb
29
31
  - bin/servicemonitor