process_monitoring 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/process_monitoring.rb +47 -0
- data/lib/process_monitoring.rb +6 -0
- data/lib/process_monitoring/monitoring.rb +85 -0
- data/lib/process_monitoring/monitoring_info.rb +79 -0
- data/lib/process_monitoring/send_email.rb +40 -0
- data/lib/process_monitoring/thread_safe_hash.rb +39 -0
- data/lib/process_monitoring/version.rb +3 -0
- metadata +148 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
# Author: Kolman Vornovitsky (kolmanv@gmail.com)
|
2
|
+
# This files gives example of how to use process monitoring module.
|
3
|
+
|
4
|
+
require 'process_monitoring'
|
5
|
+
|
6
|
+
# What are we monitoring?
|
7
|
+
# 1) Logs
|
8
|
+
require 'log'
|
9
|
+
|
10
|
+
# 2) Parameters
|
11
|
+
require 'params'
|
12
|
+
|
13
|
+
Params.init ARGV
|
14
|
+
Params['log_write_to_console'] = true
|
15
|
+
|
16
|
+
Log.init
|
17
|
+
|
18
|
+
# 3) Custom hash of variables
|
19
|
+
variables = ThreadSafeHash::ThreadSafeHash.new
|
20
|
+
variables.set('some_variable', 'this is an example :)')
|
21
|
+
|
22
|
+
# If you want this example to send emails, set Params['enable_monitoring_emails']=true
|
23
|
+
# Before you do that, check the emails parameters at 'monitoring.rb'
|
24
|
+
|
25
|
+
# Lets initialize the monitoring task.
|
26
|
+
# The command below generates new thread which can be retrieved by 'mon.thread'.
|
27
|
+
# The command below starts checking periodically for errors in logs and/or send status update emails
|
28
|
+
# to Params['monitoring_email']
|
29
|
+
mon = Monitoring::Monitoring.new(variables)
|
30
|
+
|
31
|
+
# Lets initialize the monitoring variables HTTP interface (look at localhost:5555).
|
32
|
+
# The command below generates new thread which can be retrieved by 'mon_http.thread'.
|
33
|
+
mon_http = MonitoringInfo::MonitoringInfo.new(variables)
|
34
|
+
|
35
|
+
# Lets connect the monitoring to the log.
|
36
|
+
Log.add_consumer(mon)
|
37
|
+
|
38
|
+
# Let there is a running process
|
39
|
+
number = 1
|
40
|
+
loop do
|
41
|
+
number += 1
|
42
|
+
variables.set('number', number)
|
43
|
+
Log.info "number: #{number}"
|
44
|
+
remote_mon_info = MonitoringInfo::MonitoringInfo.get_remote_monitoring_info('localhost', 5555)
|
45
|
+
Log.info "Remote monitoring info (localhost:5555): #{remote_mon_info}" if remote_mon_info
|
46
|
+
sleep(3)
|
47
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
require 'log'
|
4
|
+
require 'params'
|
5
|
+
|
6
|
+
require 'process_monitoring/send_email'
|
7
|
+
|
8
|
+
# This module purpose it to alert the user on different behaviour such as no space left
|
9
|
+
# or other error cases. The module will send email to the user to notify him on those cases.
|
10
|
+
module Monitoring
|
11
|
+
Params.float('monitoring_sleep_time_in_seconds', 10,
|
12
|
+
'Represents the monitoring sleeping time in seconds to check data')
|
13
|
+
Params.float('send_email_duration_4_monitoring_state', 60*60, # Once per hour.
|
14
|
+
'Represents the duration in seconds to send email monitoring state')
|
15
|
+
|
16
|
+
# Username and Password for gmail account to send monitoting emails.
|
17
|
+
Params.string('gmail_username', nil, 'Backup server gmail username.')
|
18
|
+
Params.string('gmail_password', nil, 'Backup server gmail password.')
|
19
|
+
|
20
|
+
class Monitoring
|
21
|
+
attr_reader :thread
|
22
|
+
def initialize(process_variables)
|
23
|
+
@thread = 'dummy'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
=begin
|
27
|
+
class Monitoring < Log::Consumer
|
28
|
+
attr_reader :thread
|
29
|
+
def initialize(process_variables)
|
30
|
+
super(false)
|
31
|
+
@passed_time_dur = 0
|
32
|
+
@process_variables = process_variables
|
33
|
+
@thread = Thread.new do
|
34
|
+
loop do
|
35
|
+
Log.debug3 'Sleeping in process monitoring.'
|
36
|
+
sleep(Params['monitoring_sleep_time_in_seconds'])
|
37
|
+
Log.debug3 'Awake in process monitoring.'
|
38
|
+
@passed_time_dur += Params['monitoring_sleep_time_in_seconds']
|
39
|
+
Log.debug3 'handle_logs in process monitoring.'
|
40
|
+
handle_logs()
|
41
|
+
Log.debug3 'handle_monitoring_state in process monitoring.'
|
42
|
+
handle_monitoring_state()
|
43
|
+
@process_variables.inc('monitoring_loop_count')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
# For debug purposes.
|
47
|
+
@thread.abort_on_exception = true
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
# To keep thread safe state all methods should be private and executed only from @thread
|
52
|
+
def send_email(subject, body)
|
53
|
+
SendEmail.send_email({
|
54
|
+
:to => Params['gmail_username'],
|
55
|
+
:from => Params['gmail_username'],
|
56
|
+
:password => Params['gmail_password'],
|
57
|
+
:body => body,
|
58
|
+
:subject => subject,
|
59
|
+
})
|
60
|
+
end
|
61
|
+
|
62
|
+
# Override logs consumer handler.
|
63
|
+
def handle_logs
|
64
|
+
while log_msg = @consumer_queue.pop(non_block=true) do
|
65
|
+
send_log_email(log_msg) if Log.is_error(log_msg)
|
66
|
+
end rescue ThreadError # Rescue when queue is empty.
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_monitoring_state
|
70
|
+
if @passed_time_dur > Params['send_email_duration_4_monitoring_state']
|
71
|
+
send_email('BBFS Current Monitoring State notification', get_monitoring_state_body())
|
72
|
+
@passed_time_dur = 0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_monitoring_state_body
|
77
|
+
# TODO(slava): Implement the following function.
|
78
|
+
# MonitoringInfo::MonitoringInfo.get_html(@process_variables)
|
79
|
+
"server_name: #{@process_variables.get('server_name')}\n" +
|
80
|
+
"num_files_received: #{@process_variables.get('num_files_received')}\n" +
|
81
|
+
"monitoring_loop_count: #{@process_variables.get('monitoring_loop_count')}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
=end
|
85
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'json'
|
3
|
+
require 'net/http'
|
4
|
+
require 'thin'
|
5
|
+
require 'sinatra'
|
6
|
+
|
7
|
+
require 'params'
|
8
|
+
|
9
|
+
# Set up event machine to exit on ctrl+c.
|
10
|
+
EventMachine.schedule do
|
11
|
+
trap("INT") do
|
12
|
+
puts "Caught SIGINT"
|
13
|
+
EventMachine.exit # this is useless
|
14
|
+
# exit # this stops the EventMachine
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# This module export process info to http port, that way the user may access with the
|
19
|
+
# browser to the process to see what is happening inside, what is it's state and parameters.
|
20
|
+
module MonitoringInfo
|
21
|
+
Params.integer('process_monitoring_web_port', 5555,
|
22
|
+
'The port from which monitoring data will be served as http.')
|
23
|
+
|
24
|
+
class MonitoringInfo
|
25
|
+
attr_reader :thread
|
26
|
+
|
27
|
+
def initialize(process_variables)
|
28
|
+
@process_variables = process_variables
|
29
|
+
@web_interface = Sinatra.new { get('/') { MonitoringInfo.get_json(process_variables.clone) } }
|
30
|
+
@web_interface.set(:port, Params['process_monitoring_web_port'])
|
31
|
+
@thread = Thread.new do
|
32
|
+
@web_interface.run!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.get_json(hash)
|
37
|
+
return '' if !hash.is_a?(Hash)
|
38
|
+
|
39
|
+
entries = []
|
40
|
+
hash.each do |key, value|
|
41
|
+
if value.is_a? String
|
42
|
+
entries << "\"#{key}\": \"#{value}\""
|
43
|
+
else
|
44
|
+
entries << "\"#{key}\": #{value}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
return '{' + entries.join(',') + '}'
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.get_html (hash, opts = {})
|
52
|
+
return if !hash.is_a?(Hash)
|
53
|
+
|
54
|
+
indent_level = opts.fetch(:indent_level) { 0 }
|
55
|
+
|
56
|
+
out = " " * indent_level + "<ul>\n"
|
57
|
+
|
58
|
+
hash.each do |key, value|
|
59
|
+
out += " " * (indent_level + 2) + "<li><strong>#{key}:</strong>"
|
60
|
+
|
61
|
+
if value.is_a?(Hash)
|
62
|
+
out += "\n" + get_html(value, :indent_level => indent_level + 2) + " " * (indent_level + 2) + "</li>\n"
|
63
|
+
else
|
64
|
+
out += " <span>#{value}</span></li>\n"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
out += " " * indent_level + "</ul>\n"
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.get_remote_monitoring_info(host, port)
|
72
|
+
begin
|
73
|
+
JSON.parse(Net::HTTP.get(URI("http://#{host}:#{port}/")))
|
74
|
+
rescue Errno::ECONNREFUSED => e
|
75
|
+
''
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
|
3
|
+
require 'log'
|
4
|
+
require 'params'
|
5
|
+
|
6
|
+
module SendEmail
|
7
|
+
Params.boolean('enable_monitoring_emails', false, 'Whether to send emails for process monitoring events.')
|
8
|
+
|
9
|
+
#class SendEmail
|
10
|
+
def SendEmail.send_email(opts={})
|
11
|
+
opts[:to] ||= '' # Required.
|
12
|
+
opts[:from] ||= '' # Required.
|
13
|
+
opts[:from_alias] ||= 'BBFS Monitoring'
|
14
|
+
opts[:subject] ||= 'BBFS Notification subject'
|
15
|
+
opts[:body] ||= 'BBFS Body'
|
16
|
+
opts[:password] ||= '' # Required.
|
17
|
+
|
18
|
+
msg = "From: #{opts[:from_alias]} <#{opts[:from]}>\n" \
|
19
|
+
"To: <#{opts[:to]}>\n" \
|
20
|
+
"Subject: #{opts[:subject]}\n" \
|
21
|
+
"#{opts[:body]}"
|
22
|
+
|
23
|
+
email_log_message = "Send actual email: #{Params['enable_monitoring_emails']}.\n" \
|
24
|
+
"to: #{opts[:to]}\n" \
|
25
|
+
"msg:#{msg}"
|
26
|
+
if Params['enable_monitoring_emails']
|
27
|
+
Log.debug1(email_log_message)
|
28
|
+
smtp = Net::SMTP.new('smtp.gmail.com', 587)
|
29
|
+
smtp.enable_starttls
|
30
|
+
smtp.start('bbfs.com', opts[:from], opts[:password], :login) do
|
31
|
+
smtp.send_message(msg, opts[:from], opts[:to])
|
32
|
+
end
|
33
|
+
else
|
34
|
+
Log.info(email_log_message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
#end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Simple thread safe hash.
|
2
|
+
module ThreadSafeHash
|
3
|
+
class ThreadSafeHash
|
4
|
+
def initialize()
|
5
|
+
@hash_data = Hash.new()
|
6
|
+
@mutex = Mutex.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def inc(key)
|
10
|
+
@mutex.synchronize do
|
11
|
+
value = @hash_data[key]
|
12
|
+
if value.nil?
|
13
|
+
@hash_data[key] = 1
|
14
|
+
else
|
15
|
+
@hash_data[key] = value + 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(key)
|
21
|
+
@mutex.synchronize do
|
22
|
+
@hash_data[key]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def set(key, value)
|
27
|
+
@mutex.synchronize do
|
28
|
+
@hash_data[key] = value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def clone
|
33
|
+
@mutex.synchronize do
|
34
|
+
@hash_data.clone
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: process_monitoring
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gena Petelko, Kolman Vornovitsky
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: eventmachine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: json
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: log
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: params
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: sinatra
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: thin
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: Holds variable set which is regularly updated and export it to http protocol
|
111
|
+
email: bbfsdev@gmail.com
|
112
|
+
executables: []
|
113
|
+
extensions: []
|
114
|
+
extra_rdoc_files: []
|
115
|
+
files:
|
116
|
+
- lib/process_monitoring.rb
|
117
|
+
- lib/process_monitoring/thread_safe_hash.rb
|
118
|
+
- lib/process_monitoring/monitoring_info.rb
|
119
|
+
- lib/process_monitoring/send_email.rb
|
120
|
+
- lib/process_monitoring/monitoring.rb
|
121
|
+
- lib/process_monitoring/version.rb
|
122
|
+
- examples/process_monitoring.rb
|
123
|
+
homepage: http://github.com/bbfsdev/bbfs
|
124
|
+
licenses: []
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
|
+
none: false
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 1.8.24
|
144
|
+
signing_key:
|
145
|
+
specification_version: 3
|
146
|
+
summary: Library to add monitoring for processes.
|
147
|
+
test_files:
|
148
|
+
- examples/process_monitoring.rb
|