eye 0.1.11 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/Gemfile +2 -2
- data/README.md +41 -18
- data/bin/eye +4 -3
- data/examples/processes/em.rb +2 -1
- data/examples/processes/thin.ru +12 -0
- data/examples/sidekiq.eye +19 -0
- data/examples/test.eye +25 -16
- data/eye.gemspec +5 -3
- data/lib/eye.rb +2 -1
- data/lib/eye/checker/validation.rb +1 -1
- data/lib/eye/child_process.rb +27 -5
- data/lib/eye/controller/load.rb +13 -11
- data/lib/eye/controller/send_command.rb +32 -7
- data/lib/eye/controller/status.rb +4 -3
- data/lib/eye/dsl/config_opts.rb +38 -1
- data/lib/eye/dsl/opts.rb +12 -5
- data/lib/eye/dsl/pure_opts.rb +2 -2
- data/lib/eye/dsl/validate.rb +5 -0
- data/lib/eye/group.rb +1 -1
- data/lib/eye/group/chain.rb +2 -0
- data/lib/eye/notify.rb +86 -0
- data/lib/eye/notify/jabber.rb +30 -0
- data/lib/eye/notify/mail.rb +44 -0
- data/lib/eye/process.rb +5 -1
- data/lib/eye/process/child.rb +7 -8
- data/lib/eye/process/commands.rb +21 -18
- data/lib/eye/process/notify.rb +22 -7
- data/lib/eye/process/system.rb +18 -5
- data/lib/eye/process/validate.rb +23 -0
- data/lib/eye/system.rb +4 -1
- data/lib/eye/utils.rb +9 -0
- data/spec/checker_spec.rb +0 -1
- data/spec/client_server_spec.rb +0 -1
- data/spec/controller/controller_spec.rb +1 -1
- data/spec/controller/intergration_spec.rb +15 -0
- data/spec/controller/load_spec.rb +49 -4
- data/spec/dsl/chain_spec.rb +20 -14
- data/spec/dsl/checks_spec.rb +17 -0
- data/spec/dsl/notify_spec.rb +105 -0
- data/spec/dsl/process_spec.rb +50 -0
- data/spec/mock_spec.rb +0 -1
- data/spec/notify/jabber_spec.rb +25 -0
- data/spec/notify/mail_spec.rb +26 -0
- data/spec/notify_spec.rb +90 -0
- data/spec/process/config_spec.rb +0 -1
- data/spec/process/notify_spec.rb +27 -0
- data/spec/process/states_history_spec.rb +0 -1
- data/spec/process/stop_spec.rb +6 -0
- data/spec/process/system_spec.rb +34 -21
- data/spec/process/update_config_spec.rb +0 -1
- data/spec/spec_helper.rb +9 -2
- data/spec/support/spec_support.rb +0 -1
- data/spec/system_resources_spec.rb +0 -1
- data/spec/system_spec.rb +3 -6
- data/spec/utils/alive_array_spec.rb +0 -1
- data/spec/utils/celluloid_chain_spec.rb +0 -1
- data/spec/utils/tail_spec.rb +0 -1
- metadata +71 -7
data/.rspec
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Eye
|
2
2
|
===
|
3
3
|
|
4
|
-
Process monitoring tool. With Bluepill like config syntax. Requires MRI Ruby >= 1.9.2. Uses Celluloid and Celluloid::IO.
|
4
|
+
Process monitoring tool. Alternative for God and Bluepill. With Bluepill like config syntax. Requires MRI Ruby >= 1.9.2. Uses Celluloid and Celluloid::IO.
|
5
5
|
|
6
6
|
|
7
7
|
Recommended installation on the server (system wide):
|
@@ -10,27 +10,30 @@ Recommended installation on the server (system wide):
|
|
10
10
|
$ sudo ln -sf /usr/local/ruby/1.9.3/bin/eye /usr/local/bin/eye
|
11
11
|
|
12
12
|
|
13
|
-
Config example, shows most of the options (
|
13
|
+
Config example, shows some typical processes and most of the options (see in exampes/ folder):
|
14
14
|
|
15
|
+
examples/test.eye
|
15
16
|
```ruby
|
16
17
|
Eye.load("./eye/*.rb") # load submodules
|
18
|
+
|
17
19
|
Eye.config do
|
18
20
|
logger "/tmp/eye.log" # eye logger
|
21
|
+
logger_level Logger::DEBUG
|
19
22
|
end
|
20
23
|
|
21
|
-
Eye.
|
24
|
+
Eye.application "test" do
|
22
25
|
working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
|
23
|
-
stdall "trash.log" # stdout
|
24
|
-
env "APP_ENV" => "production"
|
26
|
+
stdall "trash.log" # stdout,err logs for processes by default
|
27
|
+
env "APP_ENV" => "production" # global env for each processes
|
25
28
|
triggers :flapping, :times => 10, :within => 1.minute
|
26
29
|
|
27
30
|
group "samples" do
|
28
|
-
env "A" => "1" # env
|
31
|
+
env "A" => "1" # merging to app env
|
29
32
|
chain :grace => 5.seconds, :action => :restart # restarting with 5s interval, one by one.
|
30
33
|
|
31
34
|
# eye daemonized process
|
32
35
|
process("sample1") do
|
33
|
-
pid_file "1.pid" # expanded with working_dir
|
36
|
+
pid_file "1.pid" # will be expanded with working_dir
|
34
37
|
start_command "ruby ./sample.rb"
|
35
38
|
daemonize true
|
36
39
|
stdall "sample1.log"
|
@@ -42,7 +45,7 @@ Eye.app "test" do
|
|
42
45
|
process("sample2") do
|
43
46
|
pid_file "2.pid"
|
44
47
|
start_command "ruby ./sample.rb -d --pid 2.pid --log sample2.log"
|
45
|
-
stop_command "kill -9 {
|
48
|
+
stop_command "kill -9 {PID}"
|
46
49
|
|
47
50
|
checks :memory, :below => 300.megabytes, :times => 3
|
48
51
|
end
|
@@ -59,12 +62,30 @@ Eye.app "test" do
|
|
59
62
|
stop_grace 5.seconds
|
60
63
|
|
61
64
|
monitor_children do
|
62
|
-
|
63
|
-
|
64
|
-
restart_command "kill -2 {{PID}}"
|
65
|
+
restart_command "kill -2 {PID}" # for this child process
|
65
66
|
checks :memory, :below => 300.megabytes, :times => 3
|
66
67
|
end
|
67
68
|
end
|
69
|
+
|
70
|
+
process :event_machine do |p|
|
71
|
+
p.pid_file = 'em.pid'
|
72
|
+
p.start_command = 'ruby em.rb'
|
73
|
+
p.stdout = 'em.log'
|
74
|
+
p.daemonize = true
|
75
|
+
p.stop_signals = [:QUIT, 2.seconds, :KILL]
|
76
|
+
|
77
|
+
p.checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
|
78
|
+
:timeout => 1.second, :send_data => "ping", :expect_data => /pong/
|
79
|
+
end
|
80
|
+
|
81
|
+
process :thin do
|
82
|
+
pid_file "thin.pid"
|
83
|
+
start_command "bundle exec thin start -R thin.ru -p 33233 -d -l thin.log -P thin.pid"
|
84
|
+
stop_signals [:QUIT, 2.seconds, :TERM, 1.seconds, :KILL]
|
85
|
+
|
86
|
+
checks :http, :url => "http://127.0.0.1:33233/hello", :pattern => /World/, :every => 5.seconds,
|
87
|
+
:times => [2, 3], :timeout => 1.second
|
88
|
+
end
|
68
89
|
|
69
90
|
end
|
70
91
|
```
|
@@ -87,14 +108,16 @@ Process statuses:
|
|
87
108
|
$ eye i(nfo)
|
88
109
|
|
89
110
|
```
|
90
|
-
test
|
111
|
+
test
|
91
112
|
samples
|
92
|
-
sample1 ....................... up (21:
|
93
|
-
sample2 ....................... up (21:
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
113
|
+
sample1 ....................... up (21:52, 0%, 13Mb, <4107>)
|
114
|
+
sample2 ....................... up (21:52, 0%, 12Mb, <4142>)
|
115
|
+
event_machine ................... up (21:52, 3%, 26Mb, <4112>)
|
116
|
+
forking ......................... up (21:52, 0%, 41Mb, <4203>)
|
117
|
+
child-4206 .................... up (21:52, 0%, 41Mb, <4206>)
|
118
|
+
child-4211 .................... up (21:52, 0%, 41Mb, <4211>)
|
119
|
+
child-4214 .................... up (21:52, 0%, 41Mb, <4214>)
|
120
|
+
thin ............................ up (21:53, 2%, 54Mb, <4228>)
|
98
121
|
```
|
99
122
|
|
100
123
|
### Commands:
|
data/bin/eye
CHANGED
@@ -23,8 +23,9 @@ class Cli < Thor
|
|
23
23
|
|
24
24
|
desc "xinfo", "extended eye info, debug data"
|
25
25
|
method_option :config, :type => :boolean, :aliases => "-c"
|
26
|
+
method_option :show_processes, :type => :boolean, :aliases => "-p"
|
26
27
|
def xinfo
|
27
|
-
res = cmd(:xinfo, options[:config])
|
28
|
+
res = cmd(:xinfo, options[:config], options[:show_processes])
|
28
29
|
puts res if res && !res.empty?
|
29
30
|
puts
|
30
31
|
end
|
@@ -167,8 +168,8 @@ private
|
|
167
168
|
end
|
168
169
|
|
169
170
|
if opts[:print_config]
|
170
|
-
require '
|
171
|
-
|
171
|
+
require 'pp'
|
172
|
+
PP.pp res[:config]
|
172
173
|
end
|
173
174
|
end
|
174
175
|
end
|
data/examples/processes/em.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
def sidekiq_process(proxy, name)
|
2
|
+
proxy.process(name) do
|
3
|
+
start_command "ruby ./bin/sidekiq -e #{proxy.env['RAILS_ENV']} -C ./config/sidekiq.#{proxy.env['RAILS_ENV']}.yml"
|
4
|
+
pid_file "tmp/pids/#{name}.pid"
|
5
|
+
stdall "log/#{name}.log"
|
6
|
+
daemonize true
|
7
|
+
stop_signals [:QUIT, 5.seconds, :TERM, 5.seconds, :KILL]
|
8
|
+
|
9
|
+
checks :cpu, :every => 30, :below => 100, :times => 5
|
10
|
+
checks :memory, :every => 30, :below => 300.megabytes, :times => 5
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Eye.application :sidekiq_test do
|
15
|
+
working_dir '/some_dir'
|
16
|
+
env "RAILS_ENV" => 'production'
|
17
|
+
|
18
|
+
sidekiq_process self, :sidekiq
|
19
|
+
end
|
data/examples/test.eye
CHANGED
@@ -1,22 +1,23 @@
|
|
1
1
|
Eye.load("./eye/*.rb") # load submodules
|
2
|
+
|
2
3
|
Eye.config do
|
3
4
|
logger "/tmp/eye.log" # eye logger
|
4
5
|
logger_level Logger::DEBUG
|
5
6
|
end
|
6
7
|
|
7
|
-
Eye.
|
8
|
+
Eye.application "test" do
|
8
9
|
working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
|
9
|
-
stdall "trash.log" # stdout
|
10
|
-
env "APP_ENV" => "production"
|
10
|
+
stdall "trash.log" # stdout,err logs for processes by default
|
11
|
+
env "APP_ENV" => "production" # global env for each processes
|
11
12
|
triggers :flapping, :times => 10, :within => 1.minute
|
12
13
|
|
13
14
|
group "samples" do
|
14
|
-
env "A" => "1" # env
|
15
|
+
env "A" => "1" # merging to app env
|
15
16
|
chain :grace => 5.seconds, :action => :restart # restarting with 5s interval, one by one.
|
16
17
|
|
17
18
|
# eye daemonized process
|
18
19
|
process("sample1") do
|
19
|
-
pid_file "1.pid" # expanded with working_dir
|
20
|
+
pid_file "1.pid" # will be expanded with working_dir
|
20
21
|
start_command "ruby ./sample.rb"
|
21
22
|
daemonize true
|
22
23
|
stdall "sample1.log"
|
@@ -28,7 +29,7 @@ Eye.app "test" do
|
|
28
29
|
process("sample2") do
|
29
30
|
pid_file "2.pid"
|
30
31
|
start_command "ruby ./sample.rb -d --pid 2.pid --log sample2.log"
|
31
|
-
stop_command "kill -9 {
|
32
|
+
stop_command "kill -9 {PID}"
|
32
33
|
|
33
34
|
checks :memory, :below => 300.megabytes, :times => 3
|
34
35
|
end
|
@@ -45,21 +46,29 @@ Eye.app "test" do
|
|
45
46
|
stop_grace 5.seconds
|
46
47
|
|
47
48
|
monitor_children do
|
48
|
-
|
49
|
-
|
50
|
-
restart_command "kill -2 {{PID}}"
|
49
|
+
restart_command "kill -2 {PID}" # for this child process
|
51
50
|
checks :memory, :below => 300.megabytes, :times => 3
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
55
|
-
process :event_machine do
|
56
|
-
pid_file 'em.pid'
|
57
|
-
start_command 'ruby em.rb'
|
58
|
-
|
59
|
-
daemonize true
|
54
|
+
process :event_machine do |p|
|
55
|
+
p.pid_file = 'em.pid'
|
56
|
+
p.start_command = 'ruby em.rb'
|
57
|
+
p.stdout = 'em.log'
|
58
|
+
p.daemonize = true
|
59
|
+
p.stop_signals = [:QUIT, 2.seconds, :KILL]
|
60
60
|
|
61
|
-
checks :socket, :addr => "tcp://127.0.0.1:33221", :
|
62
|
-
|
61
|
+
p.checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
|
62
|
+
:timeout => 1.second, :send_data => "ping", :expect_data => /pong/
|
63
|
+
end
|
64
|
+
|
65
|
+
process :thin do
|
66
|
+
pid_file "thin.pid"
|
67
|
+
start_command "bundle exec thin start -R thin.ru -p 33233 -d -l thin.log -P thin.pid"
|
68
|
+
stop_signals [:QUIT, 2.seconds, :TERM, 1.seconds, :KILL]
|
69
|
+
|
70
|
+
checks :http, :url => "http://127.0.0.1:33233/hello", :pattern => /World/, :every => 5.seconds,
|
71
|
+
:times => [2, 3], :timeout => 1.second
|
63
72
|
end
|
64
73
|
|
65
74
|
end
|
data/eye.gemspec
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
require File.expand_path('../lib/eye', __FILE__)
|
3
2
|
|
4
3
|
Gem::Specification.new do |gem|
|
5
4
|
gem.authors = "Konstantin Makarchev"
|
6
5
|
gem.email = "kostya27@gmail.com"
|
7
6
|
|
8
|
-
gem.description =
|
9
|
-
|
7
|
+
gem.description = gem.summary = \
|
8
|
+
%q{Process monitoring tool. Alternative for God and Bluepill. With Bluepill like config syntax. Requires MRI Ruby >= 1.9.2. Uses Celluloid and Celluloid::IO.}
|
10
9
|
gem.homepage = "http://github.com/kostya/eye"
|
11
10
|
|
12
11
|
gem.files = `git ls-files`.split($\)
|
@@ -34,4 +33,7 @@ Gem::Specification.new do |gem|
|
|
34
33
|
gem.add_development_dependency 'forking'
|
35
34
|
gem.add_development_dependency 'fakeweb'
|
36
35
|
gem.add_development_dependency 'eventmachine'
|
36
|
+
gem.add_development_dependency 'sinatra'
|
37
|
+
gem.add_development_dependency 'thin'
|
38
|
+
gem.add_development_dependency 'xmpp4r'
|
37
39
|
end
|
data/lib/eye.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Eye
|
2
|
-
VERSION = "0.
|
2
|
+
VERSION = "0.2"
|
3
3
|
ABOUT = "Eye v#{VERSION} (c) 2012-2013 @kostya"
|
4
4
|
|
5
5
|
autoload :Process, 'eye/process'
|
@@ -16,6 +16,7 @@ module Eye
|
|
16
16
|
autoload :Settings, 'eye/settings'
|
17
17
|
autoload :Client, 'eye/client'
|
18
18
|
autoload :Utils, 'eye/utils'
|
19
|
+
autoload :Notify, 'eye/notify'
|
19
20
|
|
20
21
|
autoload :Controller, 'eye/controller'
|
21
22
|
autoload :Control, 'eye/control'
|
@@ -42,7 +42,7 @@ module Eye::Checker::Validation
|
|
42
42
|
end
|
43
43
|
|
44
44
|
should_bes.each do |param|
|
45
|
-
raise Error, "#{self.name}
|
45
|
+
raise Error, "#{self.name} for param :#{param} value should be" unless options[param.to_sym] || defaults[param.to_sym]
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
data/lib/eye/child_process.rb
CHANGED
@@ -27,16 +27,17 @@ class Eye::ChildProcess
|
|
27
27
|
# scheduler
|
28
28
|
include Eye::Process::Scheduler
|
29
29
|
|
30
|
-
attr_reader :pid, :name, :config, :watchers
|
30
|
+
attr_reader :pid, :name, :full_name, :config, :watchers
|
31
31
|
|
32
32
|
def initialize(pid, config = {}, logger_prefix = nil)
|
33
33
|
raise 'Empty pid' unless pid
|
34
34
|
|
35
35
|
@pid = pid
|
36
36
|
@config = prepare_config(config)
|
37
|
-
@name =
|
37
|
+
@name = "child-#{pid}"
|
38
|
+
@full_name = [logger_prefix, @name] * ':'
|
38
39
|
|
39
|
-
@logger = Eye::Logger.new(
|
40
|
+
@logger = Eye::Logger.new(@full_name)
|
40
41
|
|
41
42
|
@watchers = {}
|
42
43
|
|
@@ -49,12 +50,23 @@ class Eye::ChildProcess
|
|
49
50
|
:up
|
50
51
|
end
|
51
52
|
|
53
|
+
def send_command(command, *args)
|
54
|
+
schedule command, *args, "#{command} by user"
|
55
|
+
end
|
56
|
+
|
57
|
+
def start
|
58
|
+
end
|
59
|
+
|
52
60
|
def stop
|
53
61
|
kill_process
|
54
62
|
end
|
55
63
|
|
56
64
|
def restart
|
57
|
-
|
65
|
+
if self[:restart_command]
|
66
|
+
execute_restart_command
|
67
|
+
else
|
68
|
+
stop
|
69
|
+
end
|
58
70
|
end
|
59
71
|
|
60
72
|
def monitor
|
@@ -63,11 +75,21 @@ class Eye::ChildProcess
|
|
63
75
|
def unmonitor
|
64
76
|
end
|
65
77
|
|
66
|
-
def delete
|
78
|
+
def delete
|
79
|
+
end
|
80
|
+
|
81
|
+
def destroy
|
67
82
|
remove_watchers
|
68
83
|
terminate
|
69
84
|
end
|
70
85
|
|
86
|
+
def signal(sig)
|
87
|
+
if self.pid
|
88
|
+
res = send_signal(sig)
|
89
|
+
info "send signal #{sig} to #{self.pid} = #{res}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
71
93
|
def status_data(debug = false)
|
72
94
|
self_status_data(debug)
|
73
95
|
end
|
data/lib/eye/controller/load.rb
CHANGED
@@ -24,7 +24,7 @@ module Eye::Controller::Load
|
|
24
24
|
private
|
25
25
|
|
26
26
|
# regexp for clean backtrace to show for user
|
27
|
-
BT_REGX = %r[/lib/eye/|lib/celluloid|internal:prelude|logger.rb
|
27
|
+
BT_REGX = %r[/lib/eye/|lib/celluloid|internal:prelude|logger.rb:|active_support/core_ext|shellwords.rb].freeze
|
28
28
|
|
29
29
|
def catch_load_error(filename, &block)
|
30
30
|
res = block.call
|
@@ -34,7 +34,8 @@ private
|
|
34
34
|
error "load: config error <#{filename}>: #{ex.message}"
|
35
35
|
|
36
36
|
# filter backtrace for user output
|
37
|
-
bt = (ex.backtrace || [])
|
37
|
+
bt = (ex.backtrace || [])
|
38
|
+
bt = bt.reject{|line| line.to_s =~ BT_REGX }
|
38
39
|
error bt.join("\n")
|
39
40
|
|
40
41
|
res = {:error => true, :message => ex.message}
|
@@ -69,27 +70,28 @@ private
|
|
69
70
|
|
70
71
|
raise Eye::Dsl::Error, "config file '#{mask}' not found!" if configs.blank?
|
71
72
|
|
72
|
-
|
73
|
+
@loaded_config = Eye::Dsl.initial_config
|
73
74
|
configs.each do |cfg|
|
74
|
-
|
75
|
+
@loaded_config = merge_configs(@loaded_config, cfg)
|
75
76
|
end
|
76
77
|
|
78
|
+
new_cfg = merge_configs(@current_config, @loaded_config)
|
77
79
|
validate(new_cfg)
|
78
|
-
|
79
80
|
new_cfg
|
80
81
|
end
|
81
82
|
|
82
83
|
def _load(filename)
|
83
84
|
new_cfg = parse_set_of_configs(filename)
|
84
|
-
|
85
|
-
load_config(new_cfg)
|
85
|
+
|
86
|
+
load_config(new_cfg, @loaded_config[:applications].keys)
|
87
|
+
@loaded_config = nil
|
86
88
|
|
87
89
|
GC.start
|
88
90
|
end
|
89
91
|
|
90
|
-
def load_config(new_config)
|
92
|
+
def load_config(new_config, changed_apps = [])
|
91
93
|
load_options(new_config[:config])
|
92
|
-
create_objects(new_config[:applications])
|
94
|
+
create_objects(new_config[:applications], changed_apps)
|
93
95
|
@current_config = new_config
|
94
96
|
end
|
95
97
|
|
@@ -117,10 +119,10 @@ private
|
|
117
119
|
end
|
118
120
|
|
119
121
|
# create objects as diff, from configs
|
120
|
-
def create_objects(apps_config)
|
122
|
+
def create_objects(apps_config, changed_apps = [])
|
121
123
|
debug 'create objects'
|
122
124
|
apps_config.each do |app_name, app_cfg|
|
123
|
-
update_or_create_application(app_name, app_cfg.clone)
|
125
|
+
update_or_create_application(app_name, app_cfg.clone) if changed_apps.include?(app_name)
|
124
126
|
end
|
125
127
|
|
126
128
|
# sorting applications
|