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,5 @@
1
+ require 'sigar'
2
+ require 'logger'
3
+
4
+ Eye::Sigar = ::Sigar.new
5
+ Eye::Sigar.logger = ::Logger.new(nil)
@@ -55,13 +55,15 @@ module Eye::System
55
55
  # :environment
56
56
  # :stdin, :stdout, :stderr
57
57
  def daemonize(cmd, cfg = {})
58
- opts = spawn_options(cfg)
59
- pid = Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), opts)
60
- Process.detach(pid)
58
+ pid = ::Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))
59
+
61
60
  {:pid => pid, :exitstatus => 0}
62
61
 
63
62
  rescue Errno::ENOENT, Errno::EACCES => ex
64
63
  {:error => ex}
64
+
65
+ ensure
66
+ Process.detach(pid) if pid
65
67
  end
66
68
 
67
69
  # Execute cmd with blocking, return status (be careful: inside actor blocks it mailbox, use with defer)
@@ -70,8 +72,7 @@ module Eye::System
70
72
  # :environment
71
73
  # :stdin, :stdout, :stderr
72
74
  def execute(cmd, cfg = {})
73
- opts = spawn_options(cfg)
74
- pid = Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), opts)
75
+ pid = ::Process::spawn(prepare_env(cfg), *Shellwords.shellwords(cmd), spawn_options(cfg))
75
76
 
76
77
  timeout = cfg[:timeout] || 1.second
77
78
  status = 0
@@ -142,7 +143,7 @@ module Eye::System
142
143
  o.update(err: [config[:stderr], 'a']) if config[:stderr]
143
144
  o.update(in: config[:stdin]) if config[:stdin]
144
145
 
145
- if Eye::Settings.root?
146
+ if Eye::Local.root?
146
147
  o.update(uid: Etc.getpwnam(config[:uid]).uid) if config[:uid]
147
148
  o.update(gid: Etc.getpwnam(config[:gid]).gid) if config[:gid]
148
149
  end
@@ -6,31 +6,33 @@ class Eye::SystemResources
6
6
  class << self
7
7
 
8
8
  def memory(pid)
9
- ps_aux[pid].try :[], :rss
9
+ cache.proc_mem(pid).try(:resident)
10
10
  end
11
11
 
12
12
  def cpu(pid)
13
- ps_aux[pid].try :[], :cpu
13
+ if cpu = cache.proc_cpu(pid)
14
+ cpu.percent * 100
15
+ end
14
16
  end
15
17
 
16
18
  def childs(parent_pid)
17
- parent_pid = parent_pid.to_i
19
+ cache.childs(parent_pid)
20
+ end
18
21
 
19
- childs = []
20
- ps_aux.each do |pid, h|
21
- childs << pid if h[:ppid] == parent_pid
22
+ def start_time(pid) # unixtime
23
+ if cpu = cache.proc_cpu(pid)
24
+ cpu.start_time.to_i / 1000
22
25
  end
23
-
24
- childs
25
26
  end
26
27
 
27
- def start_time(pid)
28
- ps_aux[pid].try :[], :start_time
28
+ # total cpu usage in seconds
29
+ def cputime(pid)
30
+ if cpu = cache.proc_cpu(pid)
31
+ cpu.total.to_f / 1000
32
+ end
29
33
  end
30
34
 
31
35
  def resources(pid)
32
- return {} unless ps_aux[pid]
33
-
34
36
  { :memory => memory(pid),
35
37
  :cpu => cpu(pid),
36
38
  :start_time => start_time(pid),
@@ -38,49 +40,52 @@ class Eye::SystemResources
38
40
  }
39
41
  end
40
42
 
41
- # initialize actor, call 1 time before using
42
- def setup
43
- @actor ||= PsAxActor.new
44
- end
45
-
46
- private
47
-
48
- def reset!
49
- setup.terminate
50
- @actor = nil
51
- end
52
-
53
- def ps_aux
54
- setup
55
- @actor.get
43
+ def cache
44
+ @cache ||= Cache.new
56
45
  end
57
-
58
46
  end
59
47
 
60
- class PsAxActor
48
+ class Cache
61
49
  include Celluloid
62
50
 
63
- UPDATE_INTERVAL = 5 # seconds
51
+ attr_reader :expire
64
52
 
65
53
  def initialize
66
- set
54
+ clear
55
+ setup_expire
67
56
  end
68
57
 
69
- def get
70
- if @at + UPDATE_INTERVAL < Time.now
71
- @at = Time.now # for minimize races
72
- async.set
73
- end
74
- @ps_aux
58
+ def setup_expire(expire = 5)
59
+ @expire = expire
60
+ @timer.cancel if @timer
61
+ @timer = every(@expire) { clear }
75
62
  end
76
63
 
77
- private
64
+ def clear
65
+ @memory = {}
66
+ @cpu = {}
67
+ @ppids = {}
68
+ end
78
69
 
79
- def set
80
- @ps_aux = Eye::System.ps_aux
81
- @at = Time.now
70
+ def proc_mem(pid)
71
+ @memory[pid] ||= Eye::Sigar.proc_mem(pid) if pid
72
+
73
+ rescue ArgumentError # when incorrect PID
82
74
  end
83
75
 
76
+ def proc_cpu(pid)
77
+ @cpu[pid] ||= Eye::Sigar.proc_cpu(pid) if pid
78
+
79
+ rescue ArgumentError # when incorrect PID
80
+ end
81
+
82
+ def childs(pid)
83
+ if pid
84
+ @ppids[pid] ||= Eye::Sigar.proc_list("State.Ppid.eq=#{pid}")
85
+ else
86
+ []
87
+ end
88
+ end
84
89
  end
85
90
 
86
91
  end
@@ -1,16 +1,16 @@
1
1
  class Eye::Trigger
2
+ include Eye::Dsl::Validation
3
+
2
4
  autoload :Flapping, 'eye/trigger/flapping'
3
- autoload :State, 'eye/trigger/state'
5
+ autoload :Transition, 'eye/trigger/transition'
4
6
  autoload :StopChilds, 'eye/trigger/stop_childs'
5
7
 
6
8
  # ex: { :type => :flapping, :times => 2, :within => 30.seconds}
7
9
 
8
- TYPES = {:flapping => "Flapping", :state => "State", :stop_childs => "StopChilds"}
10
+ TYPES = {:flapping => 'Flapping', :transition => 'Transition', :stop_childs => 'StopChilds'}
9
11
 
10
12
  attr_reader :message, :options, :process
11
13
 
12
- extend Eye::Dsl::Validation
13
-
14
14
  def self.name_and_class(type)
15
15
  type = type.to_sym
16
16
  return {:name => type, :type => type} if TYPES[type]
@@ -24,6 +24,9 @@ class Eye::Trigger
24
24
  def self.get_class(type)
25
25
  klass = eval("Eye::Trigger::#{TYPES[type]}") rescue nil
26
26
  raise "Unknown trigger #{type}" unless klass
27
+ if deps = klass.depends_on
28
+ Array(deps).each { |d| require d }
29
+ end
27
30
  klass
28
31
  end
29
32
 
@@ -59,8 +62,9 @@ class Eye::Trigger
59
62
  "trigger(#{@options[:type]})"
60
63
  end
61
64
 
62
- def notify(transition)
65
+ def notify(transition, reason)
63
66
  debug "check (:#{transition.event}) :#{transition.from} => :#{transition.to}"
67
+ @reason = reason
64
68
  @transition = transition
65
69
 
66
70
  check(transition) if filter_transition(transition)
@@ -82,7 +86,7 @@ class Eye::Trigger
82
86
  end
83
87
 
84
88
  def check(transition)
85
- raise "realize me"
89
+ raise 'realize me'
86
90
  end
87
91
 
88
92
  def run_in_process_context(p)
@@ -94,12 +98,15 @@ class Eye::Trigger
94
98
  end
95
99
 
96
100
  def self.register(base)
97
- name = base.to_s.gsub("Eye::Trigger::", '')
101
+ name = base.to_s.gsub('Eye::Trigger::', '')
98
102
  type = name.underscore.to_sym
99
103
  Eye::Trigger::TYPES[type] = name
100
104
  Eye::Trigger.const_set(name, base)
101
105
  end
102
106
 
107
+ def self.depends_on
108
+ end
109
+
103
110
  class Custom < Eye::Trigger
104
111
  def self.inherited(base)
105
112
  super
@@ -120,4 +127,4 @@ private
120
127
  end
121
128
  end
122
129
 
123
- end
130
+ end
@@ -32,7 +32,7 @@ private
32
32
  end
33
33
 
34
34
  def on_flapping
35
- debug "flapping recognized!!!"
35
+ debug 'flapping recognized!!!'
36
36
 
37
37
  process.notify :error, 'flapping!'
38
38
  process.schedule :unmonitor, Eye::Reason.new(:flapping)
@@ -3,7 +3,7 @@ class Eye::Trigger::StopChilds < Eye::Trigger
3
3
  param :timeout, [Fixnum, Float], nil, 60
4
4
 
5
5
  def check(trans)
6
- debug "stop childs"
6
+ debug 'stop childs'
7
7
  process.childs.pmap { |pid, c| c.stop }
8
8
  end
9
9
 
@@ -0,0 +1,15 @@
1
+ class Eye::Trigger::Transition < Eye::Trigger
2
+
3
+ # trigger :transition, :to => :up, :from => :starting, :do => ->{ ... }
4
+
5
+ param :do, [Proc, Symbol]
6
+
7
+ def check(trans)
8
+ act = @options[:do]
9
+ if act
10
+ instance_exec(&@options[:do]) if act.is_a?(Proc)
11
+ send(act, process) if act.is_a?(Symbol)
12
+ end
13
+ end
14
+
15
+ end
@@ -1,3 +1,5 @@
1
+ require 'date'
2
+
1
3
  module Eye::Utils
2
4
  autoload :Tail, 'eye/utils/tail'
3
5
  autoload :AliveArray, 'eye/utils/alive_array'
@@ -11,4 +13,14 @@ module Eye::Utils
11
13
  end
12
14
  end
13
15
 
16
+ D1 = '%H:%M'
17
+ D2 = '%b%d'
18
+
19
+ def self.human_time(unix_time)
20
+ time = Time.at(unix_time.to_i)
21
+ d1 = time.to_date
22
+ d2 = Time.now.to_date
23
+ time.strftime (d1 == d2) ? D1 : D2
24
+ end
25
+
14
26
  end
@@ -0,0 +1,7 @@
1
+ # http://stackoverflow.com/questions/7263268/ruby-symbolto-proc-leaks-references-in-1-9-2-p180
2
+
3
+ class Symbol
4
+ def to_proc
5
+ lambda { |x| x.send(self) }
6
+ end
7
+ end
@@ -0,0 +1,106 @@
1
+ require 'time'
2
+
3
+ def silence_warnings
4
+ old_verbose, $VERBOSE = $VERBOSE, nil
5
+ yield
6
+ ensure
7
+ $VERBOSE = old_verbose
8
+ end
9
+
10
+ class Object
11
+ def blank?
12
+ respond_to?(:empty?) ? empty? : !self
13
+ end
14
+
15
+ def present?
16
+ !blank?
17
+ end
18
+
19
+ def try(m, *args)
20
+ send(m, *args) if respond_to?(m)
21
+ end
22
+ end
23
+
24
+ class NilClass
25
+ def try(*args)
26
+ end
27
+ end
28
+
29
+ class String
30
+ def underscore
31
+ word = self.dup
32
+ word.gsub!('::', '/')
33
+ word.gsub!(/(?:([A-Za-z\d])|^)((?=a)b)(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
34
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
35
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
36
+ word.tr!("-", "_")
37
+ word.downcase!
38
+ word
39
+ end
40
+
41
+ def truncate(l)
42
+ self[0..l]
43
+ end
44
+ end
45
+
46
+ class Array
47
+ def extract_options!
48
+ self[-1].is_a?(Hash) ? self.pop : {}
49
+ end
50
+ end
51
+
52
+ class Numeric
53
+ def seconds
54
+ self
55
+ end
56
+ alias :second :seconds
57
+
58
+ def minutes
59
+ self * 60
60
+ end
61
+ alias :minute :minutes
62
+
63
+ def hours
64
+ self * 3600
65
+ end
66
+ alias :hour :hours
67
+
68
+ def days
69
+ self * 86400
70
+ end
71
+ alias :day :days
72
+
73
+ def weeks
74
+ self * 86400 * 7
75
+ end
76
+ alias :week :weeks
77
+
78
+ def ago
79
+ ::Time.now - self
80
+ end
81
+
82
+ def bytes
83
+ self
84
+ end
85
+ alias :byte :bytes
86
+
87
+ def kilobytes
88
+ self * 1024
89
+ end
90
+ alias :kilobyte :kilobytes
91
+
92
+ def megabytes
93
+ self * 1024 * 1024
94
+ end
95
+ alias :megabyte :megabytes
96
+
97
+ def gigabytes
98
+ self * 1024 * 1024 * 1024
99
+ end
100
+ alias :gigabyte :gigabytes
101
+
102
+ def terabytes
103
+ self * 1024 * 1024 * 1024 * 1024
104
+ end
105
+ alias :terabyte :terabytes
106
+ 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.4.2
4
+ version: '0.5'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Makarchev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-23 00:00:00.000000000 Z
11
+ date: 2013-10-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 0.14.0
19
+ version: 0.15.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: 0.14.0
26
+ version: 0.15.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: celluloid-io
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: 0.14.0
33
+ version: 0.15.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
- version: 0.14.0
40
+ version: 0.15.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: state_machine
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -67,19 +67,19 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: activesupport
70
+ name: sigar
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
- version: '3'
75
+ version: 0.7.2
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: '3'
82
+ version: 0.7.2
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -250,7 +250,7 @@ dependencies:
250
250
  version: '0'
251
251
  description: Process monitoring tool. Inspired from Bluepill and God. Requires Ruby(MRI)
252
252
  >= 1.9.3-p194. Uses Celluloid and Celluloid::IO.
253
- email: kostya27@gmail.com
253
+ email: eye-rb@googlegroups.com
254
254
  executables:
255
255
  - eye
256
256
  - loader_eye
@@ -284,13 +284,20 @@ files:
284
284
  - lib/eye/application.rb
285
285
  - lib/eye/checker.rb
286
286
  - lib/eye/checker/cpu.rb
287
+ - lib/eye/checker/cputime.rb
287
288
  - lib/eye/checker/file_ctime.rb
288
289
  - lib/eye/checker/file_size.rb
290
+ - lib/eye/checker/file_touched.rb
289
291
  - lib/eye/checker/http.rb
290
292
  - lib/eye/checker/memory.rb
291
293
  - lib/eye/checker/nop.rb
294
+ - lib/eye/checker/runtime.rb
292
295
  - lib/eye/checker/socket.rb
293
296
  - lib/eye/child_process.rb
297
+ - lib/eye/cli.rb
298
+ - lib/eye/cli/commands.rb
299
+ - lib/eye/cli/render.rb
300
+ - lib/eye/cli/server.rb
294
301
  - lib/eye/client.rb
295
302
  - lib/eye/config.rb
296
303
  - lib/eye/control.rb
@@ -300,7 +307,6 @@ files:
300
307
  - lib/eye/controller/load.rb
301
308
  - lib/eye/controller/options.rb
302
309
  - lib/eye/controller/send_command.rb
303
- - lib/eye/controller/show_history.rb
304
310
  - lib/eye/controller/status.rb
305
311
  - lib/eye/dsl.rb
306
312
  - lib/eye/dsl/application_opts.rb
@@ -317,6 +323,7 @@ files:
317
323
  - lib/eye/group.rb
318
324
  - lib/eye/group/chain.rb
319
325
  - lib/eye/loader.rb
326
+ - lib/eye/local.rb
320
327
  - lib/eye/logger.rb
321
328
  - lib/eye/notify.rb
322
329
  - lib/eye/notify/jabber.rb
@@ -338,17 +345,19 @@ files:
338
345
  - lib/eye/process/watchers.rb
339
346
  - lib/eye/reason.rb
340
347
  - lib/eye/server.rb
341
- - lib/eye/settings.rb
348
+ - lib/eye/sigar.rb
342
349
  - lib/eye/system.rb
343
350
  - lib/eye/system_resources.rb
344
351
  - lib/eye/trigger.rb
345
352
  - lib/eye/trigger/flapping.rb
346
- - lib/eye/trigger/state.rb
347
353
  - lib/eye/trigger/stop_childs.rb
354
+ - lib/eye/trigger/transition.rb
348
355
  - lib/eye/utils.rb
349
356
  - lib/eye/utils/alive_array.rb
350
357
  - lib/eye/utils/celluloid_chain.rb
351
358
  - lib/eye/utils/celluloid_klass.rb
359
+ - lib/eye/utils/leak_19.rb
360
+ - lib/eye/utils/mini_active_support.rb
352
361
  - lib/eye/utils/pmap.rb
353
362
  - lib/eye/utils/tail.rb
354
363
  homepage: http://github.com/kostya/eye