eye 0.7.pre → 0.7

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGES.md +10 -2
  4. data/README.md +5 -0
  5. data/examples/delayed_job.eye +1 -1
  6. data/examples/dependency.eye +1 -1
  7. data/examples/plugin/plugin.rb +1 -1
  8. data/examples/process_thin.rb +2 -1
  9. data/examples/processes/forking.rb +6 -2
  10. data/examples/processes/sample.rb +4 -4
  11. data/examples/syslog.eye +15 -0
  12. data/examples/test.eye +3 -0
  13. data/examples/thin-farm.eye +2 -2
  14. data/examples/unicorn.eye +1 -1
  15. data/eye.gemspec +1 -1
  16. data/lib/eye.rb +1 -1
  17. data/lib/eye/application.rb +3 -10
  18. data/lib/eye/checker.rb +2 -1
  19. data/lib/eye/checker/children_count.rb +1 -7
  20. data/lib/eye/checker/file_touched.rb +1 -1
  21. data/lib/eye/checker/http.rb +2 -3
  22. data/lib/eye/checker/ssl_socket.rb +28 -0
  23. data/lib/eye/child_process.rb +4 -4
  24. data/lib/eye/cli.rb +12 -6
  25. data/lib/eye/cli/commands.rb +8 -8
  26. data/lib/eye/cli/render.rb +2 -8
  27. data/lib/eye/cli/server.rb +3 -2
  28. data/lib/eye/client.rb +2 -5
  29. data/lib/eye/config.rb +33 -3
  30. data/lib/eye/controller.rb +0 -1
  31. data/lib/eye/controller/load.rb +5 -10
  32. data/lib/eye/controller/status.rb +1 -1
  33. data/lib/eye/dsl.rb +2 -2
  34. data/lib/eye/dsl/config_opts.rb +8 -1
  35. data/lib/eye/dsl/opts.rb +8 -4
  36. data/lib/eye/dsl/pure_opts.rb +1 -3
  37. data/lib/eye/dsl/validation.rb +4 -4
  38. data/lib/eye/group.rb +12 -3
  39. data/lib/eye/local.rb +5 -15
  40. data/lib/eye/notify.rb +0 -3
  41. data/lib/eye/process/children.rb +1 -1
  42. data/lib/eye/process/commands.rb +1 -1
  43. data/lib/eye/process/data.rb +2 -2
  44. data/lib/eye/process/scheduler.rb +4 -0
  45. data/lib/eye/process/system.rb +14 -8
  46. data/lib/eye/system_resources.rb +18 -3
  47. data/lib/eye/utils.rb +1 -1
  48. data/lib/eye/utils/pmap.rb +1 -2
  49. metadata +7 -6
  50. data/lib/eye/utils/celluloid_klass.rb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 488ed21561da07936dd5fbc3e0d869e4665ba4a5
4
- data.tar.gz: 12b6d6c69ee5e0bf9409bb61e700a6525d1d386a
3
+ metadata.gz: af465bb7737a6f1891bc3ab6ee5d9ebe9547530a
4
+ data.tar.gz: 929efa8c2932925ef6aa2974377982a16e50494e
5
5
  SHA512:
6
- metadata.gz: 54a0993fb03ecf29c9f8a572c977aeb6856da53b972f6d3555c1e17fef13bc807fdfb819ed968f4571f5ee3dd05c8faf0cf766a77be6017ac81e007927605438
7
- data.tar.gz: 3023586158006d3c76ba25675b88bfc2eb0977cafc748b928437ab1cf74178d4494e229e6028615ae8c1efc667188566b0801f5739fa565a94026e6cd737fb56
6
+ metadata.gz: 9bb24f0bc0d47d2345aa0a1f708ad76486cfbe72363cdd6b6410133b912fc8cf47bddde0995422272c7688338ca986386ec3e8b4e9234b09d82adcc9dda155a6
7
+ data.tar.gz: edf8b2a9874f4d58423d501bbe130e75109317be53a05d418118782f127ba5b4637d5109674c1621f21ceb5a04022cbaa6ba8864f2ab34a690c1b1b277798b44
@@ -3,5 +3,5 @@ rvm:
3
3
  - "1.9.3"
4
4
  - "2.0.0"
5
5
  - "2.1"
6
- - "2.2"
6
+ - "2.2.2"
7
7
  script: bundle exec rake split_test N=15
data/CHANGES.md CHANGED
@@ -1,10 +1,18 @@
1
- 0.7.pre
1
+ 0.7
2
2
  -------
3
- * add trigger starting_guard
3
+ * add `stdall syslog`, example: https://github.com/kostya/eye/blob/master/examples/syslog.eye
4
+ * added check `ssl_socket` #125
5
+ * some fixes with `eye q -s`
6
+ * fixed `__default__` apps
7
+ * default loaded configs with first eye start, is: `/etc/eye.conf`, and `~/.eyeconfig`
8
+ * add trigger `starting_guard`
9
+ * fix `load_env` function
4
10
  * fix multiple contacts #118
5
11
  * add slack notifier #115
6
12
  * some fixes in depend_on
7
13
  * some fixes in flapping
14
+ * add proxy_url to http check
15
+ * process with children, shows children history now
8
16
  * Update Celluloid to 0.16.0
9
17
 
10
18
  0.6.4
data/README.md CHANGED
@@ -43,6 +43,9 @@ Eye.application 'test' do
43
43
  # All options inherits down to the config leafs.
44
44
  # except `env`, which merging down
45
45
 
46
+ # uid "user_name" # run app as a user_name (optional) - available only on ruby >= 2.0
47
+ # gid "group_name" # run app as a group_name (optional) - available only on ruby >= 2.0
48
+
46
49
  working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
47
50
  stdall 'trash.log' # stdout,err logs for processes by default
48
51
  env 'APP_ENV' => 'production' # global env for each processes
@@ -152,6 +155,8 @@ test
152
155
  thin ............................ up (21:53, 2%, 54Mb, <4228>)
153
156
  ```
154
157
 
158
+ $ eye i -j # show info in JSON format
159
+
155
160
  ### Commands:
156
161
 
157
162
  start, stop, restart, delete, monitor, unmonitor
@@ -2,7 +2,7 @@ cwd = File.expand_path(File.join(File.dirname(__FILE__), %w[ ../ ../ ]))
2
2
 
3
3
  config_path = File.join(cwd, %w{ config dj.yml } )
4
4
 
5
- workers_count = if File.exists?(config_path)
5
+ workers_count = if File.exist?(config_path)
6
6
  YAML.load_file(config_path).try(:[], :workers) || 5
7
7
  else
8
8
  5
@@ -1,4 +1,4 @@
1
- # process dependencies :b -> :a
1
+ # process dependencies example
2
2
 
3
3
  Eye.app :dependency do
4
4
  process(:a) do
@@ -13,7 +13,7 @@ class Reactor
13
13
  end
14
14
 
15
15
  def read_file
16
- if File.exists?(@filename)
16
+ if File.exist?(@filename)
17
17
  cmd = File.read(@filename).chop
18
18
  File.delete(@filename) rescue nil
19
19
  cmd
@@ -1,3 +1,4 @@
1
+ # part of thin-farm.eye config
1
2
 
2
3
  def thin(proxy, port)
3
4
  name = "thin-#{port}"
@@ -10,7 +11,7 @@ def thin(proxy, port)
10
11
  "-R thin.ru",
11
12
  "--tag #{proxy.app.name}.#{proxy.name}",
12
13
  "-t 60",
13
- "-e #{proxy.env["RAILS_ENV"]}",
14
+ "-e #{proxy.env['RAILS_ENV']}",
14
15
  "-c #{proxy.working_dir}",
15
16
  "-a 127.0.0.1"
16
17
  ]
@@ -2,19 +2,23 @@ require 'bundler/setup'
2
2
  require 'forking'
3
3
 
4
4
  root = File.expand_path(File.dirname(__FILE__))
5
+ cnt = (ENV['FORKING_COUNT'] || 3).to_i
5
6
 
6
7
  f = Forking.new(:name => 'forking', :working_dir => root,
7
8
  :log_file => "#{root}/forking.log",
8
9
  :pid_file => "#{root}/forking.pid", :sync_log => true)
9
10
 
10
- 3.times do |i|
11
+ cnt.times do |i|
11
12
  f.spawn(:log_file => "#{root}/child#{i}.log", :sync_log => true) do
12
13
  $0 = "forking child"
14
+ t = 0
13
15
  loop do
14
16
  p "#{Time.now} - #{Time.now.to_f} - #{i} - tick"
15
17
  sleep 0.1
18
+ t += 0.1
19
+ exit if t > 300
16
20
  end
17
21
  end
18
22
  end
19
23
 
20
- f.run!
24
+ f.run!
@@ -53,7 +53,7 @@ optparse.parse!
53
53
  module Sample
54
54
  def puts(mes = "")
55
55
  tm = Time.now
56
- STDOUT.puts "#{tm.to_s} (#{tm.to_f}) - #{mes}"
56
+ STDOUT.puts "#{tm} (#{tm.to_f}) - #{mes}"
57
57
  STDOUT.flush
58
58
  end
59
59
 
@@ -92,10 +92,10 @@ if options[:daemonize]
92
92
  daemonize(options[:pid_file], options[:log_file], options[:daemonize_delay])
93
93
  end
94
94
 
95
- puts "Started #{ARGV.inspect}, #{options.inspect}, #{ENV["ENV1"]}"
95
+ puts "Started #{ARGV.inspect}, #{options.inspect}, #{ENV['ENV1']}"
96
96
 
97
97
  if options[:lock_file]
98
- if File.exists?(options[:lock_file])
98
+ if File.exist?(options[:lock_file])
99
99
  puts "Lock file exists, exiting"
100
100
  exit 1
101
101
  else
@@ -124,7 +124,7 @@ loop do
124
124
  puts "tick"
125
125
 
126
126
  if options[:watch_file]
127
- if File.exists?(options[:watch_file])
127
+ if File.exist?(options[:watch_file])
128
128
  puts "watch file finded"
129
129
  File.unlink(options[:watch_file])
130
130
 
@@ -0,0 +1,15 @@
1
+ # output eye logger to syslog, and process stdout to syslog too
2
+ # experimental feature, in some cases may be unstable
3
+
4
+ Eye.config do
5
+ logger syslog
6
+ end
7
+
8
+ Eye.app :syslog_test do
9
+ process :some do
10
+ pid_file "/tmp/syslog_test.pid"
11
+ start_command "ruby -e 'loop { p Time.now; sleep 1 }'"
12
+ daemonize!
13
+ stdall syslog
14
+ end
15
+ end
@@ -11,6 +11,9 @@ Eye.application 'test' do
11
11
  # All options inherits down to the config leafs.
12
12
  # except `env`, which merging down
13
13
 
14
+ # uid "user_name" # run app as a user_name (optional) - available only on ruby >= 2.0
15
+ # gid "group_name" # run app as a group_name (optional) - available only on ruby >= 2.0
16
+
14
17
  working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
15
18
  stdall 'trash.log' # stdout,err logs for processes by default
16
19
  env 'APP_ENV' => 'production' # global env for each processes
@@ -11,8 +11,8 @@ Eye.app 'thin-farm' do
11
11
  working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
12
12
  env "RAILS_ENV" => "production"
13
13
 
14
- stop_on_delete true # this option means, when we change pids and load config,
15
- # deleted processes will be stops
14
+ # more about stop_on_delete: https://github.com/kostya/eye/wiki/About-stop_on_delete-=-true
15
+ stop_on_delete true
16
16
 
17
17
  trigger :flapping, :times => 10, :within => 1.minute
18
18
  check :memory, :below => 60.megabytes, :every => 30.seconds, :times => 5
@@ -1,4 +1,4 @@
1
- # Example: now to run unicorn, and monitor its child processes
1
+ # Example: how to run unicorn, and monitor its child processes
2
2
 
3
3
  RUBY = '/usr/local/ruby/1.9.3/bin/ruby' # ruby on the server
4
4
  RAILS_ENV = 'production'
@@ -23,7 +23,7 @@ Gem::Specification.new do |gem|
23
23
  gem.add_dependency 'celluloid-io', '~> 0.16.0'
24
24
  gem.add_dependency 'state_machine'
25
25
  gem.add_dependency 'thor'
26
- gem.add_dependency 'sigar', '~> 0.7.2'
26
+ gem.add_dependency 'sigar', '~> 0.7.3'
27
27
 
28
28
  gem.add_development_dependency 'rake'
29
29
  gem.add_development_dependency 'rspec', '< 2.14'
data/lib/eye.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Eye
2
- VERSION = "0.7.pre"
2
+ VERSION = "0.7"
3
3
  ABOUT = "Eye v#{VERSION} (c) 2012-2015 @kostya"
4
4
  PROCLINE = "eye monitoring v#{VERSION}"
5
5
 
@@ -1,6 +1,6 @@
1
1
  class Eye::Application
2
2
 
3
- attr_reader :groups, :name
3
+ attr_reader :groups, :name, :config
4
4
 
5
5
  def initialize(name, config = {})
6
6
  @groups = Eye::Utils::AliveArray.new
@@ -28,19 +28,12 @@ class Eye::Application
28
28
 
29
29
  def status_data(debug = false)
30
30
  h = { name: @name, type: :application, subtree: @groups.map{|gr| gr.status_data(debug) }}
31
- h.merge!(debug: debug_data) if debug
31
+ h[:debug] = debug_data if debug
32
32
  h
33
33
  end
34
34
 
35
35
  def status_data_short
36
- h = Hash.new
37
- @groups.each do |c|
38
- c.processes.each do |p|
39
- h[p.state] ||= 0
40
- h[p.state] += 1
41
- end
42
- end
43
- { name: @name, type: :application, states: h}
36
+ { name: @name, type: :application, subtree: @groups.map(&:status_data_short) }
44
37
  end
45
38
 
46
39
  def debug_data
@@ -8,6 +8,7 @@ class Eye::Checker
8
8
  autoload :FileSize, 'eye/checker/file_size'
9
9
  autoload :FileTouched,'eye/checker/file_touched'
10
10
  autoload :Socket, 'eye/checker/socket'
11
+ autoload :SslSocket, 'eye/checker/ssl_socket'
11
12
  autoload :Nop, 'eye/checker/nop'
12
13
  autoload :Runtime, 'eye/checker/runtime'
13
14
  autoload :Cputime, 'eye/checker/cputime'
@@ -17,7 +18,7 @@ class Eye::Checker
17
18
  TYPES = {:memory => 'Memory', :cpu => 'Cpu', :http => 'Http',
18
19
  :ctime => 'FileCTime', :fsize => 'FileSize', :file_touched => 'FileTouched',
19
20
  :socket => 'Socket', :nop => 'Nop', :runtime => 'Runtime', :cputime => 'Cputime',
20
- :children_count => "ChildrenCount", :children_memory => "ChildrenMemory" }
21
+ :children_count => "ChildrenCount", :children_memory => "ChildrenMemory", :ssl_socket => 'SslSocket' }
21
22
 
22
23
  attr_accessor :value, :values, :options, :pid, :type, :check_count, :process
23
24
 
@@ -14,13 +14,7 @@ class Eye::Checker::ChildrenCount < Eye::Checker::Measure
14
14
  super
15
15
  else
16
16
  pids = ordered_by_date_children_pids
17
-
18
- pids = if strategy == :kill_old
19
- pids[0...-below]
20
- else
21
- pids[below..-1]
22
- end
23
-
17
+ pids = (strategy == :kill_old) ? pids[0...-below] : pids[below..-1]
24
18
  kill_pids(pids)
25
19
  end
26
20
  end
@@ -9,7 +9,7 @@ class Eye::Checker::FileTouched < Eye::Checker
9
9
  end
10
10
 
11
11
  def get_value
12
- File.exists?(file)
12
+ File.exist?(file)
13
13
  end
14
14
 
15
15
  def good?(value)
@@ -21,10 +21,9 @@ class Eye::Checker::Http < Eye::Checker::Defer
21
21
  @uri = URI.parse(url)
22
22
  @proxy_uri = URI.parse(proxy_url) if proxy_url
23
23
  @kind = case kind
24
- when Fixnum then Net::HTTPResponse::CODE_TO_OBJ[kind]
24
+ when Fixnum then Net::HTTPResponse::CODE_TO_OBJ[kind.to_s]
25
25
  when String, Symbol then Net.const_get("HTTP#{kind.to_s.camelize}") rescue Net::HTTPSuccess
26
- else
27
- Net::HTTPSuccess
26
+ else Net::HTTPSuccess
28
27
  end
29
28
  @open_timeout = (open_timeout || 3).to_f
30
29
  @read_timeout = (read_timeout || timeout || 15).to_f
@@ -0,0 +1,28 @@
1
+ require 'openssl'
2
+
3
+ class Eye::Checker::SslSocket < Eye::Checker::Socket
4
+ param :ctx, Hash, nil, {ssl_version: :SSLv23, verify_mode: OpenSSL::SSL::VERIFY_NONE}
5
+
6
+ # other params inherits from socket check
7
+ #
8
+ # examples:
9
+ #
10
+ # check :ssl_socket, :addr => "tcp://127.0.0.1:443", :every => 5.seconds, :times => 1, :timeout => 1.second,
11
+ # :ctx => {ssl_version: :SSLv23, verify_mode: OpenSSL::SSL::VERIFY_NONE}
12
+ #
13
+ #
14
+ # ctx_params from http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
15
+
16
+ private
17
+
18
+ def open_socket
19
+ OpenSSL::SSL::SSLSocket.new(super, ctx_params).tap do |socket|
20
+ socket.sync_close = true
21
+ socket.connect
22
+ end
23
+ end
24
+
25
+ def ctx_params
26
+ @ctx_params ||= OpenSSL::SSL::SSLContext.new().tap { |c| c.set_params(ctx) }
27
+ end
28
+ end
@@ -24,13 +24,13 @@ class Eye::ChildProcess
24
24
  # scheduler
25
25
  include Eye::Process::Scheduler
26
26
 
27
- attr_reader :pid, :name, :full_name, :config, :watchers
27
+ attr_reader :pid, :name, :full_name, :config, :watchers, :parent
28
28
 
29
- def initialize(pid, config = {}, logger_prefix = nil, parent_pid = nil)
29
+ def initialize(pid, config = {}, logger_prefix = nil, parent = nil)
30
30
  raise 'Empty pid' unless pid
31
31
 
32
32
  @pid = pid
33
- @parent_pid = parent_pid
33
+ @parent = parent
34
34
  @config = prepare_config(config)
35
35
  @name = "child-#{pid}"
36
36
  @full_name = [logger_prefix, @name] * ':'
@@ -96,6 +96,6 @@ class Eye::ChildProcess
96
96
  end
97
97
 
98
98
  def prepare_command(command) # override
99
- super.gsub('{PARENT_PID}', @parent_pid.to_s)
99
+ super.gsub('{PARENT_PID}', @parent.pid.to_s)
100
100
  end
101
101
  end
@@ -98,18 +98,24 @@ class Eye::Cli < Thor
98
98
  ensure_stop_previous_server if res != :corrupted_data
99
99
 
100
100
  # remove pid_file
101
- File.delete(Eye::Local.pid_path) if File.exists?(Eye::Local.pid_path)
101
+ File.delete(Eye::Local.pid_path) if File.exist?(Eye::Local.pid_path)
102
102
 
103
103
  say "Quit ಠ╭╮ಠ", :yellow
104
104
  end
105
105
 
106
- [:start, :stop, :restart, :unmonitor, :monitor, :delete, :match].each do |_cmd|
107
- desc "#{_cmd} MASK[,...]", "#{_cmd} app,group or process"
108
- define_method(_cmd) do |*masks|
109
- send_command(_cmd, *masks)
106
+ [:start, :stop, :restart, :unmonitor, :monitor, :delete, :match].each do |command|
107
+ desc "#{command} MASK[,...]", "#{command} app,group or process"
108
+ define_method(command) do |*masks|
109
+ send_command(command, *masks)
110
110
  end
111
111
  end
112
112
 
113
+ desc "force_restart MASK[,...]", "restart by stop;start (not by restart_command)"
114
+ def force_restart(*masks)
115
+ send_command(:stop, *masks)
116
+ send_command(:start, *masks)
117
+ end
118
+
113
119
  desc "signal SIG MASK[,...]", "send signal to app,group or process"
114
120
  def signal(sig, *masks)
115
121
  send_command(:signal, sig, *masks)
@@ -189,7 +195,7 @@ private
189
195
 
190
196
  def log_trace(tag = '')
191
197
  log_file = cmd(:logger_dev)
192
- if log_file && File.exists?(log_file)
198
+ if log_file && File.exist?(log_file)
193
199
  Process.exec "tail -n 100 -f #{log_file} | grep '#{tag}'"
194
200
  else
195
201
  error! "log file not found #{log_file.inspect}"
@@ -27,10 +27,10 @@ private
27
27
  error!(res) unless res.is_a?(Hash)
28
28
  say_filename = (res.size > 1)
29
29
  error = false
30
- res.each do |filename, _res|
30
+ res.each do |filename, res2|
31
31
  say "#{filename}: ", nil, true if say_filename
32
- show_load_message(_res, opts)
33
- error = true if _res[:error]
32
+ show_load_message(res2, opts)
33
+ error = true if res2[:error]
34
34
  end
35
35
 
36
36
  exit(1) if error
@@ -54,10 +54,10 @@ private
54
54
  end
55
55
  end
56
56
 
57
- def send_command(_cmd, *args)
58
- res = cmd(_cmd, *args)
57
+ def send_command(command, *args)
58
+ res = cmd(command, *args)
59
59
  if res == :unknown_command
60
- error! "unknown command :#{_cmd}"
60
+ error! "unknown command :#{command}"
61
61
  elsif res == :corrupted_data
62
62
  error! 'something crazy wrong, check eye logs!'
63
63
  elsif res.is_a?(Hash)
@@ -65,9 +65,9 @@ private
65
65
  error! "Error: #{res[:error]}"
66
66
  elsif res = res[:result]
67
67
  if res == []
68
- error! "command :#{_cmd}, objects not found!"
68
+ error! "command :#{command}, objects not found!"
69
69
  else
70
- say "command :#{_cmd} sent to [#{res * ", "}]"
70
+ say "command :#{command} sent to [#{res * ', '}]"
71
71
  end
72
72
  end
73
73
  else
@@ -34,7 +34,7 @@ private
34
34
  off = level * 2
35
35
  off_str = ' ' * off
36
36
 
37
- short_state = (data[:type] == :application && data[:states])
37
+ short_state = ((data[:type] == :application || data[:type] == :group) && data[:states])
38
38
  is_text = data[:state] || data[:states]
39
39
 
40
40
  name = (data[:type] == :application && !is_text) ? "\033[1m#{data[:name]}\033[0m" : data[:name].to_s
@@ -105,13 +105,7 @@ private
105
105
 
106
106
  def render_history(data)
107
107
  error!("unexpected server response #{data.inspect}") unless data.is_a?(Hash)
108
-
109
- res = []
110
- data.each do |name, data|
111
- res << detail_process_info(name, data)
112
- end
113
-
114
- res * "\n"
108
+ data.map { |name, history| detail_process_info(name, history) }.join("\n")
115
109
  end
116
110
 
117
111
  def detail_process_info(name, history)
@@ -9,7 +9,7 @@ private
9
9
 
10
10
  def loader_path
11
11
  filename = File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. .. bin loader_eye]))
12
- File.exists?(filename) ? filename : nil
12
+ File.exist?(filename) ? filename : nil
13
13
  end
14
14
 
15
15
  def ruby_path
@@ -62,7 +62,8 @@ private
62
62
  error! 'server has not started in 15 seconds, something is very wrong'
63
63
  end
64
64
 
65
- configs.unshift(Eye::Local.eyeconfig) if File.exists?(Eye::Local.eyeconfig)
65
+ configs.unshift(Eye::Local.global_eyeconfig) if File.exist?(Eye::Local.global_eyeconfig)
66
+ configs.unshift(Eye::Local.eyeconfig) if File.exist?(Eye::Local.eyeconfig)
66
67
  configs << Eye::Local.eyefile if Eye::Local.local_runner
67
68
 
68
69
  say 'Eye started! ㋡', :green
@@ -13,10 +13,7 @@ class Eye::Client
13
13
  end
14
14
 
15
15
  def attempt_command(pack)
16
- Timeout.timeout(Eye::Local.client_timeout) do
17
- return send_request(pack)
18
- end
19
-
16
+ Timeout.timeout(Eye::Local.client_timeout) { send_request(pack) }
20
17
  rescue Timeout::Error, EOFError
21
18
  :timeouted
22
19
  end
@@ -25,7 +22,7 @@ class Eye::Client
25
22
  UNIXSocket.open(@socket_path) do |socket|
26
23
  socket.write(pack)
27
24
  data = socket.read
28
- res = Marshal.load(data) rescue :corrupted_data
25
+ Marshal.load(data) rescue :corrupted_data
29
26
  end
30
27
  end
31
28
 
@@ -20,11 +20,18 @@ class Eye::Config
20
20
  end
21
21
 
22
22
  def to_h
23
- {:settings => @settings, :applications => @applications}
23
+ h = {}
24
+ h[:settings] = @settings
25
+ if Eye.respond_to?(:parsed_default_app)
26
+ d = Eye.parsed_default_app
27
+ h[:defaults] = d ? d.config : {}
28
+ end
29
+ h[:applications] = @applications
30
+ h
24
31
  end
25
32
 
26
33
  # raise an error if config wrong
27
- def validate!(localize = true)
34
+ def validate!(validate_apps = [])
28
35
  all_processes = processes
29
36
 
30
37
  # Check blank pid_files
@@ -58,13 +65,36 @@ class Eye::Config
58
65
 
59
66
  # validate processes with their own validate
60
67
  all_processes.each do |process_cfg|
61
- Eye::Process.validate process_cfg, localize
68
+ Eye::Process.validate process_cfg, validate_apps.include?(process_cfg[:application])
62
69
  end
63
70
 
64
71
  # just to be sure ENV was not removed
65
72
  ENV[''] rescue raise Eye::Dsl::Error.new("ENV is not a hash '#{ENV.inspect}'")
66
73
  end
67
74
 
75
+ def transform!
76
+ all_processes = processes
77
+
78
+ # transform syslog option
79
+ all_processes.each do |process|
80
+ out = process[:stdout] && process[:stdout].start_with?(':syslog')
81
+ err = process[:stderr] && process[:stderr].start_with?(':syslog')
82
+ if err || out
83
+ redir = err ? '2>&1' : ''
84
+ process[:stdout] = nil if out
85
+ process[:stderr] = nil if err
86
+
87
+ escaped_start_command = process[:start_command].to_s.gsub(%{"}, %{\\"})
88
+
89
+ names = [process[:application], process[:group] == '__default__' ? nil : process[:group], process[:name]].compact
90
+ logger = "logger -t \"#{names.join(':')}\""
91
+
92
+ process[:start_command] = %{sh -c "#{escaped_start_command} #{redir} | #{logger}"}
93
+ process[:use_leaf_child] = true if process[:daemonize]
94
+ end
95
+ end
96
+ end
97
+
68
98
  def processes
69
99
  applications.values.map{|e| (e[:groups] || {}).values.map{|c| (c[:processes] || {}).values} }.flatten
70
100
  end
@@ -1,7 +1,6 @@
1
1
  require 'celluloid'
2
2
  require 'yaml'
3
3
 
4
- require_relative 'utils/celluloid_klass'
5
4
  require_relative 'utils/pmap'
6
5
 
7
6
  require_relative 'utils/leak_19'
@@ -9,7 +9,7 @@ module Eye::Controller::Load
9
9
  end
10
10
 
11
11
  def load(*args)
12
- h = args.extract_options!
12
+ args.extract_options!
13
13
  obj_strs = args.flatten
14
14
  info "=> loading: #{obj_strs}"
15
15
 
@@ -49,7 +49,7 @@ private
49
49
  error bt.join("\n")
50
50
 
51
51
  res = { :error => true, :message => ex.message }
52
- res.merge!(:backtrace => bt) if bt.present?
52
+ res[:backtrace] = bt if bt.present?
53
53
  res
54
54
  end
55
55
 
@@ -58,12 +58,7 @@ private
58
58
  return res if obj_strs.empty?
59
59
 
60
60
  obj_strs.each do |filename|
61
- mask = if File.directory?(filename)
62
- File.join filename, '{*.eye}'
63
- else
64
- filename
65
- end
66
-
61
+ mask = File.directory?(filename) ? File.join(filename, '{*.eye}') : filename
67
62
  debug { "loading: globbing mask #{mask}" }
68
63
 
69
64
  sub = []
@@ -83,7 +78,7 @@ private
83
78
  debug { "parsing: #{filename}" }
84
79
 
85
80
  cfg = Eye::Dsl.parse(nil, filename)
86
- @current_config.merge(cfg).validate!(false) # just validate summary config here
81
+ @current_config.merge(cfg).validate! # just validate summary config here
87
82
  Eye.parsed_config = nil # remove link on config, for better gc
88
83
  cfg
89
84
  end
@@ -92,7 +87,7 @@ private
92
87
  def load_config(filename, config)
93
88
  info "loading: #{filename}"
94
89
  new_cfg = @current_config.merge(config)
95
- new_cfg.validate!
90
+ new_cfg.validate!(config.application_names)
96
91
 
97
92
  load_options(new_cfg.settings)
98
93
  create_objects(new_cfg.applications, config.application_names)
@@ -2,7 +2,7 @@ module Eye::Controller::Status
2
2
 
3
3
  def debug_data(*args)
4
4
  h = args.extract_options!
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
5
+ actors = Celluloid::Actor.all.map{|actor| actor.wrapped_object.class.to_s }.group_by{|a| a}.map{|k,v| [k, v.size]}.sort_by{ |a| a[1] }.reverse
6
6
 
7
7
  res = {
8
8
  :about => Eye::ABOUT,
@@ -27,7 +27,6 @@ class Eye::Dsl
27
27
  def parse(content = nil, filename = nil)
28
28
  Eye.parsed_config = Eye::Config.new
29
29
  Eye.parsed_filename = filename
30
- Eye.parsed_default_app = nil
31
30
 
32
31
  content = File.read(filename) if content.blank?
33
32
 
@@ -35,7 +34,8 @@ class Eye::Dsl
35
34
  Kernel.eval(content, Eye::BINDING, filename.to_s)
36
35
  end
37
36
 
38
- Eye.parsed_config.validate!(false)
37
+ Eye.parsed_config.transform!
38
+ Eye.parsed_config.validate!
39
39
  Eye.parsed_config
40
40
  end
41
41
 
@@ -12,6 +12,13 @@ class Eye::Dsl::ConfigOpts < Eye::Dsl::PureOpts
12
12
  end
13
13
  alias logger= logger
14
14
 
15
+ def syslog(name = 'eye', *args)
16
+ require 'syslog/logger'
17
+ Syslog::Logger.new(name, *args)
18
+ rescue LoadError
19
+ raise Eye::Dsl::Error, "logger syslog requires Ruby >= 2.0"
20
+ end
21
+
15
22
  # ==== contact options ==============================
16
23
  def self.add_notify(type)
17
24
  create_options_methods([type], Hash)
@@ -23,7 +30,7 @@ class Eye::Dsl::ConfigOpts < Eye::Dsl::PureOpts
23
30
  end
24
31
  end
25
32
 
26
- Eye::Notify::TYPES.keys.each { |name| add_notify(name) }
33
+ Eye::Notify::TYPES.each_key { |name| add_notify(name) }
27
34
 
28
35
  def contact(contact_name, contact_type, contact, contact_opts = {})
29
36
  raise Eye::Dsl::Error, "unknown contact_type #{contact_type}" unless Eye::Notify::TYPES[contact_type]
@@ -19,7 +19,7 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
19
19
  def initialize(name = nil, parent = nil)
20
20
  super(name, parent)
21
21
 
22
- @config[:application] = parent.name if parent.is_a?(Eye::Dsl::ApplicationOpts)
22
+ @config[:application] = parent.name if parent.is_a?(Eye::Dsl::ApplicationOpts) && parent.name != '__default__'
23
23
  @config[:group] = parent.name if parent.is_a?(Eye::Dsl::GroupOpts)
24
24
 
25
25
  # hack for full name
@@ -30,7 +30,7 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
30
30
  nac = Eye::Checker.name_and_class(type.to_sym)
31
31
  raise Eye::Dsl::Error, "unknown checker type #{type}" unless nac
32
32
 
33
- opts.merge!(:type => nac[:type])
33
+ opts[:type] = nac[:type]
34
34
  Eye::Checker.validate!(opts)
35
35
 
36
36
  @config[:checks] ||= {}
@@ -41,7 +41,7 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
41
41
  nac = Eye::Trigger.name_and_class(type.to_sym)
42
42
  raise Eye::Dsl::Error, "unknown trigger type #{type}" unless nac
43
43
 
44
- opts.merge!(:type => nac[:type])
44
+ opts[:type] = nac[:type]
45
45
  Eye::Trigger.validate!(opts)
46
46
 
47
47
  @config[:triggers] ||= {}
@@ -184,7 +184,7 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
184
184
  def load_env(filename = '~/.env', raise_when_no_file = true)
185
185
  fnames = [File.expand_path(filename, @config[:working_dir]),
186
186
  File.expand_path(filename)].uniq
187
- filenames = fnames.select { |f| File.exists?(f) }
187
+ filenames = fnames.select { |f| File.exist?(f) }
188
188
 
189
189
  if filenames.size < 1
190
190
  unless raise_when_no_file
@@ -205,6 +205,10 @@ class Eye::Dsl::Opts < Eye::Dsl::PureOpts
205
205
  @config[:skip_group_actions][act] = val
206
206
  end
207
207
 
208
+ def syslog
209
+ ':syslog'
210
+ end
211
+
208
212
  private
209
213
 
210
214
  def validate_signals(signals = nil)
@@ -82,7 +82,7 @@ class Eye::Dsl::PureOpts
82
82
  def use(proc, *args)
83
83
  if proc.is_a?(String)
84
84
  self.class.with_parsed_file(proc) do |path|
85
- if File.exists?(path)
85
+ if File.exist?(path)
86
86
  Eye::Dsl.debug { "=> load #{path}" }
87
87
  self.instance_eval(File.read(path))
88
88
  Eye::Dsl.debug { "<= load #{path}" }
@@ -101,8 +101,6 @@ class Eye::Dsl::PureOpts
101
101
 
102
102
  def nop(*args, &block); end
103
103
 
104
- private
105
-
106
104
  def self.with_parsed_file(file_name)
107
105
  saved_parsed_filename = Eye.parsed_filename
108
106
 
@@ -20,13 +20,13 @@ module Eye::Dsl::Validation
20
20
  def defaults; @defaults ||= {}; end
21
21
  def variants; @variants ||= {}; end
22
22
 
23
- def param(param, types = [], should_be = false, default = nil, _variants = nil)
23
+ def param(param, types = [], should_be = false, default = nil, variants = nil)
24
24
  param = param.to_sym
25
25
 
26
- validates[param] = types
27
- should_bes << param if should_be
26
+ self.validates[param] = types
27
+ self.should_bes << param if should_be
28
28
  param_default(param, default)
29
- variants[param] = _variants
29
+ self.variants[param] = variants
30
30
 
31
31
  return if param == :do
32
32
 
@@ -49,7 +49,7 @@ class Eye::Group
49
49
 
50
50
  h = { name: name, type: :group, subtree: plist }
51
51
 
52
- h.merge!(debug: debug_data) if debug
52
+ h[:debug] = debug_data if debug
53
53
 
54
54
  # show current chain
55
55
  if current_scheduled_command
@@ -67,6 +67,15 @@ class Eye::Group
67
67
  h
68
68
  end
69
69
 
70
+ def status_data_short
71
+ h = Hash.new
72
+ @processes.each do |p|
73
+ h[p.state] ||= 0
74
+ h[p.state] += 1
75
+ end
76
+ { name: (@name == '__default__' ? 'default' : @name), type: :group, states: h }
77
+ end
78
+
70
79
  def debug_data
71
80
  {:queue => scheduler_actions_list, :chain => chain_status}
72
81
  end
@@ -76,9 +85,9 @@ class Eye::Group
76
85
 
77
86
  case command
78
87
  when :delete
79
- delete *args
88
+ delete(*args)
80
89
  when :break_chain
81
- break_chain *args
90
+ break_chain(*args)
82
91
  else
83
92
  schedule command, *args, Eye::Reason::User.new(command)
84
93
  end
@@ -12,16 +12,14 @@ module Eye::Local
12
12
  end
13
13
  end
14
14
 
15
- def dir=(d)
16
- @dir = d
15
+ attr_writer :dir, :client_timeout, :host
16
+
17
+ def global_eyeconfig
18
+ '/etc/eye.conf'
17
19
  end
18
20
 
19
21
  def eyeconfig
20
- if root?
21
- '/etc/eye.conf'
22
- else
23
- File.expand_path(File.join(home, '.eyeconfig'))
24
- end
22
+ File.expand_path(File.join(home, '.eyeconfig'))
25
23
  end
26
24
 
27
25
  def root?
@@ -62,10 +60,6 @@ module Eye::Local
62
60
  @client_timeout ||= default_client_timeout
63
61
  end
64
62
 
65
- def client_timeout=(cl)
66
- @client_timeout = cl
67
- end
68
-
69
63
  def supported_setsid?
70
64
  RUBY_VERSION >= '2.0'
71
65
  end
@@ -77,10 +71,6 @@ module Eye::Local
77
71
  end
78
72
  end
79
73
 
80
- def host=(hostname)
81
- @host = hostname
82
- end
83
-
84
74
  def eyefile
85
75
  @eyefile ||= find_eyefile('.')
86
76
  end
@@ -108,12 +108,9 @@ class Eye::Notify
108
108
  end
109
109
  end
110
110
 
111
- private
112
-
113
111
  %w{at host message name full_name pid level}.each do |name|
114
112
  define_method("msg_#{name}") do
115
113
  @message_h[name.to_sym]
116
114
  end
117
115
  end
118
-
119
116
  end
@@ -32,7 +32,7 @@ module Eye::Process::Children
32
32
  if new_children.present?
33
33
  new_children.each do |child_pid|
34
34
  cfg = self[:monitor_children].try :update, :notify => self[:notify]
35
- self.children[child_pid] = Eye::ChildProcess.new(child_pid, cfg, logger.prefix, self.pid)
35
+ self.children[child_pid] = Eye::ChildProcess.new(child_pid, cfg, logger.prefix, current_actor)
36
36
  end
37
37
  end
38
38
 
@@ -170,7 +170,7 @@ private
170
170
 
171
171
  def daemonize_process
172
172
  time_before = Time.now
173
- res = Eye::System.daemonize(self[:start_command], config)
173
+ res = daemonize(self[:start_command], config)
174
174
  start_time = Time.now - time_before
175
175
 
176
176
  info "daemonizing: `#{self[:start_command]}` with start_grace: #{self[:start_grace].to_f}s, env: '#{environment_string}', <#{res[:pid]}> (in #{self[:working_dir]})"
@@ -43,8 +43,8 @@ module Eye::Process::Data
43
43
  state_reason: @states_history.last_reason.to_s )
44
44
  end
45
45
 
46
- h.merge!(debug: debug_data) if debug
47
- h.merge!(current_command: current_scheduled_command) if current_scheduled_command
46
+ h[:debug] = debug_data if debug
47
+ h[:current_command] = current_scheduled_command if current_scheduled_command
48
48
 
49
49
  h
50
50
  end
@@ -53,6 +53,10 @@ module Eye::Process::Scheduler
53
53
  info "<= #{command}"
54
54
 
55
55
  schedule_history.push(command, reason, @last_scheduled_at.to_i)
56
+
57
+ if parent = self.try(:parent)
58
+ parent.schedule_history.push("#{command}_child", reason, @last_scheduled_at.to_i)
59
+ end
56
60
  end
57
61
 
58
62
  def scheduler_actions_list
@@ -3,7 +3,7 @@ require 'timeout'
3
3
  module Eye::Process::System
4
4
 
5
5
  def load_pid_from_file
6
- res = if File.exists?(self[:pid_file_ex])
6
+ res = if File.exist?(self[:pid_file_ex])
7
7
  _pid = File.read(self[:pid_file_ex]).to_i
8
8
  _pid > 0 ? _pid : nil
9
9
  end
@@ -73,19 +73,25 @@ module Eye::Process::System
73
73
  end
74
74
 
75
75
  def execute(cmd, cfg = {})
76
- defer{ Eye::System::execute cmd, cfg }
76
+ defer { Eye::System::execute cmd, cfg }.tap do |res|
77
+ notify(:debug, "Bad exit status of command #{cmd.inspect}(#{res[:exitstatus].inspect})") if res[:exitstatus] != 0
78
+ end
79
+ end
80
+
81
+ def daemonize(cmd, cfg = {})
82
+ Eye::System.daemonize(cmd, cfg)
77
83
  end
78
84
 
79
85
  def execute_sync(cmd, opts = {:timeout => 1.second})
80
- res = execute cmd, self.config.merge(opts)
81
- info "execute_sync `#{cmd}` with res: #{res}"
82
- res
86
+ execute(cmd, self.config.merge(opts)).tap do |res|
87
+ info "execute_sync `#{cmd}` with res: #{res}"
88
+ end
83
89
  end
84
90
 
85
91
  def execute_async(cmd, opts = {})
86
- res = Eye::System.daemonize(cmd, self.config.merge(opts))
87
- info "execute_async `#{cmd}` with res: #{res}"
88
- res
92
+ daemonize(cmd, self.config.merge(opts)).tap do |res|
93
+ info "execute_async `#{cmd}` with res: #{res}"
94
+ end
89
95
  end
90
96
 
91
97
  def failsafe_load_pid
@@ -36,10 +36,25 @@ class Eye::SystemResources
36
36
 
37
37
  # last child in a children tree
38
38
  def leaf_child(pid)
39
+ if dc = deep_children(pid)
40
+ dc.detect do |child|
41
+ args = Eye::Sigar.proc_args(child)[0] rescue ''
42
+ !args.start_with?('logger') && child != pid
43
+ end
44
+ end
45
+ end
46
+
47
+ def deep_children(pid)
48
+ Array(pid_or_children(pid)).flatten.sort_by { |pid| -pid }
49
+ end
50
+
51
+ def pid_or_children(pid)
39
52
  c = children(pid)
40
- return if c.empty?
41
- c += children(c.shift) while c.size > 1
42
- c[0]
53
+ if !c || c.empty?
54
+ pid
55
+ else
56
+ c.map { |ppid| pid_or_children(ppid) }
57
+ end
43
58
  end
44
59
 
45
60
  def resources(pid)
@@ -33,7 +33,7 @@ module Eye::Utils
33
33
  time = Time.at(unix_time.to_i)
34
34
  d1 = time.to_date
35
35
  d2 = Time.now.to_date
36
- time.strftime (d1 == d2) ? D1 : D2
36
+ time.strftime((d1 == d2) ? D1 : D2)
37
37
  end
38
38
 
39
39
  DF = '%d %b %H:%M'
@@ -1,7 +1,6 @@
1
1
  module Enumerable
2
2
  # Simple parallel map using Celluloid::Futures
3
3
  def pmap(&block)
4
- futures = map { |elem| Celluloid::Future.new(elem, &block) }
5
- futures.map { |future| future.value }
4
+ map { |elem| Celluloid::Future.new(elem, &block) }.map(&:value)
6
5
  end
7
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eye
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.pre
4
+ version: '0.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Makarchev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-10 00:00:00.000000000 Z
11
+ date: 2015-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.7.2
75
+ version: 0.7.3
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.7.2
82
+ version: 0.7.3
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -326,6 +326,7 @@ files:
326
326
  - examples/rbenv.eye
327
327
  - examples/sidekiq.eye
328
328
  - examples/stress_test.eye
329
+ - examples/syslog.eye
329
330
  - examples/test.eye
330
331
  - examples/thin-farm.eye
331
332
  - examples/triggers.eye
@@ -346,6 +347,7 @@ files:
346
347
  - lib/eye/checker/nop.rb
347
348
  - lib/eye/checker/runtime.rb
348
349
  - lib/eye/checker/socket.rb
350
+ - lib/eye/checker/ssl_socket.rb
349
351
  - lib/eye/child_process.rb
350
352
  - lib/eye/cli.rb
351
353
  - lib/eye/cli/commands.rb
@@ -412,7 +414,6 @@ files:
412
414
  - lib/eye/utils.rb
413
415
  - lib/eye/utils/alive_array.rb
414
416
  - lib/eye/utils/celluloid_chain.rb
415
- - lib/eye/utils/celluloid_klass.rb
416
417
  - lib/eye/utils/leak_19.rb
417
418
  - lib/eye/utils/mini_active_support.rb
418
419
  - lib/eye/utils/pmap.rb
@@ -437,7 +438,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
437
438
  version: 1.3.6
438
439
  requirements: []
439
440
  rubyforge_project:
440
- rubygems_version: 2.4.5
441
+ rubygems_version: 2.4.7
441
442
  signing_key:
442
443
  specification_version: 4
443
444
  summary: Process monitoring tool. Inspired from Bluepill and God. Requires Ruby(MRI)
@@ -1,5 +0,0 @@
1
- class Celluloid::SyncProxy
2
- def __klass__
3
- @klass
4
- end
5
- end