reel-eye 0.3.2 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -1
  4. data/.travis.yml +3 -1
  5. data/CHANGES.md +11 -2
  6. data/Gemfile +1 -0
  7. data/README.md +18 -14
  8. data/Rakefile +10 -3
  9. data/bin/eye +41 -27
  10. data/examples/process_thin.rb +1 -1
  11. data/examples/processes/em.rb +2 -2
  12. data/examples/processes/forking.rb +2 -2
  13. data/examples/processes/sample.rb +5 -5
  14. data/examples/rbenv.eye +1 -1
  15. data/examples/sidekiq.eye +2 -2
  16. data/examples/test.eye +10 -6
  17. data/examples/thin-farm.eye +1 -1
  18. data/examples/unicorn.eye +1 -1
  19. data/eye.gemspec +13 -7
  20. data/lib/eye.rb +6 -6
  21. data/lib/eye/application.rb +9 -6
  22. data/lib/eye/checker.rb +51 -21
  23. data/lib/eye/checker/file_size.rb +1 -1
  24. data/lib/eye/checker/http.rb +3 -3
  25. data/lib/eye/checker/memory.rb +1 -1
  26. data/lib/eye/checker/socket.rb +6 -6
  27. data/lib/eye/child_process.rb +7 -11
  28. data/lib/eye/client.rb +6 -6
  29. data/lib/eye/config.rb +2 -2
  30. data/lib/eye/controller.rb +13 -8
  31. data/lib/eye/controller/commands.rb +9 -10
  32. data/lib/eye/controller/helpers.rb +1 -0
  33. data/lib/eye/controller/load.rb +11 -7
  34. data/lib/eye/controller/options.rb +1 -1
  35. data/lib/eye/controller/send_command.rb +44 -19
  36. data/lib/eye/controller/show_history.rb +8 -7
  37. data/lib/eye/controller/status.rb +39 -26
  38. data/lib/eye/dsl.rb +3 -3
  39. data/lib/eye/dsl/application_opts.rb +4 -4
  40. data/lib/eye/dsl/config_opts.rb +4 -4
  41. data/lib/eye/dsl/helpers.rb +2 -2
  42. data/lib/eye/dsl/main.rb +2 -2
  43. data/lib/eye/dsl/opts.rb +19 -14
  44. data/lib/eye/dsl/process_opts.rb +1 -1
  45. data/lib/eye/dsl/pure_opts.rb +2 -2
  46. data/lib/eye/dsl/validation.rb +7 -5
  47. data/lib/eye/group.rb +17 -11
  48. data/lib/eye/group/chain.rb +3 -3
  49. data/lib/eye/http.rb +1 -1
  50. data/lib/eye/http/router.rb +2 -2
  51. data/lib/eye/loader.rb +8 -7
  52. data/lib/eye/logger.rb +14 -5
  53. data/lib/eye/notify.rb +13 -7
  54. data/lib/eye/notify/jabber.rb +2 -2
  55. data/lib/eye/notify/mail.rb +2 -2
  56. data/lib/eye/process.rb +10 -13
  57. data/lib/eye/process/child.rb +1 -1
  58. data/lib/eye/process/commands.rb +34 -32
  59. data/lib/eye/process/config.rb +17 -12
  60. data/lib/eye/process/controller.rb +3 -6
  61. data/lib/eye/process/data.rb +16 -5
  62. data/lib/eye/process/monitor.rb +12 -5
  63. data/lib/eye/process/notify.rb +1 -1
  64. data/lib/eye/process/scheduler.rb +3 -3
  65. data/lib/eye/process/states.rb +10 -13
  66. data/lib/eye/process/states_history.rb +3 -3
  67. data/lib/eye/process/system.rb +17 -21
  68. data/lib/eye/process/trigger.rb +11 -30
  69. data/lib/eye/process/watchers.rb +9 -9
  70. data/lib/eye/server.rb +14 -6
  71. data/lib/eye/settings.rb +4 -4
  72. data/lib/eye/system.rb +10 -7
  73. data/lib/eye/system_resources.rb +4 -4
  74. data/lib/eye/trigger.rb +58 -21
  75. data/lib/eye/trigger/flapping.rb +24 -4
  76. data/lib/eye/trigger/state.rb +28 -0
  77. data/lib/eye/utils/alive_array.rb +1 -1
  78. data/lib/eye/utils/celluloid_klass.rb +5 -0
  79. data/lib/eye/utils/pmap.rb +7 -0
  80. data/lib/eye/utils/tail.rb +1 -1
  81. metadata +252 -271
  82. data/lib/eye/utils/leak_19.rb +0 -7
data/examples/test.eye CHANGED
@@ -1,5 +1,5 @@
1
1
  # load submodules, here just for example
2
- Eye.load("./eye/*.rb")
2
+ Eye.load("./eye/*.rb")
3
3
 
4
4
  # Eye self-configuration section
5
5
  Eye.config do
@@ -24,6 +24,10 @@ Eye.application "test" do
24
24
  process :sample1 do
25
25
  pid_file "1.pid" # pid_path will be expanded with the working_dir
26
26
  start_command "ruby ./sample.rb"
27
+
28
+ # when no stop_command or stop_signals, default stop is [:TERM, 0.5, :KILL]
29
+ # default `restart` command is `stop; start`
30
+
27
31
  daemonize true
28
32
  stdall "sample1.log"
29
33
 
@@ -49,13 +53,13 @@ Eye.application "test" do
49
53
 
50
54
  start_timeout 5.seconds
51
55
  stop_grace 5.seconds
52
-
56
+
53
57
  monitor_children do
54
58
  restart_command "kill -2 {PID}" # for this child process
55
59
  checks :memory, :below => 300.megabytes, :times => 3
56
60
  end
57
61
  end
58
-
62
+
59
63
  # eventmachine process, daemonized with eye
60
64
  process :event_machine do |p|
61
65
  pid_file 'em.pid'
@@ -63,8 +67,8 @@ Eye.application "test" do
63
67
  stdout 'em.log'
64
68
  daemonize true
65
69
  stop_signals [:QUIT, 2.seconds, :KILL]
66
-
67
- checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
70
+
71
+ checks :socket, :addr => "tcp://127.0.0.1:33221", :every => 10.seconds, :times => 2,
68
72
  :timeout => 1.second, :send_data => "ping", :expect_data => /pong/
69
73
  end
70
74
 
@@ -74,7 +78,7 @@ Eye.application "test" do
74
78
  start_command "bundle exec thin start -R thin.ru -p 33233 -d -l thin.log -P thin.pid"
75
79
  stop_signals [:QUIT, 2.seconds, :TERM, 1.seconds, :KILL]
76
80
 
77
- checks :http, :url => "http://127.0.0.1:33233/hello", :pattern => /World/, :every => 5.seconds,
81
+ checks :http, :url => "http://127.0.0.1:33233/hello", :pattern => /World/, :every => 5.seconds,
78
82
  :times => [2, 3], :timeout => 1.second
79
83
  end
80
84
 
@@ -11,7 +11,7 @@ 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,
14
+ stop_on_delete true # this option means, when we change pids and load config,
15
15
  # deleted processes will be stops
16
16
 
17
17
  triggers :flapping, :times => 10, :within => 1.minute
data/examples/unicorn.eye CHANGED
@@ -6,7 +6,7 @@ RAILS_ENV = 'production'
6
6
  Eye.application "rails_unicorn" do
7
7
  env "RAILS_ENV" => RAILS_ENV, "PATH" => "#{File.dirname(RUBY)}:#{ENV['PATH']}"
8
8
  working_dir File.expand_path(File.join(File.dirname(__FILE__), %w[ processes ]))
9
-
9
+
10
10
  process("unicorn") do
11
11
  pid_file "tmp/pids/unicorn.pid"
12
12
  start_command "#{RUBY} ./bin/unicorn -Dc ./config/unicorn.rb -E #{RAILS_ENV}"
data/eye.gemspec CHANGED
@@ -17,19 +17,24 @@ Gem::Specification.new do |gem|
17
17
  gem.license = "MIT"
18
18
 
19
19
  gem.required_ruby_version = '>= 1.9.2' # because of celluloid
20
- gem.required_rubygems_version = '>= 1.3.6'
21
-
22
- gem.add_dependency 'celluloid', '~> 0.13.0'
23
- gem.add_dependency 'celluloid-io', '~> 0.13.0'
24
- gem.add_dependency 'state_machine', '< 1.2'
25
- gem.add_dependency 'activesupport', '~> 3.2.0'
20
+ gem.required_rubygems_version = '>= 1.3.6'
21
+
22
+ gem.add_dependency 'celluloid', '~> 0.14.0'
23
+ gem.add_dependency 'celluloid-io', '~> 0.14.0'
24
+ gem.add_dependency 'state_machine'
26
25
  gem.add_dependency 'thor'
27
26
 
28
27
  gem.add_dependency 'reel', '~> 0.4.0.pre'
29
28
  gem.add_dependency 'cuba'
30
29
 
30
+ if RUBY_VERSION == '1.9.2'
31
+ gem.add_dependency 'activesupport', '>= 3', '< 4.0'
32
+ else
33
+ gem.add_dependency 'activesupport', '>= 3'
34
+ end
35
+
31
36
  gem.add_development_dependency 'rake'
32
- gem.add_development_dependency 'rspec'
37
+ gem.add_development_dependency 'rspec', '< 2.14'
33
38
  gem.add_development_dependency 'rr'
34
39
  gem.add_development_dependency 'ruby-graphviz'
35
40
  gem.add_development_dependency 'forking'
@@ -39,4 +44,5 @@ Gem::Specification.new do |gem|
39
44
  gem.add_development_dependency 'thin'
40
45
  gem.add_development_dependency 'xmpp4r'
41
46
  gem.add_development_dependency 'coveralls'
47
+ gem.add_development_dependency 'parallel_tests'
42
48
  end
data/lib/eye.rb CHANGED
@@ -1,5 +1,5 @@
1
- module Eye
2
- VERSION = "0.3.2"
1
+ module Eye
2
+ VERSION = "0.4"
3
3
  ABOUT = "ReelEye v#{VERSION} (c) 2012-2013 @kostya"
4
4
  PROCLINE = "reel-eye monitoring v#{VERSION}"
5
5
 
@@ -8,19 +8,19 @@ module Eye
8
8
  autoload :Server, 'eye/server'
9
9
  autoload :Logger, 'eye/logger'
10
10
  autoload :System, 'eye/system'
11
- autoload :SystemResources,'eye/system_resources'
11
+ autoload :SystemResources,'eye/system_resources'
12
12
  autoload :Checker, 'eye/checker'
13
13
  autoload :Trigger, 'eye/trigger'
14
14
  autoload :Group, 'eye/group'
15
- autoload :Dsl, 'eye/dsl'
16
- autoload :Application, 'eye/application'
15
+ autoload :Dsl, 'eye/dsl'
16
+ autoload :Application, 'eye/application'
17
17
  autoload :Settings, 'eye/settings'
18
18
  autoload :Client, 'eye/client'
19
19
  autoload :Utils, 'eye/utils'
20
20
  autoload :Notify, 'eye/notify'
21
21
  autoload :Config, 'eye/config'
22
22
  autoload :Reason, 'eye/reason'
23
-
23
+
24
24
  autoload :Controller, 'eye/controller'
25
25
  autoload :Control, 'eye/control'
26
26
 
@@ -2,16 +2,17 @@ class Eye::Application
2
2
 
3
3
  attr_reader :groups, :name
4
4
 
5
- include Eye::Logger::Helpers
6
-
7
5
  def initialize(name, config = {})
8
6
  @groups = Eye::Utils::AliveArray.new
9
7
  @name = name
10
- @logger = Eye::Logger.new(full_name)
11
8
  @config = config
12
9
  debug 'created'
13
10
  end
14
11
 
12
+ def logger_tag
13
+ full_name
14
+ end
15
+
15
16
  def full_name
16
17
  @name
17
18
  end
@@ -37,7 +38,7 @@ class Eye::Application
37
38
 
38
39
  def status_data_short
39
40
  h = Hash.new 0
40
- @groups.each do |c|
41
+ @groups.each do |c|
41
42
  c.processes.each do |p|
42
43
  h[p.state] += 1
43
44
  end
@@ -51,7 +52,7 @@ class Eye::Application
51
52
 
52
53
  def send_command(command, *args)
53
54
  info "send_command #{command}"
54
-
55
+
55
56
  @groups.each do |group|
56
57
  group.send_command(command, *args)
57
58
  end
@@ -68,7 +69,9 @@ class Eye::Application
68
69
  end
69
70
 
70
71
  def processes
71
- Eye::Utils::AliveArray.new(@groups.map{|gr| gr.processes.to_a }.flatten)
72
+ out = []
73
+ @groups.each{|gr| out += gr.processes.to_a }
74
+ Eye::Utils::AliveArray.new(out)
72
75
  end
73
76
 
74
77
  end
data/lib/eye/checker.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  class Eye::Checker
2
- include Eye::Logger::Helpers
3
2
 
4
3
  autoload :Memory, 'eye/checker/memory'
5
4
  autoload :Cpu, 'eye/checker/cpu'
@@ -8,10 +7,15 @@ class Eye::Checker
8
7
  autoload :FileSize, 'eye/checker/file_size'
9
8
  autoload :Socket, 'eye/checker/socket'
10
9
 
11
- TYPES = {:memory => "Memory", :cpu => "Cpu", :http => "Http",
10
+ TYPES = {:memory => "Memory", :cpu => "Cpu", :http => "Http",
12
11
  :ctime => "FileCTime", :fsize => "FileSize", :socket => "Socket"}
13
12
 
14
- attr_accessor :value, :values, :options, :pid, :type, :check_count
13
+ attr_accessor :value, :values, :options, :pid, :type, :check_count, :process
14
+
15
+ extend Eye::Dsl::Validation
16
+ param :every, [Fixnum, Float], false, 5
17
+ param :times, [Fixnum, Array], nil, 1
18
+ param :fire, Symbol, nil, nil, [:stop, :restart, :unmonitor, :nothing]
15
19
 
16
20
  def self.name_and_class(type)
17
21
  type = type.to_sym
@@ -20,7 +24,7 @@ class Eye::Checker
20
24
  if type =~ /\A(.*?)_?[0-9]+\z/
21
25
  ctype = $1.to_sym
22
26
  return {:name => type, :type => ctype} if TYPES[ctype]
23
- end
27
+ end
24
28
  end
25
29
 
26
30
  def self.get_class(type)
@@ -29,29 +33,41 @@ class Eye::Checker
29
33
  klass
30
34
  end
31
35
 
32
- def self.create(pid, options = {}, logger_prefix = nil)
33
- get_class(options[:type]).new(pid, options, logger_prefix)
36
+ def self.create(pid, options = {}, process = nil)
37
+ get_class(options[:type]).new(pid, options, process)
34
38
  end
35
39
 
36
40
  def self.validate!(options)
37
41
  get_class(options[:type]).validate(options)
38
42
  end
39
43
 
40
- def initialize(pid, options = {}, logger_prefix = nil)
44
+ def initialize(pid, options = {}, process = nil)
45
+ @process = process
41
46
  @pid = pid
42
47
  @options = options
43
48
  @type = options[:type]
44
49
 
45
- @logger = Eye::Logger.new(logger_prefix, "check:#{check_name}")
46
50
  debug "create checker, with #{options}"
47
-
51
+
48
52
  @value = nil
49
53
  @values = Eye::Utils::Tail.new(max_tries)
50
54
  @check_count = 0
51
55
  end
52
56
 
57
+ def inspect
58
+ "<#{self.class} @process='#{@process.full_name}' @options=#{@options} @pid=#{@pid}>"
59
+ end
60
+
61
+ def logger_tag
62
+ @process.logger.prefix
63
+ end
64
+
65
+ def logger_sub_tag
66
+ "check:#{check_name}"
67
+ end
68
+
53
69
  def last_human_values
54
- h_values = @values.map do |v|
70
+ h_values = @values.map do |v|
55
71
  sign = v[:good] ? '' : '*'
56
72
  sign + human_value(v[:value]).to_s
57
73
  end
@@ -90,7 +106,7 @@ class Eye::Checker
90
106
  # true if check ok
91
107
  # false if check bad
92
108
  def good?(value)
93
- raise 'Realize me'
109
+ value
94
110
  end
95
111
 
96
112
  def check_name
@@ -106,7 +122,7 @@ class Eye::Checker
106
122
  end
107
123
  else
108
124
  1
109
- end
125
+ end
110
126
  end
111
127
 
112
128
  def min_tries
@@ -125,10 +141,13 @@ class Eye::Checker
125
141
  @values[-1][:value] if @values.present?
126
142
  end
127
143
 
128
- extend Eye::Dsl::Validation
129
- param :every, [Fixnum, Float], false, 5
130
- param :times, [Fixnum, Array]
131
- param :fire, Symbol, nil, nil, [:stop, :restart, :unmonitor, :nothing]
144
+ def run_in_process_context(p)
145
+ process.instance_exec(&p) if process.alive?
146
+ end
147
+
148
+ def defer(&block)
149
+ Celluloid::Future.new(&block).value
150
+ end
132
151
 
133
152
  class Defer < Eye::Checker
134
153
  def get_value_safe
@@ -136,13 +155,24 @@ class Eye::Checker
136
155
  end
137
156
  end
138
157
 
139
- class Custom < Defer
158
+ def self.register(base)
159
+ name = base.to_s.gsub("Eye::Checker::", '')
160
+ type = name.underscore.to_sym
161
+ Eye::Checker::TYPES[type] = name
162
+ Eye::Checker.const_set(name, base)
163
+ end
164
+
165
+ class Custom < Eye::Checker
166
+ def self.inherited(base)
167
+ super
168
+ register(base)
169
+ end
170
+ end
171
+
172
+ class CustomDefer < Defer
140
173
  def self.inherited(base)
141
174
  super
142
- name = base.to_s
143
- type = name.underscore.to_sym
144
- Eye::Checker::TYPES[type] = name
145
- Eye::Checker.const_set(name, base)
175
+ register(base)
146
176
  end
147
177
  end
148
178
  end
@@ -2,7 +2,7 @@ class Eye::Checker::FileSize < Eye::Checker
2
2
 
3
3
  # Check that file size changed (log for example)
4
4
 
5
- # checks :fsize, :every => 5.seconds, :file => "/tmp/1.log", :times => [3,5],
5
+ # checks :fsize, :every => 5.seconds, :file => "/tmp/1.log", :times => [3,5],
6
6
  # :below => 30.kilobytes, :above => 10.kilobytes
7
7
 
8
8
  param :file, [String], true
@@ -28,7 +28,7 @@ class Eye::Checker::Http < Eye::Checker::Defer
28
28
  @open_timeout = (open_timeout || 3).to_f
29
29
  @read_timeout = (read_timeout || timeout || 15).to_f
30
30
  end
31
-
31
+
32
32
  def get_value
33
33
  res = session.start{ |http| http.get(@uri.request_uri) }
34
34
  {:result => res}
@@ -52,7 +52,7 @@ class Eye::Checker::Http < Eye::Checker::Defer
52
52
  return false unless value[:result]
53
53
 
54
54
  unless value[:result].kind_of?(@kind)
55
- return false
55
+ return false
56
56
  end
57
57
 
58
58
  if @pattern
@@ -79,7 +79,7 @@ class Eye::Checker::Http < Eye::Checker::Defer
79
79
  msg += "<#{value[:notice]}>" if value[:notice]
80
80
  msg
81
81
  end
82
- end
82
+ end
83
83
 
84
84
  private
85
85
 
@@ -3,7 +3,7 @@ class Eye::Checker::Memory < Eye::Checker
3
3
  # checks :memory, :every => 3.seconds, :below => 80.megabytes, :times => [3,5]
4
4
 
5
5
  param :below, [Fixnum, Float], true
6
-
6
+
7
7
  def check_name
8
8
  @check_name ||= "memory(#{human_value(below)})"
9
9
  end
@@ -68,18 +68,18 @@ class Eye::Checker::Socket < Eye::Checker::Defer
68
68
  return false if !value[:result]
69
69
 
70
70
  if expect_data
71
- if expect_data.is_a?(Proc)
71
+ if expect_data.is_a?(Proc)
72
72
  match = begin
73
- !!expect_data[value[:result]]
73
+ !!expect_data[value[:result]]
74
74
  rescue Timeout::Error, Exception => ex
75
75
  mes = "proc match failed with '#{ex.message}'"
76
76
  error(mes)
77
77
  value[:notice] = mes
78
78
  return false
79
79
  end
80
-
80
+
81
81
  unless match
82
- warn "proc #{expect_data} not matched (#{value[:result].truncate(30)}) answer"
82
+ warn "proc #{expect_data} not matched (#{value[:result].truncate(30)}) answer"
83
83
  value[:notice] = "missing proc validation"
84
84
  end
85
85
 
@@ -108,7 +108,7 @@ class Eye::Checker::Socket < Eye::Checker::Defer
108
108
  else
109
109
  res = "#{value[:result].to_s.size}b"
110
110
  res += "<#{value[:notice]}>" if value[:notice]
111
- res
111
+ res
112
112
  end
113
113
  end
114
114
  end
@@ -116,7 +116,7 @@ class Eye::Checker::Socket < Eye::Checker::Defer
116
116
  private
117
117
 
118
118
  def open_socket
119
- if @socket_family == :tcp
119
+ if @socket_family == :tcp
120
120
  TCPSocket.open(@socket_addr, @socket_port)
121
121
  elsif @socket_family == :unix
122
122
  UNIXSocket.open(@socket_path)
@@ -15,9 +15,6 @@ class Eye::ChildProcess
15
15
  # system methods: send_signal
16
16
  include Eye::Process::System
17
17
 
18
- # logger methods: info, ...
19
- include Eye::Logger::Helpers
20
-
21
18
  # self_status_data
22
19
  include Eye::Process::Data
23
20
 
@@ -37,8 +34,6 @@ class Eye::ChildProcess
37
34
  @name = "child-#{pid}"
38
35
  @full_name = [logger_prefix, @name] * ':'
39
36
 
40
- @logger = Eye::Logger.new(@full_name)
41
-
42
37
  @watchers = {}
43
38
 
44
39
  debug "start monitoring CHILD config: #{@config.inspect}"
@@ -46,6 +41,10 @@ class Eye::ChildProcess
46
41
  start_checkers
47
42
  end
48
43
 
44
+ def logger_tag
45
+ full_name
46
+ end
47
+
49
48
  def state
50
49
  :up
51
50
  end
@@ -70,7 +69,7 @@ class Eye::ChildProcess
70
69
  execute_restart_command
71
70
  else
72
71
  stop
73
- end
72
+ end
74
73
  end
75
74
 
76
75
  def monitor
@@ -79,7 +78,7 @@ class Eye::ChildProcess
79
78
  def unmonitor
80
79
  end
81
80
 
82
- def delete
81
+ def delete
83
82
  end
84
83
 
85
84
  def destroy
@@ -88,10 +87,7 @@ class Eye::ChildProcess
88
87
  end
89
88
 
90
89
  def signal(sig)
91
- if self.pid
92
- res = send_signal(sig)
93
- info "send signal #{sig} to #{self.pid} = #{res}"
94
- end
90
+ send_signal(sig) if self.pid
95
91
  end
96
92
 
97
93
  def status_data(debug = false)