process_monitoring 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,6 @@
1
+ require 'process_monitoring/monitoring'
2
+ require 'process_monitoring/monitoring_info'
3
+ require 'process_monitoring/thread_safe_hash'
4
+
5
+ module ProcessMonitoring
6
+ 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
+
@@ -0,0 +1,3 @@
1
+ module ProcessMonitoring
2
+ VERSION = "1.0.0"
3
+ end
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