process_monitoring 1.0.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.
- 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
|