bluepill 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
data/bin/bluepill CHANGED
@@ -5,7 +5,6 @@ require 'bluepill'
5
5
 
6
6
  # defaults
7
7
  options = {
8
- :application => "all",
9
8
  :log_file => "/var/log/bluepill.log"
10
9
  }
11
10
 
@@ -37,6 +36,7 @@ case options[:command]
37
36
  when "load"
38
37
  file = ARGV.shift
39
38
  eval(File.read(file))
39
+
40
40
  when "log"
41
41
  pattern = ARGV.shift
42
42
  pattern = controller.send_cmd(options[:application], :grep_pattern, pattern)
@@ -49,5 +49,5 @@ when *ALLOWED_COMMANDS
49
49
  puts controller.send_cmd(options[:application], options[:command], process_or_group_name)
50
50
 
51
51
  else
52
- "Unknown command `%s`" % options[:command]
52
+ puts "Unknown command `%s`" % options[:command]
53
53
  end
data/bluepill.gemspec ADDED
@@ -0,0 +1,88 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{bluepill}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Arya Asemanfar", "Gary Tsang", "Rohith Ravi"]
12
+ s.date = %q{2009-10-05}
13
+ s.default_executable = %q{bluepill}
14
+ s.description = %q{Bluepill keeps your daemons up while taking up as little resources as possible. After all you probably want the resources of your server to be used by whatever daemons you are running rather than the thing that's supposed to make sure they are brought back up, should they die or misbehave.}
15
+ s.email = %q{entombedvirus@gmail.com}
16
+ s.executables = ["bluepill"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README",
20
+ "README.rdoc"
21
+ ]
22
+ s.files = [
23
+ ".document",
24
+ ".gitignore",
25
+ "LICENSE",
26
+ "README",
27
+ "README.rdoc",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "bin/bluepill",
31
+ "bluepill.gemspec",
32
+ "lib/bluepill.rb",
33
+ "lib/bluepill/application.rb",
34
+ "lib/bluepill/application/client.rb",
35
+ "lib/bluepill/application/server.rb",
36
+ "lib/bluepill/comm.rb",
37
+ "lib/bluepill/condition_watch.rb",
38
+ "lib/bluepill/controller.rb",
39
+ "lib/bluepill/dsl.rb",
40
+ "lib/bluepill/group.rb",
41
+ "lib/bluepill/logger.rb",
42
+ "lib/bluepill/process.rb",
43
+ "lib/bluepill/process_conditions.rb",
44
+ "lib/bluepill/process_conditions/always_true.rb",
45
+ "lib/bluepill/process_conditions/cpu_usage.rb",
46
+ "lib/bluepill/process_conditions/mem_usage.rb",
47
+ "lib/bluepill/process_conditions/process_condition.rb",
48
+ "lib/bluepill/socket.rb",
49
+ "lib/bluepill/util/rotational_array.rb",
50
+ "lib/example.rb",
51
+ "spec/blue-pill_spec.rb",
52
+ "spec/process_spec.rb",
53
+ "spec/spec_helper.rb"
54
+ ]
55
+ s.has_rdoc = true
56
+ s.homepage = %q{http://github.com/arya/bluepill}
57
+ s.rdoc_options = ["--charset=UTF-8"]
58
+ s.require_paths = ["lib"]
59
+ s.rubygems_version = %q{1.3.2}
60
+ s.summary = %q{A process monitor written in Ruby with stability and minimalism in mind.}
61
+ s.test_files = [
62
+ "spec/blue-pill_spec.rb",
63
+ "spec/process_spec.rb",
64
+ "spec/spec_helper.rb"
65
+ ]
66
+
67
+ if s.respond_to? :specification_version then
68
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
69
+ s.specification_version = 3
70
+
71
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
72
+ s.add_development_dependency(%q<rspec>, [">= 0"])
73
+ s.add_runtime_dependency(%q<daemons>, [">= 1.0.9"])
74
+ s.add_runtime_dependency(%q<pluginaweek-state_machine>, [">= 0.8.0"])
75
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.0.2"])
76
+ else
77
+ s.add_dependency(%q<rspec>, [">= 0"])
78
+ s.add_dependency(%q<daemons>, [">= 1.0.9"])
79
+ s.add_dependency(%q<pluginaweek-state_machine>, [">= 0.8.0"])
80
+ s.add_dependency(%q<activesupport>, [">= 2.0.2"])
81
+ end
82
+ else
83
+ s.add_dependency(%q<rspec>, [">= 0"])
84
+ s.add_dependency(%q<daemons>, [">= 1.0.9"])
85
+ s.add_dependency(%q<pluginaweek-state_machine>, [">= 0.8.0"])
86
+ s.add_dependency(%q<activesupport>, [">= 2.0.2"])
87
+ end
88
+ end
@@ -1,18 +1,14 @@
1
- require 'logger'
2
-
3
1
  module Bluepill
4
2
  class Application
5
3
  attr_accessor :name, :logger, :base_dir, :socket, :pid_file
6
- attr_accessor :groups, :group_logger
4
+ attr_accessor :groups
7
5
 
8
6
  def initialize(name, options = {})
9
7
  self.name = name
10
8
  self.base_dir = options[:base_dir] ||= '/var/bluepill'
11
9
 
12
- self.logger = Bluepill::Logger.new
13
- self.group_logger = Bluepill::Logger.new(self.logger, "#{self.name}:") if self.logger
10
+ self.logger = Bluepill::Logger.new.prefix_with(self.name)
14
11
 
15
- # self.groups = Hash.new { |h,k| h[k] = Group.new(k, :logger => self.group_logger) }
16
12
  self.groups = Hash.new
17
13
 
18
14
  self.pid_file = File.join(self.base_dir, 'pids', self.name + ".pid")
@@ -118,9 +114,17 @@ module Bluepill
118
114
  end
119
115
  end
120
116
 
121
- def add_process(process, group = nil)
122
- self.groups[group] ||= Group.new(group, :logger => self.group_logger)
123
- self.groups[group].add_process(process)
117
+ def quit
118
+ if @server
119
+ ::Process.kill("TERM", 0)
120
+ else
121
+ send_to_server("quit")
122
+ end
123
+ end
124
+
125
+ def add_process(process, group_name = nil)
126
+ self.groups[group_name] ||= Group.new(group_name, :logger => self.logger.prefix_with(group_name))
127
+ self.groups[group_name].add_process(process)
124
128
  end
125
129
 
126
130
  def send_to_server(method)
@@ -204,10 +208,10 @@ private
204
208
  Signal.trap("INT", &terminator)
205
209
  end
206
210
 
207
- def grep_pattern(query)
208
- bluepilld = 'bluepill\[[[:digit:]]+\]:[[:space:]]+'
209
- pattern = [self.name, query].join('|')
210
- [bluepilld, '\[.*', Regexp.escape(pattern), '.*\]'].join
211
+ def grep_pattern(query = nil)
212
+ bluepilld = 'bluepilld\[[[:digit:]]+\]:[[:space:]]+'
213
+ pattern = [self.name, query].compact.join(':')
214
+ [bluepilld, '\[.*', Regexp.escape(pattern), '.*'].join
211
215
  end
212
216
  end
213
217
  end
@@ -1,6 +1,6 @@
1
1
  module Bluepill
2
2
  class ConditionWatch
3
- attr_accessor :logger
3
+ attr_accessor :logger, :name
4
4
  def initialize(name, options = {})
5
5
  @name = name
6
6
 
@@ -26,9 +26,9 @@ module Bluepill
26
26
 
27
27
  def record_value(value)
28
28
  # TODO: record value in ProcessStatistics
29
- self.logger.info(self.to_s) if self.logger
30
29
  @history[@history_index] = [value, @process_condition.check(value)]
31
30
  @history_index = (@history_index + 1) % @history.size
31
+ self.logger.info(self.to_s)
32
32
  end
33
33
 
34
34
  def clear_history!
@@ -38,7 +38,7 @@ module Bluepill
38
38
  end
39
39
 
40
40
  def fired?
41
- @history.select {|v| !v[1] }.size >= @times[0]
41
+ @history.select {|v| v && !v[1]}.size >= @times[0]
42
42
  end
43
43
 
44
44
  def to_s
@@ -46,7 +46,8 @@ module Bluepill
46
46
  # use (@history[(@history_index - 1)..1] + @history[0..(@history_index - 1)]).
47
47
  # collect {|v| "#{v[0]}#{v[1] ? '' : '*'}"}.join(", ")
48
48
  # but that's gross so... it's gonna be out of order till we figure out a better way to get it in order
49
- @history.collect {|v| "#{v[0]}#{v[1] ? '' : '*'}"}.join(", ")
49
+ data = @history.collect {|v| "#{v[0]}#{v[1] ? '' : '*'}" if v}.compact.join(", ")
50
+ "#{@name}: [#{data}]"
50
51
  end
51
52
  end
52
53
  end
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+
1
3
  module Bluepill
2
4
  class Controller
3
5
  attr_accessor :base_dir, :sockets_dir, :pids_dir
@@ -8,6 +10,7 @@ module Bluepill
8
10
  self.sockets_dir = File.join(base_dir, 'socks')
9
11
  self.pids_dir = File.join(base_dir, 'pids')
10
12
  self.applications = Hash.new
13
+ setup_dir_structure
11
14
  end
12
15
 
13
16
  def list
@@ -18,5 +21,13 @@ module Bluepill
18
21
  applications[application] ||= Application.new(application, {:base_dir => base_dir})
19
22
  applications[application].send(command.to_sym, *args.compact)
20
23
  end
24
+
25
+ private
26
+
27
+ def setup_dir_structure
28
+ [@sockets_dir, @pids_dir].each do |dir|
29
+ FileUtils.mkdir_p(dir) unless File.exists?(dir)
30
+ end
31
+ end
21
32
  end
22
33
  end
@@ -7,15 +7,10 @@ module Bluepill
7
7
  self.name = name
8
8
  self.processes = []
9
9
  self.logger = options[:logger]
10
-
11
- if self.logger
12
- logger_prefix = self.name ? "#{self.name}:" : nil
13
- self.process_logger = Bluepill::Logger.new(self.logger, logger_prefix)
14
- end
15
10
  end
16
11
 
17
12
  def add_process(process)
18
- process.logger = Logger.new(self.process_logger, process.name)
13
+ process.logger = self.logger.prefix_with(process.name)
19
14
  self.processes << process
20
15
  end
21
16
 
@@ -1,17 +1,29 @@
1
1
  module Bluepill
2
2
  class Logger
3
- def initialize(logger = nil, prefix = nil)
4
- @logger = logger || Syslog.open('bluepill', Syslog::LOG_PID | Syslog::LOG_CONS, Syslog::LOG_LOCAL6)
5
- @prefix = prefix
3
+ LOG_METHODS = [:emerg, :alert, :crit, :err, :warning, :notice, :info, :debug]
4
+
5
+ def initialize(options = {})
6
+ @logger = options[:logger] || Syslog.open(options[:identity] || 'bluepilld', Syslog::LOG_PID, Syslog::LOG_LOCAL6)
7
+ @prefix = options[:prefix]
8
+ @prefixes = {}
6
9
  end
7
10
 
8
- [:emerg, :alert, :crit, :err, :warning, :notice, :info, :debug].each do |method|
11
+ LOG_METHODS.each do |method|
9
12
  eval <<-END
10
- def #{method}(*args)
11
- with_prefix = args.collect {|s| "\#{@prefix}\#{s}" }
12
- @logger.#{method}(*with_prefix)
13
+ def #{method}(msg, prefix = [])
14
+ if @logger.is_a?(self.class)
15
+ @logger.#{method}(msg, [@prefix] + prefix)
16
+ else
17
+ prefix = prefix.size > 0 ? "[\#{prefix.compact.join(':')}] " : ""
18
+ @logger.#{method}("\#{prefix}\#{msg}")
19
+ end
13
20
  end
14
21
  END
15
22
  end
23
+
24
+ def prefix_with(prefix)
25
+ @prefixes[prefix] ||= self.class.new(:logger => self, :prefix => prefix)
26
+ end
27
+
16
28
  end
17
29
  end
@@ -82,7 +82,7 @@ module Bluepill
82
82
  end
83
83
 
84
84
  def add_watch(name, options = {})
85
- self.watches << ConditionWatch.new(name, options.merge(:logger => self.watch_logger))
85
+ self.watches << ConditionWatch.new(name, options.merge(:logger => self.logger))
86
86
  end
87
87
 
88
88
  def daemonize?
@@ -90,10 +90,14 @@ module Bluepill
90
90
  end
91
91
 
92
92
  def dispatch!(event)
93
- logger.info "Got stop"
94
93
  self.send("#{event}!")
95
94
  end
96
95
 
96
+ def logger=(logger)
97
+ @logger = logger
98
+ self.watches.each {|w| w.logger = logger }
99
+ end
100
+
97
101
  def process_running?(force = false)
98
102
  @process_running = nil if force
99
103
  @process_running ||= signal_process(0)
@@ -158,14 +162,18 @@ module Bluepill
158
162
  now = Time.now.to_i
159
163
 
160
164
  threads = self.watches.collect do |watch|
161
- Thread.new { Thread.current[:events] = watch.run(self.actual_pid, now) }
165
+ [watch, Thread.new { Thread.current[:events] = watch.run(self.actual_pid, now) }]
162
166
  end
163
167
 
164
168
  @transitioned = false
165
169
 
166
- threads.inject([]) do |events, thread|
170
+ threads.inject([]) do |events, (watch, thread)|
167
171
  thread.join
168
- events << thread[:events]
172
+ if thread[:events].size > 0
173
+ logger.info "#{watch.name} dispatched: #{thread[:events].join(',')}"
174
+ events << thread[:events]
175
+ end
176
+ events
169
177
  end.flatten.uniq.each do |event|
170
178
  break if @transitioned
171
179
  self.dispatch!(event)
@@ -174,6 +182,7 @@ module Bluepill
174
182
 
175
183
  def record_transition(state_name)
176
184
  @transitioned = true
185
+ self.watches.each { |w| w.clear_history! }
177
186
  # do other stuff here?
178
187
  end
179
188
 
@@ -192,10 +201,6 @@ module Bluepill
192
201
  @actual_pid = nil
193
202
  File.unlink(pid_file) if File.exists?(pid_file)
194
203
  end
195
-
196
- def watch_logger
197
- @watch_logger ||= Logger.new(self.logger, "#{self.name}:") if self.logger
198
- end
199
204
  end
200
205
  end
201
206
 
data/lib/example.rb CHANGED
@@ -19,25 +19,25 @@ ROOT_DIR = "/tmp/bp"
19
19
  # application.start
20
20
 
21
21
 
22
- Bluepill.application(:sample_app, :base_dir => ROOT_DIR) do |app|
22
+ Bluepill.application(:sample_app) do |app|
23
23
  2.times do |i|
24
24
  app.process("process_#{i}") do |process|
25
25
  process.start_command = "echo 'Process #{i}' && sleep #{rand(15) + i}"
26
26
  process.daemonize = true
27
27
  process.pid_file = "#{ROOT_DIR}/pids/process_#{i}.pid"
28
28
 
29
- process.checks :always_true, :every => 2
29
+ process.checks :cpu_usage, :every => 1, :below => 1, :times => [1,4]
30
30
  end
31
31
  end
32
32
 
33
- 10.times do |i|
33
+ 0.times do |i|
34
34
  app.process("group_process_#{i}") do |process|
35
35
  process.start_command = "sleep #{rand(15) + i}"
36
36
  process.group = "Poopfaced"
37
37
  process.daemonize = true
38
38
  process.pid_file = "#{ROOT_DIR}/pids/process_#{i}.pid"
39
39
 
40
- process.checks :always_true, :every => 2
40
+ process.checks :always_true, :every => 10
41
41
  end
42
42
  end
43
43
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bluepill
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arya Asemanfar
@@ -73,6 +73,7 @@ files:
73
73
  - Rakefile
74
74
  - VERSION
75
75
  - bin/bluepill
76
+ - bluepill.gemspec
76
77
  - lib/bluepill.rb
77
78
  - lib/bluepill/application.rb
78
79
  - lib/bluepill/application/client.rb