reel-eye 0.4.1 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +4 -0
- data/CHANGES.md +17 -1
- data/README.md +3 -3
- data/Rakefile +8 -0
- data/bin/eye +0 -316
- data/bin/loader_eye +3 -3
- data/examples/test.eye +2 -2
- data/eye.gemspec +6 -10
- data/lib/eye.rb +4 -2
- data/lib/eye/application.rb +3 -3
- data/lib/eye/checker.rb +35 -7
- data/lib/eye/checker/cputime.rb +23 -0
- data/lib/eye/checker/file_touched.rb +15 -0
- data/lib/eye/checker/http.rb +7 -9
- data/lib/eye/checker/memory.rb +1 -1
- data/lib/eye/checker/runtime.rb +28 -0
- data/lib/eye/checker/socket.rb +4 -4
- data/lib/eye/cli.rb +166 -0
- data/lib/eye/cli/commands.rb +79 -0
- data/lib/eye/cli/render.rb +137 -0
- data/lib/eye/cli/server.rb +85 -0
- data/lib/eye/client.rb +3 -3
- data/lib/eye/config.rb +17 -14
- data/lib/eye/controller.rb +6 -10
- data/lib/eye/controller/commands.rb +6 -10
- data/lib/eye/controller/helpers.rb +1 -1
- data/lib/eye/controller/send_command.rb +5 -2
- data/lib/eye/controller/status.rb +38 -106
- data/lib/eye/dsl.rb +1 -1
- data/lib/eye/dsl/application_opts.rb +6 -2
- data/lib/eye/dsl/child_process_opts.rb +3 -2
- data/lib/eye/dsl/config_opts.rb +2 -2
- data/lib/eye/dsl/group_opts.rb +2 -1
- data/lib/eye/dsl/main.rb +4 -2
- data/lib/eye/dsl/opts.rb +11 -4
- data/lib/eye/dsl/validation.rb +49 -43
- data/lib/eye/group.rb +1 -1
- data/lib/eye/http.rb +4 -9
- data/lib/eye/http/router.rb +1 -1
- data/lib/eye/loader.rb +5 -9
- data/lib/eye/{settings.rb → local.rb} +1 -1
- data/lib/eye/logger.rb +5 -0
- data/lib/eye/notify.rb +12 -6
- data/lib/eye/notify/jabber.rb +2 -2
- data/lib/eye/process/child.rb +3 -1
- data/lib/eye/process/commands.rb +2 -2
- data/lib/eye/process/controller.rb +1 -1
- data/lib/eye/process/trigger.rb +1 -1
- data/lib/eye/sigar.rb +5 -0
- data/lib/eye/system.rb +8 -7
- data/lib/eye/system_resources.rb +46 -41
- data/lib/eye/trigger.rb +15 -8
- data/lib/eye/trigger/flapping.rb +1 -1
- data/lib/eye/trigger/stop_childs.rb +1 -1
- data/lib/eye/trigger/transition.rb +15 -0
- data/lib/eye/utils.rb +12 -0
- data/lib/eye/utils/leak_19.rb +7 -0
- data/lib/eye/utils/mini_active_support.rb +106 -0
- metadata +40 -17
- data/lib/eye/controller/show_history.rb +0 -63
- data/lib/eye/trigger/state.rb +0 -11
@@ -0,0 +1,79 @@
|
|
1
|
+
module Eye::Cli::Commands
|
2
|
+
private
|
3
|
+
|
4
|
+
def client
|
5
|
+
@client ||= Eye::Client.new(Eye::Local.socket_path)
|
6
|
+
end
|
7
|
+
|
8
|
+
def _cmd(cmd, *args)
|
9
|
+
client.command(cmd, *args)
|
10
|
+
rescue Errno::ECONNREFUSED, Errno::ENOENT
|
11
|
+
:not_started
|
12
|
+
end
|
13
|
+
|
14
|
+
def cmd(cmd, *args)
|
15
|
+
res = _cmd(cmd, *args)
|
16
|
+
|
17
|
+
if res == :not_started
|
18
|
+
error! "socket(#{Eye::Local.socket_path}) not found, did you `eye load`?"
|
19
|
+
elsif res == :timeouted
|
20
|
+
error! 'eye does not answer, timeouted...'
|
21
|
+
end
|
22
|
+
|
23
|
+
res
|
24
|
+
end
|
25
|
+
|
26
|
+
def say_load_result(res = {}, opts = {})
|
27
|
+
error!(res) unless res.is_a?(Hash)
|
28
|
+
say_filename = (res.size > 1)
|
29
|
+
say 'eye started!', :green if opts[:started]
|
30
|
+
error = false
|
31
|
+
res.each do |filename, _res|
|
32
|
+
say "#{filename}: ", nil, true if say_filename
|
33
|
+
show_load_message(_res, opts)
|
34
|
+
error = true if _res[:error]
|
35
|
+
end
|
36
|
+
|
37
|
+
exit(1) if error
|
38
|
+
end
|
39
|
+
|
40
|
+
def show_load_message(res, opts = {})
|
41
|
+
if res[:error]
|
42
|
+
say res[:message], :red
|
43
|
+
res[:backtrace].to_a.each{|line| say line, :red }
|
44
|
+
else
|
45
|
+
if opts[:syntax]
|
46
|
+
say 'config ok!', :green if !res[:empty]
|
47
|
+
else
|
48
|
+
say 'config loaded!', :green if !res[:empty]
|
49
|
+
end
|
50
|
+
|
51
|
+
if opts[:print_config]
|
52
|
+
require 'pp'
|
53
|
+
PP.pp res[:config], STDOUT, 150
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def send_command(_cmd, *args)
|
59
|
+
res = cmd(_cmd, *args)
|
60
|
+
if res == :unknown_command
|
61
|
+
error! "unknown command :#{_cmd}"
|
62
|
+
elsif res == :corrupted_data
|
63
|
+
error! 'something crazy wrong, check eye logs!'
|
64
|
+
elsif res.is_a?(Hash)
|
65
|
+
if res[:error]
|
66
|
+
error! "Error: #{res[:error]}"
|
67
|
+
elsif res = res[:result]
|
68
|
+
if res == []
|
69
|
+
error! "command :#{_cmd}, objects not found!"
|
70
|
+
else
|
71
|
+
say "command :#{_cmd} sended to [#{res * ", "}]"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
else
|
75
|
+
error! "unknown result #{res.inspect}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Eye::Cli::Render
|
2
|
+
private
|
3
|
+
DF = '%d %b %H:%M'
|
4
|
+
|
5
|
+
def render_info(data)
|
6
|
+
error!("unexpected server answer #{data.inspect}") unless data.is_a?(Hash)
|
7
|
+
|
8
|
+
make_str data
|
9
|
+
end
|
10
|
+
|
11
|
+
def make_str(data, level = -1)
|
12
|
+
return nil if !data || data.empty?
|
13
|
+
|
14
|
+
if data.is_a?(Array)
|
15
|
+
data.map{|el| make_str(el, level) }.compact * "\n"
|
16
|
+
else
|
17
|
+
str = nil
|
18
|
+
|
19
|
+
if data[:name]
|
20
|
+
return make_str(data[:subtree], level) if data[:name] == '__default__'
|
21
|
+
|
22
|
+
off = level * 2
|
23
|
+
off_str = ' ' * off
|
24
|
+
|
25
|
+
short_state = (data[:type] == :application && data[:states])
|
26
|
+
is_text = data[:state] || data[:states]
|
27
|
+
|
28
|
+
name = (data[:type] == :application && !is_text) ? "\033[1m#{data[:name]}\033[0m" : data[:name].to_s
|
29
|
+
off_len = short_state ? 20 : 35
|
30
|
+
str = off_str + (name + ' ').ljust(off_len - off, is_text ? '.' : ' ')
|
31
|
+
|
32
|
+
if short_state
|
33
|
+
str += ' ' + data[:states].map { |k, v| "#{k}:#{v}" }.join(', ')
|
34
|
+
elsif data[:state]
|
35
|
+
str += ' ' + data[:state].to_s
|
36
|
+
str += ' (' + resources_str(data[:resources]) + ')' if data[:resources] && data[:state].to_sym == :up
|
37
|
+
str += " (#{data[:state_reason]} at #{data[:state_changed_at].strftime(DF)})" if data[:state_reason] && data[:state] == 'unmonitored'
|
38
|
+
elsif data[:current_command]
|
39
|
+
chain_progress = if data[:chain_progress]
|
40
|
+
" #{data[:chain_progress][0]} of #{data[:chain_progress][1]}" rescue ''
|
41
|
+
end
|
42
|
+
str += " \e[1;33m[#{data[:current_command]}#{chain_progress}]\033[0m"
|
43
|
+
str += " (#{data[:chain_commands] * ', '})" if data[:chain_commands]
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
if data[:subtree].nil?
|
49
|
+
str
|
50
|
+
elsif !data[:subtree] && data[:type] != :application
|
51
|
+
nil
|
52
|
+
else
|
53
|
+
[str, make_str(data[:subtree], level + 1)].compact * "\n"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def resources_str(r)
|
59
|
+
return '' if !r || r.empty?
|
60
|
+
memory, cpu, start_time, pid = r[:memory], r[:cpu], r[:start_time], r[:pid]
|
61
|
+
return '' unless memory && cpu && start_time
|
62
|
+
|
63
|
+
res = "#{Eye::Utils.human_time(start_time)}, #{cpu.to_i}%"
|
64
|
+
res += ", #{memory / 1024 / 1024}Mb"
|
65
|
+
res += ", <#{pid}>"
|
66
|
+
|
67
|
+
res
|
68
|
+
end
|
69
|
+
|
70
|
+
def render_debug_info(data)
|
71
|
+
error!("unexpected server answer #{data.inspect}") unless data.is_a?(Hash)
|
72
|
+
|
73
|
+
s = ""
|
74
|
+
|
75
|
+
config_yaml = data.delete(:config_yaml)
|
76
|
+
|
77
|
+
data.each do |k, v|
|
78
|
+
s << "#{"#{k}:".ljust(10)} "
|
79
|
+
|
80
|
+
case k
|
81
|
+
when :resources
|
82
|
+
s << resources_str(v)
|
83
|
+
else
|
84
|
+
s << "#{v}"
|
85
|
+
end
|
86
|
+
|
87
|
+
s << "\n"
|
88
|
+
end
|
89
|
+
|
90
|
+
s << "\n"
|
91
|
+
|
92
|
+
if config_yaml
|
93
|
+
s << "Current config:\n"
|
94
|
+
s << config_yaml
|
95
|
+
end
|
96
|
+
|
97
|
+
s
|
98
|
+
end
|
99
|
+
|
100
|
+
def render_history(data)
|
101
|
+
error!("unexpected server answer #{data.inspect}") unless data.is_a?(Hash)
|
102
|
+
|
103
|
+
res = []
|
104
|
+
data.each do |name, data|
|
105
|
+
res << detail_process_info(name, data)
|
106
|
+
end
|
107
|
+
|
108
|
+
res * "\n"
|
109
|
+
end
|
110
|
+
|
111
|
+
def detail_process_info(name, history)
|
112
|
+
return if history.empty?
|
113
|
+
|
114
|
+
res = "\033[1m#{name}\033[0m:\n"
|
115
|
+
history = history.reverse
|
116
|
+
|
117
|
+
history.chunk{|h| [h[:state], h[:reason].to_s] }.each do |_, hist|
|
118
|
+
if hist.size >= 3
|
119
|
+
res << detail_process_info_string(hist[0])
|
120
|
+
res << detail_process_info_string(:state => "... #{hist.size - 2} times", :reason => '...', :at => hist[-1][:at])
|
121
|
+
res << detail_process_info_string(hist[-1])
|
122
|
+
else
|
123
|
+
hist.each do |h|
|
124
|
+
res << detail_process_info_string(h)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
res
|
130
|
+
end
|
131
|
+
|
132
|
+
def detail_process_info_string(h)
|
133
|
+
state = h[:state].to_s.ljust(14)
|
134
|
+
"#{Time.at(h[:at]).strftime(DF)} - #{state} (#{h[:reason]})\n"
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Eye::Cli::Server
|
2
|
+
private
|
3
|
+
|
4
|
+
def server_started?
|
5
|
+
_cmd(:ping) == :pong
|
6
|
+
end
|
7
|
+
|
8
|
+
def loader_path
|
9
|
+
filename = File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. .. bin loader_eye]))
|
10
|
+
File.exists?(filename) ? filename : nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def ruby_path
|
14
|
+
require 'rbconfig'
|
15
|
+
RbConfig::CONFIG['bindir'] + '/ruby'
|
16
|
+
end
|
17
|
+
|
18
|
+
def ensure_loader_path
|
19
|
+
unless loader_path
|
20
|
+
error! "start monitoring needs to run under ruby with installed gem 'eye'"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def server_start_foreground(conf = nil)
|
25
|
+
ensure_loader_path
|
26
|
+
Eye::Local.ensure_eye_dir
|
27
|
+
|
28
|
+
if server_started?
|
29
|
+
_cmd(:quit) && sleep(1) # stop previous server
|
30
|
+
end
|
31
|
+
|
32
|
+
args = []
|
33
|
+
args += ['-c', conf] if conf
|
34
|
+
args += ['-l', 'stdout']
|
35
|
+
|
36
|
+
Process.exec(ruby_path, loader_path, *args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def server_start(configs)
|
40
|
+
ensure_loader_path
|
41
|
+
Eye::Local.ensure_eye_dir
|
42
|
+
|
43
|
+
ensure_stop_previous_server
|
44
|
+
|
45
|
+
args = []
|
46
|
+
opts = {:out => '/dev/null', :err => '/dev/null', :in => '/dev/null',
|
47
|
+
:chdir => '/', :pgroup => true}
|
48
|
+
|
49
|
+
pid = Process.spawn(ruby_path, loader_path, *args, opts)
|
50
|
+
Process.detach(pid)
|
51
|
+
File.open(Eye::Local.pid_path, 'w'){|f| f.write(pid) }
|
52
|
+
|
53
|
+
unless wait_server
|
54
|
+
error! 'server not runned in 15 seconds, something crazy wrong'
|
55
|
+
end
|
56
|
+
|
57
|
+
configs.unshift(Eye::Local.eyeconfig) if File.exists?(Eye::Local.eyeconfig)
|
58
|
+
|
59
|
+
if !configs.empty?
|
60
|
+
say_load_result cmd(:load, *configs), :started => true
|
61
|
+
else
|
62
|
+
say 'started!', :green
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def ensure_stop_previous_server
|
67
|
+
Eye::Local.ensure_eye_dir
|
68
|
+
pid = File.read(Eye::Local.pid_path).to_i rescue nil
|
69
|
+
if pid
|
70
|
+
Process.kill(9, pid) rescue nil
|
71
|
+
end
|
72
|
+
File.delete(Eye::Local.pid_path) rescue nil
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
def wait_server(timeout = 15)
|
77
|
+
Timeout.timeout(timeout) do
|
78
|
+
sleep 0.3 while !server_started?
|
79
|
+
end
|
80
|
+
true
|
81
|
+
rescue Timeout::Error
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/lib/eye/client.rb
CHANGED
@@ -13,7 +13,7 @@ class Eye::Client
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def attempt_command(pack)
|
16
|
-
Timeout.timeout(Eye::
|
16
|
+
Timeout.timeout(Eye::Local.client_timeout) do
|
17
17
|
return send_request(pack)
|
18
18
|
end
|
19
19
|
|
@@ -25,8 +25,8 @@ class Eye::Client
|
|
25
25
|
UNIXSocket.open(@socket_path) do |socket|
|
26
26
|
socket.write(pack)
|
27
27
|
data = socket.read
|
28
|
-
res = Marshal.load(data) rescue :
|
28
|
+
res = Marshal.load(data) rescue :corrupted_data
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
end
|
32
|
+
end
|
data/lib/eye/config.rb
CHANGED
@@ -30,33 +30,36 @@ class Eye::Config
|
|
30
30
|
raise Eye::Dsl::Error, "blank pid_file for: #{no_pid_file.map{|c| c[:name]} * ', '}"
|
31
31
|
end
|
32
32
|
|
33
|
-
# Check
|
33
|
+
# Check duplicates of the full pid_file
|
34
34
|
|
35
|
-
|
35
|
+
dupl_pids = all_processes.each_with_object(Hash.new(0)) do |o, h|
|
36
36
|
ex_pid_file = Eye::System.normalized_file(o[:pid_file], o[:working_dir])
|
37
37
|
h[ex_pid_file] += 1
|
38
38
|
end
|
39
|
-
|
39
|
+
dupl_pids = dupl_pids.select{|k,v| v>1}
|
40
40
|
|
41
|
-
if
|
42
|
-
raise Eye::Dsl::Error, "
|
41
|
+
if dupl_pids.present?
|
42
|
+
raise Eye::Dsl::Error, "duplicate pid_files: #{dupl_pids.inspect}"
|
43
43
|
end
|
44
44
|
|
45
|
-
# Check
|
46
|
-
|
45
|
+
# Check duplicates of the full_name
|
46
|
+
dupl_names = all_processes.each_with_object(Hash.new(0)) do |o, h|
|
47
47
|
full_name = "#{o[:application]}:#{o[:group]}:#{o[:name]}"
|
48
48
|
h[full_name] += 1
|
49
49
|
end
|
50
|
-
|
50
|
+
dupl_names = dupl_names.select{|k,v| v>1}
|
51
51
|
|
52
|
-
if
|
53
|
-
raise Eye::Dsl::Error, "
|
52
|
+
if dupl_names.present?
|
53
|
+
raise Eye::Dsl::Error, "duplicate names: #{dupl_names.inspect}"
|
54
54
|
end
|
55
55
|
|
56
56
|
# validate processes with their own validate
|
57
57
|
all_processes.each do |process_cfg|
|
58
58
|
Eye::Process.validate process_cfg
|
59
59
|
end
|
60
|
+
|
61
|
+
# just to be sure ENV was not removed
|
62
|
+
ENV[''] rescue raise Eye::Dsl::Error.new("ENV is not a hash '#{ENV.inspect}'")
|
60
63
|
end
|
61
64
|
|
62
65
|
def processes
|
@@ -73,16 +76,16 @@ class Eye::Config
|
|
73
76
|
|
74
77
|
def delete_group(name)
|
75
78
|
applications.each do |app_name, app_cfg|
|
76
|
-
app_cfg[:groups].delete(name)
|
79
|
+
(app_cfg[:groups] || {}).delete(name)
|
77
80
|
end
|
78
81
|
end
|
79
82
|
|
80
83
|
def delete_process(name)
|
81
84
|
applications.each do |app_name, app_cfg|
|
82
|
-
app_cfg[:groups].each do |gr_name, gr_cfg|
|
83
|
-
gr_cfg[:processes].delete(name)
|
85
|
+
(app_cfg[:groups] || {}).each do |gr_name, gr_cfg|
|
86
|
+
(gr_cfg[:processes] || {}).delete(name)
|
84
87
|
end
|
85
88
|
end
|
86
89
|
end
|
87
90
|
|
88
|
-
end
|
91
|
+
end
|
data/lib/eye/controller.rb
CHANGED
@@ -1,19 +1,17 @@
|
|
1
1
|
require 'celluloid'
|
2
|
-
|
3
2
|
require 'yaml'
|
4
|
-
require 'active_support'
|
5
|
-
require 'active_support/core_ext/object/blank'
|
6
|
-
require 'active_support/core_ext/object/try'
|
7
|
-
require 'active_support/core_ext/numeric'
|
8
|
-
require 'active_support/core_ext/string/filters'
|
9
|
-
require 'active_support/core_ext/array/extract_options'
|
10
3
|
|
11
4
|
require_relative 'utils/celluloid_klass'
|
12
5
|
require_relative 'utils/pmap'
|
13
6
|
|
7
|
+
require_relative 'utils/leak_19'
|
8
|
+
require_relative 'utils/mini_active_support'
|
9
|
+
|
14
10
|
# Extend all objects with logger
|
15
11
|
Object.send(:include, Eye::Logger::ObjectExt)
|
16
12
|
|
13
|
+
Eye::Sigar # needs to preload
|
14
|
+
|
17
15
|
class Eye::Controller
|
18
16
|
include Celluloid
|
19
17
|
|
@@ -22,7 +20,6 @@ class Eye::Controller
|
|
22
20
|
autoload :Commands, 'eye/controller/commands'
|
23
21
|
autoload :Status, 'eye/controller/status'
|
24
22
|
autoload :SendCommand, 'eye/controller/send_command'
|
25
|
-
autoload :ShowHistory, 'eye/controller/show_history'
|
26
23
|
autoload :Options, 'eye/controller/options'
|
27
24
|
|
28
25
|
include Eye::Controller::Load
|
@@ -30,7 +27,6 @@ class Eye::Controller
|
|
30
27
|
include Eye::Controller::Commands
|
31
28
|
include Eye::Controller::Status
|
32
29
|
include Eye::Controller::SendCommand
|
33
|
-
include Eye::Controller::ShowHistory
|
34
30
|
include Eye::Controller::Options
|
35
31
|
|
36
32
|
attr_reader :applications, :current_config
|
@@ -42,7 +38,7 @@ class Eye::Controller
|
|
42
38
|
@current_config = Eye::Config.new
|
43
39
|
|
44
40
|
Celluloid::logger = Eye::Logger.new('celluloid')
|
45
|
-
Eye::SystemResources.
|
41
|
+
Eye::SystemResources.cache
|
46
42
|
|
47
43
|
info "starting #{Eye::ABOUT} (#{$$})"
|
48
44
|
end
|
@@ -16,14 +16,6 @@ module Eye::Controller::Commands
|
|
16
16
|
signal(*args)
|
17
17
|
when :load
|
18
18
|
load(*args)
|
19
|
-
when :info
|
20
|
-
info_string(*args)
|
21
|
-
when :xinfo
|
22
|
-
info_string_debug(*args)
|
23
|
-
when :oinfo
|
24
|
-
info_string_short(*args)
|
25
|
-
when :history
|
26
|
-
history_string(*args)
|
27
19
|
when :quit
|
28
20
|
quit
|
29
21
|
when :check
|
@@ -38,9 +30,13 @@ module Eye::Controller::Commands
|
|
38
30
|
Eye::Logger.dev
|
39
31
|
|
40
32
|
# object commands, for api
|
41
|
-
when :
|
33
|
+
when :info_data
|
42
34
|
info_data(*args)
|
43
|
-
when :
|
35
|
+
when :short_data
|
36
|
+
short_data(*args)
|
37
|
+
when :debug_data
|
38
|
+
debug_data(*args)
|
39
|
+
when :history_data
|
44
40
|
history_data(*args)
|
45
41
|
|
46
42
|
else
|