servicemonitor 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/servicemonitor +30 -31
- data/lib/alert/email.rb +41 -0
- data/lib/alert.rb +6 -0
- data/lib/helper_functions.rb +8 -10
- data/lib/monitor_manager.rb +35 -0
- data/lib/monitor_type/beanstalk.rb +35 -0
- data/lib/monitor_type/dir.rb +45 -0
- data/lib/monitor_type/drive.rb +49 -0
- data/lib/monitor_type/fluiddb.rb +71 -0
- data/lib/monitor_type/http_get_json_list.rb +53 -0
- data/lib/monitor_type/process.rb +60 -0
- data/lib/monitor_type/threshold.rb +44 -0
- data/lib/monitor_type.rb +114 -0
- metadata +48 -38
- data/lib/Alert/Email.rb +0 -43
- data/lib/Alert.rb +0 -7
- data/lib/MonitorManager.rb +0 -36
- data/lib/MonitorType/Beanstalk.rb +0 -45
- data/lib/MonitorType/Dir.rb +0 -45
- data/lib/MonitorType/Drive.rb +0 -50
- data/lib/MonitorType/FluidDb.rb +0 -77
- data/lib/MonitorType/HttpGetJsonList.rb +0 -58
- data/lib/MonitorType/Process.rb +0 -57
- data/lib/MonitorType/Threshold.rb +0 -50
- data/lib/MonitorType.rb +0 -119
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c21b93e6591e1fdb7d9ab33bfbb185c2fc1a770d
|
4
|
+
data.tar.gz: 70a604920114a521584fc6776aa495d0e1893aca
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 30e355380f2cad7c5f25592b3d5eb95c2bcf2efcf402001f42e496b6abbafdb27cda3af48faa548d1e40b6350cec7c97cea3aaf136539e8fa5f06f8a5f6e3a59
|
7
|
+
data.tar.gz: c177caef1a73ae735546cdef63113a7807710c9c287114395e331a21e227fcad977ee5c5f4907bef01aefc855667274b1e68ca709b7aea06e7d1b985d6d281a3
|
data/bin/servicemonitor
CHANGED
@@ -1,46 +1,45 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
#Add the currently running directory to the start of the load path
|
3
|
+
# Add the currently running directory to the start of the load path
|
4
4
|
$:.unshift './'
|
5
5
|
|
6
6
|
require 'net/smtp'
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
|
19
|
-
|
20
|
-
#Don't buffer stdout
|
7
|
+
require 'Alert'
|
8
|
+
require 'Alert/Email'
|
9
|
+
require 'MonitorType'
|
10
|
+
require 'MonitorType/Threshold'
|
11
|
+
require 'MonitorType/Beanstalk'
|
12
|
+
require 'MonitorType/Dir'
|
13
|
+
require 'MonitorType/FluidDb'
|
14
|
+
require 'MonitorType/Process'
|
15
|
+
require 'MonitorType/HttpGetJsonList'
|
16
|
+
require 'MonitorManager'
|
17
|
+
require 'helper_functions'
|
18
|
+
|
19
|
+
# Don't buffer stdout
|
21
20
|
$stdout.sync = true
|
22
21
|
|
23
|
-
abort(
|
22
|
+
abort('Usage: servicemonitor <path to dsl>') if ARGV.length != 1
|
24
23
|
|
25
|
-
|
24
|
+
dsl_name = ARGV[0]
|
26
25
|
|
27
|
-
#Need to remove file name extension
|
28
|
-
ENV[
|
26
|
+
# Need to remove file name extension
|
27
|
+
ENV['APP_NAME'] = File.basename(dsl_name) if ENV['APP_NAME'].nil?
|
29
28
|
|
30
29
|
$a = MonitorManager.new
|
31
30
|
|
32
|
-
log "Loading dsl, #{
|
31
|
+
log "Loading dsl, #{dsl_name}"
|
33
32
|
begin
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
load dsl_name
|
34
|
+
$a.run
|
35
|
+
rescue ArgumentError
|
36
|
+
puts "*** Your dsl is not formatted correctly\n" \
|
37
|
+
"*** Ensure each line has the format,\n" \
|
38
|
+
"*** <command>, [:arg=>value]\n"
|
39
|
+
rescue SystemExit
|
41
40
|
# rescue SIGTERM=>e
|
42
|
-
|
43
|
-
puts
|
44
|
-
|
45
|
-
|
41
|
+
rescue StandardError
|
42
|
+
puts 'What the ...'
|
43
|
+
puts e.class.name
|
44
|
+
puts e.message
|
46
45
|
end
|
data/lib/alert/email.rb
ADDED
@@ -0,0 +1,41 @@
|
|
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 AlertEmail
|
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
|
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, @destination
|
34
|
+
end
|
35
|
+
|
36
|
+
rescue Errno::ECONNREFUSED
|
37
|
+
puts "*** Conection refused while attempting to connect to SMTP server\n" \
|
38
|
+
"*** Recipient, #{@destination}. Body,\n" \
|
39
|
+
"*** #{@body}\n"
|
40
|
+
end
|
41
|
+
end
|
data/lib/alert.rb
ADDED
data/lib/helper_functions.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
def log(
|
2
|
-
|
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
|
-
|
1
|
+
def log(string, verbose = false)
|
2
|
+
return if ENV['TESTING'] == 'true'
|
11
3
|
|
4
|
+
if !ENV['VERBOSE'].nil? || verbose == false
|
5
|
+
type = verbose ? 'VERB' : 'INFO'
|
6
|
+
timestamp = Time.new.strftime('%Y-%m-%d %H:%M:%S')
|
7
|
+
puts "[#{type}] #{timestamp} :: #{string}"
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Monitor Manager
|
2
|
+
class MonitorManager
|
3
|
+
def initialize
|
4
|
+
@list = []
|
5
|
+
end
|
6
|
+
|
7
|
+
def add(monitor)
|
8
|
+
@list.push monitor
|
9
|
+
end
|
10
|
+
|
11
|
+
# The main run loop
|
12
|
+
def run
|
13
|
+
Kernel.loop 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
|
25
|
+
string = "Exiting on request ...\n"
|
26
|
+
puts string
|
27
|
+
|
28
|
+
rescue StandardError
|
29
|
+
string = "#{e.class.name}\n" \
|
30
|
+
"*** This is really unexpected.\n" \
|
31
|
+
"Message: #{e.message}\n" \
|
32
|
+
"#{e.backtrace}\n"
|
33
|
+
puts string
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'beanstalk-client'
|
2
|
+
require 'monitor_type/threshold'
|
3
|
+
|
4
|
+
# A Beanstalk class for checking how many msgs are in a Queue
|
5
|
+
class MonitorTypeBeanstalk < MonitorTypeThreshold
|
6
|
+
# Extract parameters
|
7
|
+
#
|
8
|
+
# @param [String] beanstalk Optional connection string. Default to local
|
9
|
+
# @param [String] queue Name of queue to monitor
|
10
|
+
def extract_params
|
11
|
+
@connection_string = @params[:beanstalk] || 'localhost:11300'
|
12
|
+
|
13
|
+
if @params[:queue].nil?
|
14
|
+
string = "*** Beanstalk parameter missing, queue\n" \
|
15
|
+
'*** :queue => <queue name>'
|
16
|
+
fail MonitorTypeParameterMissingError, string
|
17
|
+
end
|
18
|
+
@queue = @params[:queue]
|
19
|
+
|
20
|
+
@context_sentence = "Checking number of jobs in queue, #{@queue}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup
|
24
|
+
@beanstalk = Beanstalk::Pool.new([@connection_string])
|
25
|
+
end
|
26
|
+
|
27
|
+
def derived_value
|
28
|
+
tube_stats = @beanstalk.stats_tube(@queue)
|
29
|
+
tube_stats['current-jobs-ready']
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def beanstalk(params)
|
34
|
+
$a.add(MonitorTypeBeanstalk.new(params))
|
35
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'monitor_type/threshold'
|
2
|
+
|
3
|
+
# A directory class for checking how many files are in a directory
|
4
|
+
class MonitorTypeDir < MonitorTypeThreshold
|
5
|
+
# Extract parameters
|
6
|
+
#
|
7
|
+
# @param [String] path Path to directory to check
|
8
|
+
def extract_params
|
9
|
+
if @params[:path].nil?
|
10
|
+
string = "*** Dir parameter missing, path\n" \
|
11
|
+
'*** :path => <path to directory to be monitored>'
|
12
|
+
fail MonitorTypeParameterMissingError, string
|
13
|
+
end
|
14
|
+
@path = @params[:path]
|
15
|
+
|
16
|
+
@context_sentence = "Checking number of files in, #{@path}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup
|
20
|
+
input_dir = Dir.new(@path)
|
21
|
+
@path = input_dir.path
|
22
|
+
@params[:dir] = input_dir
|
23
|
+
|
24
|
+
rescue Errno::ENOENT
|
25
|
+
str = "***** Directory does not exist, #{@path}.\n" \
|
26
|
+
"***** Create the directory, #{@path}, and try again.\n" \
|
27
|
+
"***** eg, mkdir #{@path}"
|
28
|
+
raise MonitorTypeExceptionHandled, str
|
29
|
+
rescue Errno::ENOTDIR
|
30
|
+
str = '***** The specified path does not point to a ' \
|
31
|
+
"directory, #{@path}.\n" \
|
32
|
+
'***** Either repoint path to a directory, ' \
|
33
|
+
"or remove, #{@path}, and create it as a directory.\n" \
|
34
|
+
"***** eg, rm #{@path} && mkdir #{@path}"
|
35
|
+
raise MonitorTypeExceptionHandled, str
|
36
|
+
end
|
37
|
+
|
38
|
+
def derived_value
|
39
|
+
Dir.glob("#{@path}/*").length
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def dir(params)
|
44
|
+
$a.add(MonitorTypeDir.new(params))
|
45
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'monitor_type/threshold'
|
2
|
+
require 'sys/filesystem'
|
3
|
+
include Sys
|
4
|
+
|
5
|
+
# MonitorType Drive
|
6
|
+
class MonitorTypeDrive < MonitorTypeThreshold
|
7
|
+
def extract_params
|
8
|
+
if @params[:path].nil?
|
9
|
+
string = "*** Drive parameter missing, drive\n" \
|
10
|
+
'*** :drive => <name of the drive to be monitored>'
|
11
|
+
fail MonitorTypeParameterMissingError, string
|
12
|
+
end
|
13
|
+
@path = @params[:path]
|
14
|
+
|
15
|
+
log "#{@process_name}", "result: #{(@process_name =~ /^(.*\[{1}.+\]{1}.*)$|^(\w+)$/) == 0}"
|
16
|
+
|
17
|
+
if @params[:min].nil?
|
18
|
+
string = "*** Min parameter missing, min\n" \
|
19
|
+
'*** :min => <the minimum amount of free space on ' \
|
20
|
+
'the drive to be monitored>'
|
21
|
+
fail MonitorTypeParameterMissingError, string
|
22
|
+
end
|
23
|
+
|
24
|
+
log '*** Max value will be ignored, setting to nil' unless @params[:max].nil?
|
25
|
+
@max = nil
|
26
|
+
|
27
|
+
@context_sentence = 'Checking that available drive space is greater ' \
|
28
|
+
"than min, #{@process_name}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup
|
32
|
+
# Check that the path exists
|
33
|
+
Filesystem.stat(@path)
|
34
|
+
|
35
|
+
rescue
|
36
|
+
string = "*** Unable to mount the specifed path\n" \
|
37
|
+
"*** path: #{@path}\n" \
|
38
|
+
"*** Please fix the error and run again\n"
|
39
|
+
raise MonitorTypeExceptionHandled, string
|
40
|
+
end
|
41
|
+
|
42
|
+
def derived_value
|
43
|
+
((Filesystem.stat(@path).blocks_available.to_f / Filesystem.stat(@path).blocks.to_f) * 100).round(2)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def process(params)
|
48
|
+
$a.add(MonitorTypeDrive.new(params))
|
49
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'FluidDb'
|
2
|
+
require 'monitor_type/threshold'
|
3
|
+
|
4
|
+
# A database class for checking a single number against a threshold.
|
5
|
+
# For example,
|
6
|
+
# get the max timestamp from a table as a date.
|
7
|
+
# subtract this from now
|
8
|
+
# => check that the number is not greater than 2
|
9
|
+
class MonitorTypeFluidDb < MonitorTypeThreshold
|
10
|
+
# Extract parameters
|
11
|
+
#
|
12
|
+
# @param [String] uri Connection string to db
|
13
|
+
# @param [String] sql SQL statement to gather a single value
|
14
|
+
def extract_params
|
15
|
+
if @params[:uri].nil?
|
16
|
+
string = "*** FluidDb parameter missing, uri\n" \
|
17
|
+
"*** :uri => <uri pointing to db to be monitored>"
|
18
|
+
fail MonitorTypeParameterMissingError, string
|
19
|
+
end
|
20
|
+
begin
|
21
|
+
@uri = URI.parse(@params[:uri])
|
22
|
+
rescue URI::InvalidURIError
|
23
|
+
string = '*** FluidDb encountered an error while parsing the uri' \
|
24
|
+
"*** uri: #{@params[:uri]}" \
|
25
|
+
"*** Please fix the uri and run again"
|
26
|
+
raise MonitorTypeParameterMissingError, string
|
27
|
+
end
|
28
|
+
|
29
|
+
if @params[:sql].nil?
|
30
|
+
string = '*** FluidDb parameter missing, sql' \
|
31
|
+
"*** :sql => <sql statement, producing a single " \
|
32
|
+
'column, single row which yeidls a number>'
|
33
|
+
fail MonitorTypeParameterMissingError, string
|
34
|
+
end
|
35
|
+
@sql = @params[:sql]
|
36
|
+
@context_sentence = "Checking result of sql query, #{@sql}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Create the connection to the db, and get the value
|
40
|
+
# This ensures that all params are correct.
|
41
|
+
def setup
|
42
|
+
begin
|
43
|
+
@fluid_db = FluidDb.Db(@uri)
|
44
|
+
rescue StandardError => e
|
45
|
+
string = "*** FluidDb encountered an error while connecting to the db\n" \
|
46
|
+
"*** Error: #{e.message}\n" \
|
47
|
+
"*** uri: #{@uri}\n" \
|
48
|
+
"*** Please fix the error and run again\n"
|
49
|
+
raise MonitorTypeExceptionHandled, string
|
50
|
+
end
|
51
|
+
|
52
|
+
@params[:fluidDb] = @fluid_db
|
53
|
+
end
|
54
|
+
|
55
|
+
def derived_value
|
56
|
+
@fluid_db.queryForValue(@sql, [])
|
57
|
+
rescue StandardError
|
58
|
+
string = "*** FluidDb encountered an error while running the sql\n" \
|
59
|
+
"*** sql: #{@sql}\n" \
|
60
|
+
"*** Please fix the query and run again\n"
|
61
|
+
raise MonitorTypeExceptionHandled, string
|
62
|
+
end
|
63
|
+
|
64
|
+
def teardown
|
65
|
+
@fluid_db.close
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def fluiddb(params)
|
70
|
+
$a.add(MonitorTypeFluidDb.new(params))
|
71
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'restclient'
|
2
|
+
require 'monitor_type/threshold'
|
3
|
+
|
4
|
+
# An http class for checking the length of a json list.
|
5
|
+
# For example,
|
6
|
+
# Get the list of outstandinig errors
|
7
|
+
# => check that the number is not greater than 2
|
8
|
+
class MonitorTypeHttpGetJsonList < MonitorTypeThreshold
|
9
|
+
# Extract parameters
|
10
|
+
#
|
11
|
+
# @param [String] uri Connection string to db
|
12
|
+
# @param [String] sql SQL statement to gather a single value
|
13
|
+
def extract_params
|
14
|
+
if @params[:uri].nil?
|
15
|
+
string = "*** HttpGetJsonList parameter missing, uri\n" \
|
16
|
+
'*** :uri => <uri pointing to url to be monitored>'
|
17
|
+
fail MonitorTypeParameterMissingError, string
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
@uri = URI.parse(@params[:uri])
|
22
|
+
rescue URI::InvalidURIError
|
23
|
+
str = '*** HttpGetJsonList encountered an error while parsing the uri' \
|
24
|
+
"*** uri: #{@params[:uri]}" \
|
25
|
+
'*** Please fix the uri and run again'
|
26
|
+
raise MonitorTypeParameterMissingError, str
|
27
|
+
end
|
28
|
+
|
29
|
+
url = "#{@uri.scheme}://#{@uri.host}#{@uri.path}"
|
30
|
+
@context_sentence = "Checking size of json list returned from, #{url}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def derived_value
|
34
|
+
content = RestClient.get(@uri.to_s)
|
35
|
+
list = JSON.parse(content)
|
36
|
+
str = "Expected type, Array - Actual type, #{list.class.name}"
|
37
|
+
fail MonitorTypeExceptionHandled, str unless list.class.name == 'Array'
|
38
|
+
list.length
|
39
|
+
rescue MonitorTypeExceptionHandled
|
40
|
+
raise e
|
41
|
+
|
42
|
+
rescue StandardError
|
43
|
+
string = '*** HttpGetJsonList encountered an error while running the ' \
|
44
|
+
'HTTP Get\n' \
|
45
|
+
"*** uri: #{@uri}\n" \
|
46
|
+
"*** Please fix the query and run again\n"
|
47
|
+
raise MonitorTypeExceptionHandled, string
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def httpgetjsonlist(params)
|
52
|
+
$a.add(MonitorTypeHttpGetJsonList.new(params))
|
53
|
+
end
|