eye 0.4.2 → 0.5

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGES.md +11 -0
  5. data/README.md +3 -3
  6. data/Rakefile +8 -0
  7. data/bin/eye +0 -316
  8. data/bin/loader_eye +3 -3
  9. data/examples/test.eye +2 -2
  10. data/eye.gemspec +4 -9
  11. data/lib/eye.rb +4 -2
  12. data/lib/eye/application.rb +3 -3
  13. data/lib/eye/checker.rb +14 -5
  14. data/lib/eye/checker/cputime.rb +23 -0
  15. data/lib/eye/checker/file_touched.rb +15 -0
  16. data/lib/eye/checker/http.rb +7 -9
  17. data/lib/eye/checker/memory.rb +1 -1
  18. data/lib/eye/checker/runtime.rb +28 -0
  19. data/lib/eye/checker/socket.rb +4 -4
  20. data/lib/eye/cli.rb +166 -0
  21. data/lib/eye/cli/commands.rb +79 -0
  22. data/lib/eye/cli/render.rb +137 -0
  23. data/lib/eye/cli/server.rb +85 -0
  24. data/lib/eye/client.rb +3 -3
  25. data/lib/eye/config.rb +17 -14
  26. data/lib/eye/controller.rb +6 -10
  27. data/lib/eye/controller/commands.rb +6 -10
  28. data/lib/eye/controller/helpers.rb +1 -1
  29. data/lib/eye/controller/send_command.rb +5 -2
  30. data/lib/eye/controller/status.rb +37 -105
  31. data/lib/eye/dsl.rb +1 -1
  32. data/lib/eye/dsl/application_opts.rb +6 -2
  33. data/lib/eye/dsl/child_process_opts.rb +3 -2
  34. data/lib/eye/dsl/config_opts.rb +2 -2
  35. data/lib/eye/dsl/group_opts.rb +2 -1
  36. data/lib/eye/dsl/main.rb +4 -2
  37. data/lib/eye/dsl/opts.rb +11 -4
  38. data/lib/eye/dsl/validation.rb +49 -43
  39. data/lib/eye/group.rb +1 -1
  40. data/lib/eye/loader.rb +5 -9
  41. data/lib/eye/{settings.rb → local.rb} +1 -1
  42. data/lib/eye/logger.rb +5 -0
  43. data/lib/eye/notify.rb +12 -6
  44. data/lib/eye/notify/jabber.rb +2 -2
  45. data/lib/eye/process/child.rb +3 -1
  46. data/lib/eye/process/commands.rb +2 -2
  47. data/lib/eye/process/controller.rb +1 -1
  48. data/lib/eye/process/trigger.rb +1 -1
  49. data/lib/eye/sigar.rb +5 -0
  50. data/lib/eye/system.rb +7 -6
  51. data/lib/eye/system_resources.rb +46 -41
  52. data/lib/eye/trigger.rb +15 -8
  53. data/lib/eye/trigger/flapping.rb +1 -1
  54. data/lib/eye/trigger/stop_childs.rb +1 -1
  55. data/lib/eye/trigger/transition.rb +15 -0
  56. data/lib/eye/utils.rb +12 -0
  57. data/lib/eye/utils/leak_19.rb +7 -0
  58. data/lib/eye/utils/mini_active_support.rb +106 -0
  59. metadata +24 -15
  60. data/lib/eye/controller/show_history.rb +0 -63
  61. data/lib/eye/trigger/state.rb +0 -11
@@ -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
@@ -13,7 +13,7 @@ class Eye::Client
13
13
  end
14
14
 
15
15
  def attempt_command(pack)
16
- Timeout.timeout(Eye::Settings.client_timeout) do
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 :corrupred_data
28
+ res = Marshal.load(data) rescue :corrupted_data
29
29
  end
30
30
  end
31
31
 
32
- end
32
+ end
@@ -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 dublicates of the full pid_file
33
+ # Check duplicates of the full pid_file
34
34
 
35
- dubl_pids = all_processes.each_with_object(Hash.new(0)) do |o, h|
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
- dubl_pids = dubl_pids.select{|k,v| v>1}
39
+ dupl_pids = dupl_pids.select{|k,v| v>1}
40
40
 
41
- if dubl_pids.present?
42
- raise Eye::Dsl::Error, "dublicate pid_files: #{dubl_pids.inspect}"
41
+ if dupl_pids.present?
42
+ raise Eye::Dsl::Error, "duplicate pid_files: #{dupl_pids.inspect}"
43
43
  end
44
44
 
45
- # Check dublicates of the full_name
46
- dubl_names = all_processes.each_with_object(Hash.new(0)) do |o, h|
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
- dubl_names = dubl_names.select{|k,v| v>1}
50
+ dupl_names = dupl_names.select{|k,v| v>1}
51
51
 
52
- if dubl_names.present?
53
- raise Eye::Dsl::Error, "dublicate names: #{dubl_names.inspect}"
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
@@ -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.setup
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 :raw_info
33
+ when :info_data
42
34
  info_data(*args)
43
- when :raw_history
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
@@ -8,7 +8,7 @@ module Eye::Controller::Helpers
8
8
  end
9
9
 
10
10
  def save_cache
11
- File.open(Eye::Settings.cache_path, 'w') { |f| f.write(cache_str) }
11
+ File.open(Eye::Local.cache_path, 'w') { |f| f.write(cache_str) }
12
12
  rescue => ex
13
13
  log_ex(ex)
14
14
  end
@@ -35,8 +35,11 @@ private
35
35
 
36
36
  rescue Error => ex
37
37
  log_ex(ex)
38
-
39
38
  {:error => ex.message}
39
+
40
+ rescue Celluloid::DeadActorError => ex
41
+ log_ex(ex)
42
+ {:error => "'#{ex.message}', try again!"}
40
43
  end
41
44
 
42
45
  def remove_object_from_tree(obj)
@@ -75,7 +78,7 @@ private
75
78
  end
76
79
 
77
80
  res = Eye::Utils::AliveArray.new
78
- obj_strs.map{|c| c.to_s.split(",")}.flatten.each do |mask|
81
+ obj_strs.map{|c| c.to_s.split(',')}.flatten.each do |mask|
79
82
  objs = find_objects_by_mask(mask.to_s.strip)
80
83
  objs.select! { |obj| obj.app_name == h[:application] } if h[:application]
81
84
  res += objs
@@ -1,50 +1,42 @@
1
1
  module Eye::Controller::Status
2
2
 
3
- def info_string(*args)
4
- make_str(info_data(*args)).to_s
5
- end
6
-
7
- def info_string_short(*args)
8
- make_str({:subtree => @applications.map{|a| a.status_data_short } }).to_s
9
- end
10
-
11
- def info_string_debug(*args)
3
+ def debug_data(*args)
12
4
  h = args.extract_options!
13
5
  actors = Celluloid::Actor.all.map{|actor| actor.__klass__ }.group_by{|a| a}.map{|k,v| [k, v.size]}.sort_by{|a|a[1]}.reverse
14
6
 
15
- str = <<-S
16
- About: #{Eye::ABOUT}
17
- Info: #{resources_str(Eye::SystemResources.resources($$))}
18
- Ruby: #{RUBY_DESCRIPTION}
19
- Gems: #{%w|Celluloid Celluloid::IO ActiveSupport StateMachine NIO|.map{|c| gem_version(c) }}
20
- Logger: #{Eye::Logger.dev}
21
- Socket: #{Eye::Settings::socket_path}
22
- Pid: #{Eye::Settings::pid_path}
23
- Actors: #{actors.inspect}
24
-
25
- S
7
+ res = {
8
+ :about => Eye::ABOUT,
9
+ :resources => Eye::SystemResources.resources($$),
10
+ :ruby => RUBY_DESCRIPTION,
11
+ :gems => %w|Celluloid Celluloid::IO StateMachine NIO Sigar|.map{|c| gem_version(c) },
12
+ :logger => Eye::Logger.dev,
13
+ :pid_path => Eye::Local::pid_path,
14
+ :actors => actors
15
+ }
26
16
 
27
- str += make_str(info_data_debug) + "\n" if h[:processes].present?
17
+ res[:config_yaml] = YAML.dump(current_config.to_h) if h[:config].present?
28
18
 
29
- if h[:config].present?
30
- str += "\nCurrent config: \n"
31
- str += YAML.dump(current_config.to_h)
32
- end
33
-
34
- GC.start
35
- str
19
+ res
36
20
  end
37
21
 
38
22
  def info_data(*args)
39
23
  {:subtree => info_objects(*args).map{|a| a.status_data } }
40
24
  end
41
25
 
42
- private
26
+ def short_data(*args)
27
+ {:subtree => @applications.map{|a| a.status_data_short } }
28
+ end
43
29
 
44
- def info_data_debug(*args)
45
- {:subtree => info_objects(*args).map{|a| a.status_data(true) } }
30
+ def history_data(*args)
31
+ res = {}
32
+ history_objects(*args).each do |process|
33
+ res[process.full_name] = process.schedule_history.reject{|c| c[:state] == :check_crash }
34
+ end
35
+ res
46
36
  end
47
37
 
38
+ private
39
+
48
40
  def info_objects(*args)
49
41
  res = []
50
42
  return @applications if args.empty?
@@ -52,79 +44,6 @@ private
52
44
  res
53
45
  end
54
46
 
55
- def make_str(data, level = -1)
56
- return nil if data.blank?
57
-
58
- if data.is_a?(Array)
59
- data.map{|el| make_str(el, level) }.compact * "\n"
60
- else
61
- str = nil
62
-
63
- if data[:name]
64
- return make_str(data[:subtree], level) if data[:name] == '__default__'
65
-
66
- off = level * 2
67
- off_str = ' ' * off
68
- name = (data[:type] == :application && data[:state].blank?) ? "\033[1m#{data[:name]}\033[0m" : data[:name].to_s
69
- off_len = (data[:type] == :application && !data[:state].blank?) ? 20 : 35
70
- str = off_str + (name + ' ').ljust(off_len - off, data[:state] ? '.' : ' ')
71
-
72
- if data[:debug]
73
- str += ' | ' + debug_str(data[:debug])
74
-
75
- # for group show chain data
76
- if data[:debug][:chain]
77
- str += " (chain: #{data[:debug][:chain].map(&:to_i)})"
78
- end
79
- elsif data[:state]
80
- str += ' ' + data[:state].to_s
81
- str += ' (' + resources_str(data[:resources]) + ')' if data[:resources].present? && data[:state].to_sym == :up
82
- str += " (#{data[:state_reason]} at #{data[:state_changed_at].to_s(:short)})" if data[:state_reason] && data[:state] == 'unmonitored'
83
- elsif data[:current_command]
84
- chain_progress = if data[:chain_progress]
85
- " #{data[:chain_progress][0]} of #{data[:chain_progress][1]}" rescue ''
86
- end
87
- str += " \e[1;33m[#{data[:current_command]}#{chain_progress}]\033[0m"
88
- str += " (#{data[:chain_commands] * ', '})" if data[:chain_commands]
89
- end
90
-
91
- end
92
-
93
- if data[:subtree].nil?
94
- str
95
- elsif data[:subtree].blank? && data[:type] != :application
96
- nil
97
- else
98
- [str, make_str(data[:subtree], level + 1)].compact * "\n"
99
- end
100
- end
101
- end
102
-
103
- def resources_str(r)
104
- return '' if r.blank?
105
-
106
- res = "#{r[:start_time]}, #{r[:cpu]}%"
107
- res += ", #{r[:memory] / 1024}Mb" if r[:memory]
108
- res += ", <#{r[:pid]}>"
109
-
110
- res
111
- end
112
-
113
- def debug_str(debug)
114
- return '' unless debug
115
-
116
- q = 'q(' + (debug[:queue] || []) * ',' + ')'
117
- w = 'w(' + (debug[:watchers] || []) * ',' + ')'
118
-
119
- [w, q] * '; '
120
- end
121
-
122
- def status_applications(app = nil)
123
- apps = app.present? ? @applications.select{|a| a.name == app} : nil
124
- apps = @applications unless apps
125
- apps
126
- end
127
-
128
47
  def gem_version(klass)
129
48
  v = nil
130
49
  begin
@@ -135,4 +54,17 @@ private
135
54
  "#{klass}=#{v}"
136
55
  end
137
56
 
138
- end
57
+ def history_objects(*args)
58
+ args = ['*'] if args.empty?
59
+ res = []
60
+ matched_objects(*args) do |obj|
61
+ if (obj.is_a?(Eye::Process) || obj.is_a?(Eye::ChildProcess))
62
+ res << obj
63
+ else
64
+ res += obj.processes.to_a
65
+ end
66
+ end
67
+ Eye::Utils::AliveArray.new(res)
68
+ end
69
+
70
+ end