averell23-watchdogger 0.1.0
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.
- data/CHANGES +0 -0
- data/LICENSE +676 -0
- data/README.rdoc +86 -0
- data/bin/watchdogger +54 -0
- data/lib/dog_log.rb +52 -0
- data/lib/watchdogger.rb +177 -0
- data/lib/watcher/base.rb +96 -0
- data/lib/watcher/http_watcher.rb +52 -0
- data/lib/watcher/log_watcher.rb +97 -0
- data/lib/watcher.rb +51 -0
- data/lib/watcher_action/htpost.rb +42 -0
- data/lib/watcher_action/kill_process.rb +24 -0
- data/lib/watcher_action/log_action.rb +27 -0
- data/lib/watcher_action/send_mail.rb +67 -0
- data/lib/watcher_action.rb +41 -0
- data/lib/watcher_event.rb +23 -0
- data/sample_config.yml +16 -0
- data/test/http_watcher_test.rb +63 -0
- data/test/kill_process_test.rb +29 -0
- data/test/log_watcher_test.rb +38 -0
- data/test/test_helper.rb +6 -0
- data/test/watchdogger_test.rb +82 -0
- metadata +119 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
module WatcherAction
|
2
|
+
|
3
|
+
# This action posts the event to a given URL. It may use plain HTTP Authentication
|
4
|
+
#
|
5
|
+
# Options for this Action:
|
6
|
+
#
|
7
|
+
# url - The URL to post the information to (required)
|
8
|
+
# user - The user for HTTP Authentication (optional)
|
9
|
+
# pass - The password for HTTP Authentication.
|
10
|
+
class Htpost
|
11
|
+
|
12
|
+
def initialize(options)
|
13
|
+
@url = options.get_value(:url, false)
|
14
|
+
@user = options.get_value(:user)
|
15
|
+
@pass = options.get_value(:pass)
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute(event)
|
19
|
+
con_url = URI.parse(@url)
|
20
|
+
req = Net::HTTP::Post.new(url.path)
|
21
|
+
if(@user && @pass)
|
22
|
+
req.basic_auth(@user, @pass)
|
23
|
+
end
|
24
|
+
req.set_form_data( {
|
25
|
+
'type' => 'watchdogger_event',
|
26
|
+
'event' => event.to_xml
|
27
|
+
}, ';'
|
28
|
+
)
|
29
|
+
res = Net::HTTP.new(url.host, url.port).start { |http| http.request(req) }
|
30
|
+
case res
|
31
|
+
when Net::HTTPSuccess, Net::HTTPRedirection:
|
32
|
+
dog_log.debug("HTPOST Action") { "Posted event to #{@url} "}
|
33
|
+
else
|
34
|
+
dog_log.warn("HTPOST Action") { "Could not post to #{@url}: #{@res}"}
|
35
|
+
end
|
36
|
+
rescue Exception => e
|
37
|
+
dog_log.warn("HTPOST Action") { "Error posting to #{@url}: #{e.message}"}
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module WatcherAction
|
2
|
+
|
3
|
+
# Kills the process with the given PID.
|
4
|
+
# Options:
|
5
|
+
#
|
6
|
+
# pidfile - The file containing the process id
|
7
|
+
# signal - The signal to send to the process. Defaults to KILL
|
8
|
+
class KillProcess
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
@pidfile = config.get_value(:pidfile, false)
|
12
|
+
@signal= config.get_value(:signal, 'KILL')
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(event)
|
16
|
+
pid = File.open(@pidfile) { |io| io.read }
|
17
|
+
Process.kill(@signal, pid.to_i)
|
18
|
+
rescue Exception => e
|
19
|
+
dog_log.warn { "Unable to kill process: #{e}" }
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module WatcherAction
|
4
|
+
|
5
|
+
# Logs the event information to the standard log file
|
6
|
+
# Options:
|
7
|
+
#
|
8
|
+
# format - A format string that will receive the timestamp, watcher name and
|
9
|
+
# event message (in that order) as parameters (default message if not given)
|
10
|
+
# severity - The severity of the log message (default: warn)
|
11
|
+
class LogAction
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
@format = options.get_value(:format, "Watcher %s triggered at %s: %s")
|
15
|
+
if(severity = options.get_value(:severity))
|
16
|
+
@severity = Logger.const_get(severity.upcase)
|
17
|
+
else
|
18
|
+
@severity = Logger::WARN
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute(event)
|
23
|
+
dog_log.add(@severity, nil, 'LoggerAction') { @format % [event.watcher, event.timestamp, event.message] }
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rmail'
|
2
|
+
require 'net/smtp'
|
3
|
+
|
4
|
+
module WatcherAction
|
5
|
+
|
6
|
+
# This action will send an email to a given receipient. It doesn't support any
|
7
|
+
# fancy features (you may want to do that handling externally) and will only
|
8
|
+
# use unencrypted smtp network connections.
|
9
|
+
#
|
10
|
+
# Options for this action:
|
11
|
+
#
|
12
|
+
# to - Email address to which to send the message. May be a list. (required)
|
13
|
+
# sender - Email address of the person sending the mail (required)
|
14
|
+
# subject - Subject of the message. You can put %s for the event message. (defaults if not set)
|
15
|
+
# body - Body of the email message. If set to 'xml', it will include an
|
16
|
+
# XML representation of the event. If not set, it will default
|
17
|
+
# to a sensible description of the event. You can include the
|
18
|
+
# event's message as for the subject
|
19
|
+
# server - Address or name of the mail server to use (required)
|
20
|
+
# port - Port to connect to (default: 25)
|
21
|
+
# user - Mail server user name
|
22
|
+
# pass - Mail server password
|
23
|
+
# authentication - Authentication method (default: plain)
|
24
|
+
class SendMail
|
25
|
+
|
26
|
+
def initialize(config)
|
27
|
+
@mail_to = config.get_value(:to, false)
|
28
|
+
@sender = config.get_value(:sender, false)
|
29
|
+
@subject = config.get_value(:subject, "Watchdogger triggered: %s")
|
30
|
+
@body = config.get_value(:body)
|
31
|
+
@server = config.get_value(:server, false)
|
32
|
+
@port = config.get_value(:port, '25')
|
33
|
+
@user = config.get_value(:user)
|
34
|
+
@pass = config.get_value(:pass)
|
35
|
+
@authentication = config.get_value(:authentication, :plain).to_sym
|
36
|
+
end
|
37
|
+
|
38
|
+
def execute(event)
|
39
|
+
msg = RMail::Message.new
|
40
|
+
msg.header.to = @mail_to
|
41
|
+
receipient = msg.header.to.split(',').first
|
42
|
+
msg.header.from = @sender
|
43
|
+
msg.header.subject = @subject % [event.message]
|
44
|
+
if(@body.to_s == 'xml')
|
45
|
+
msg.body = event.to_xml
|
46
|
+
elsif(@body)
|
47
|
+
msg.body = @body % [event.message]
|
48
|
+
else
|
49
|
+
msg.body = "The #{event.watcher.class.name} watcher of your watchdog triggered\nan event at #{event.timestamp}:\n#{event.message}"
|
50
|
+
end
|
51
|
+
|
52
|
+
smtp_params = [@server, @port]
|
53
|
+
if(@user && @pass)
|
54
|
+
smtp_params << [nil, @user, @pass, @authentication]
|
55
|
+
end
|
56
|
+
|
57
|
+
Net::SMTP.start(*smtp_params) do |smtp|
|
58
|
+
smtp.send_message(msg.to_str, msg.header.from, msg.header.to)
|
59
|
+
end
|
60
|
+
dog_log.debug('SMTP Action') { "Sent mail to #{@mail_to} through #{@server}" }
|
61
|
+
rescue Exception => e
|
62
|
+
dog_log.warn('SMTP Action') { "Could not send mail to #{@mail_to} on #{@server}: #{e.message}" }
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Each action object contains the action that will be taken when a watched condition is triggered.
|
2
|
+
#
|
3
|
+
# Each action must respond to the #execute(event) method, which will execute the action.
|
4
|
+
#
|
5
|
+
# Actions should *not* log the executing to the log file, unless there is an unexpected error
|
6
|
+
# in the execution of the action itself. If the user wants to log to the log file,
|
7
|
+
# the logger action should be used. (All actions may use the log for debug-level information
|
8
|
+
# in all places.)
|
9
|
+
module WatcherAction
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
# creates a new action of the given type. The Action object itself will not
|
14
|
+
# be made public, instead call the #run_action method to execute it
|
15
|
+
def register(name, config_options)
|
16
|
+
assit_kind_of(String, name)
|
17
|
+
raise(ArgumentError, "Illegal options.") unless(config_options.is_a?(Hash))
|
18
|
+
type = config_options.get_value(:type, false)
|
19
|
+
type = WatchDogger.camelize(type)
|
20
|
+
registered_actions[name.to_sym] = WatcherAction.const_get(type).new(config_options)
|
21
|
+
dog_log.debug('Action Handler') { "Registered action '#{name}' of type #{type}"}
|
22
|
+
end
|
23
|
+
|
24
|
+
# Runs the named action. Returns true if the action ran without exception.
|
25
|
+
def run_action(name, event)
|
26
|
+
registered_actions[name.to_sym].execute(event)
|
27
|
+
true
|
28
|
+
rescue Exception => e
|
29
|
+
dog_log.error('Action Handler') { "Could not execute #{name}: #{e.message} (Registered actions: #{registered_actions.keys.join(', ')})" }
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def registered_actions
|
36
|
+
@registered_actions ||= {}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'builder'
|
2
|
+
|
3
|
+
# Encodes the information of an event that was triggered.
|
4
|
+
class WatcherEvent
|
5
|
+
|
6
|
+
attr_accessor :timestamp
|
7
|
+
attr_accessor :watcher
|
8
|
+
attr_accessor :message
|
9
|
+
|
10
|
+
def to_xml
|
11
|
+
builder = Builder::XmlMarkup.new()
|
12
|
+
builder.instruct!
|
13
|
+
builder.event do
|
14
|
+
builder.timestamp(timestamp)
|
15
|
+
builder.message(message)
|
16
|
+
builder.watcher do
|
17
|
+
builder.name(watcher.name)
|
18
|
+
builder.watcher_type(watcher.class.name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/sample_config.yml
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
# The URL that will be used for testing. Should return a 200 result and a body.
|
4
|
+
TEST_URL = 'http://wiki.github.com/averell23/watchdogger'
|
5
|
+
# Text that will be expected in the page body
|
6
|
+
TEST_URL_TEXT = 'averell23'
|
7
|
+
|
8
|
+
class HttpWatcherTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@default_options = {
|
12
|
+
:url => TEST_URL,
|
13
|
+
:actions => 'default',
|
14
|
+
:timeout => '2'
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_simple
|
19
|
+
watcher = Watcher::HttpWatcher.new(@default_options)
|
20
|
+
assert_equal(false, watcher.watch_it!)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_simple_match
|
24
|
+
@default_options[:content_match] = TEST_URL_TEXT
|
25
|
+
watcher = Watcher::HttpWatcher.new(@default_options)
|
26
|
+
assert_equal(false, watcher.watch_it!)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_simple_response
|
30
|
+
@default_options[:response] = '200'
|
31
|
+
watcher = Watcher::HttpWatcher.new(@default_options)
|
32
|
+
assert_equal(false, watcher.watch_it!)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_404_response
|
36
|
+
@default_options[:url] = TEST_URL + '/narfnarf'
|
37
|
+
@default_options[:response] = '404'
|
38
|
+
watcher = Watcher::HttpWatcher.new(@default_options)
|
39
|
+
assert_equal(false, watcher.watch_it!)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_404_response_fail
|
43
|
+
@default_options[:url] = TEST_URL + '/narfnarf'
|
44
|
+
watcher = Watcher::HttpWatcher.new(@default_options)
|
45
|
+
assert_kind_of(String, watcher.watch_it!)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_simple_match_fail
|
49
|
+
@default_options[:content_match] = 'grubellnurf'
|
50
|
+
watcher = Watcher::HttpWatcher.new(@default_options)
|
51
|
+
assert_kind_of(String, watcher.watch_it!)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_illegal_open_fail
|
55
|
+
watcher = Watcher::HttpWatcher.new(
|
56
|
+
:url => 'http://www.gurgl.gurl/',
|
57
|
+
:actions => 'default',
|
58
|
+
:content_match => 'grubellnurf'
|
59
|
+
)
|
60
|
+
assert_kind_of(String, watcher.watch_it!)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
PIDFILE = 'test.pid'
|
4
|
+
|
5
|
+
class KillProcessTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@killer = WatcherAction::KillProcess.new(:pidfile => PIDFILE)
|
9
|
+
# Fork a dummy process that we can kill
|
10
|
+
@pid = Process.fork { loop { sleep 1 }}
|
11
|
+
@proc = Process.detach(@pid)
|
12
|
+
File.open(PIDFILE, 'w') { |io| io << @pid }
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
FileUtils.remove(PIDFILE) if(File.exists?(PIDFILE))
|
17
|
+
@proc.terminate! if(@proc.status != false)
|
18
|
+
rescue Exception => e
|
19
|
+
puts "! unclean teardown #{e}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_killer
|
23
|
+
assert_not_equal(false, @proc.status)
|
24
|
+
@killer.execute(WatcherEvent.new)
|
25
|
+
sleep 1 # Wait for the sleep - the ruby process will handle the kill only then
|
26
|
+
assert_equal(false, @proc.status)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class LogWatcherTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def logfile
|
6
|
+
File.expand_path(File.join(File.dirname(__FILE__), 'log_test.tmp'))
|
7
|
+
end
|
8
|
+
|
9
|
+
def setup
|
10
|
+
FileUtils.remove(logfile) if(File.exists?(logfile))
|
11
|
+
File.open(logfile, 'w') { |io| io << 'test' }
|
12
|
+
@watcher = Watcher::LogWatcher.new(
|
13
|
+
:logfile => logfile,
|
14
|
+
:match => 'da_test',
|
15
|
+
:interval_first => '1',
|
16
|
+
:interval_max => '1'
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
@watcher.cleanup
|
22
|
+
FileUtils.remove(logfile) if(File.exists?(logfile))
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_watcher_plain
|
26
|
+
assert_equal(false, @watcher.watch_it!)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_watcher_trigger
|
30
|
+
File.open(logfile, 'a') do |io|
|
31
|
+
20.times { io << 'nothing special' }
|
32
|
+
io << 'da_test'
|
33
|
+
end
|
34
|
+
sleep 2
|
35
|
+
assert_kind_of(String, @watcher.watch_it!)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
module Watcher
|
4
|
+
class DummyWatcher < Watcher::Base
|
5
|
+
def initialize(config)
|
6
|
+
@watchit = config[:watchit]
|
7
|
+
end
|
8
|
+
def watch_it!
|
9
|
+
@watchit
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module WatcherAction
|
16
|
+
class DummyAction
|
17
|
+
def initialize(config)
|
18
|
+
end
|
19
|
+
def execute(event)
|
20
|
+
@executed = true
|
21
|
+
raise(Exception) unless(event.is_a?(WatcherEvent))
|
22
|
+
raise(ArgumentError, "Boom!")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class WatchdoggerTest < Test::Unit::TestCase
|
28
|
+
|
29
|
+
def setup
|
30
|
+
Watcher.instance_variable_set(:@registered_watchers, nil)
|
31
|
+
WatcherAction.instance_variable_set(:@registered_actions, nil)
|
32
|
+
WatcherAction.register('default', { :type => 'dummy_action' })
|
33
|
+
WatcherAction.register('log_action', { 'type' => :log_action })
|
34
|
+
Watcher.register('dummy', { :type => 'dummy_watcher', 'actions' => [ :default, :log_action ] })
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_create_watcher
|
38
|
+
watchers = Watcher.instance_variable_get(:@registered_watchers)
|
39
|
+
assert_equal(1, watchers.size)
|
40
|
+
assert_kind_of(Watcher::DummyWatcher, watchers.first)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_watcher_actions
|
44
|
+
actions = Watcher.instance_variable_get(:@registered_watchers).first.send(:actions)
|
45
|
+
assert_equal([:default, :log_action], actions)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_registered_action
|
49
|
+
actions = WatcherAction.instance_variable_get(:@registered_actions)
|
50
|
+
assert_equal(2, actions.size)
|
51
|
+
assert_kind_of(WatcherAction::DummyAction, actions[:default])
|
52
|
+
assert_kind_of(WatcherAction::LogAction, actions[:log_action])
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_run_action
|
56
|
+
event = WatcherEvent.new
|
57
|
+
event.timestamp = Time.now
|
58
|
+
event.message = "TEST MESSAGE"
|
59
|
+
event.watcher = "TEST"
|
60
|
+
assert_equal(false, WatcherAction.run_action('default', event))
|
61
|
+
assert_equal(true, action_status('default'))
|
62
|
+
WatcherAction.run_action('log_action', event)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_run_watcher
|
66
|
+
assert_nothing_raised { Watcher.watch_all! }
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_run_watcher_execute
|
70
|
+
assert_equal(nil, action_status('default'))
|
71
|
+
Watcher.register('dummy2', { 'type' => :dummy_watcher, 'actions' => :default, :watchit => 'Fail' })
|
72
|
+
Watcher.watch_all!
|
73
|
+
assert_equal(true, action_status('default'))
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def action_status(name)
|
79
|
+
action = WatcherAction.instance_variable_get(:@registered_actions).get_value(name)
|
80
|
+
action.instance_variable_get(:@executed)
|
81
|
+
end
|
82
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: averell23-watchdogger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Hahn
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-16 00:00:00 -07:00
|
13
|
+
default_executable: watchdogger
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: file-tail
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.0.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: averell23-assit
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.2
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: rmail
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.0.0
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: builder
|
47
|
+
type: :runtime
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.1.2
|
54
|
+
version:
|
55
|
+
description: A small flexible watchdog system to monitor servers.
|
56
|
+
email: ghub@limitedcreativity.org
|
57
|
+
executables:
|
58
|
+
- watchdogger
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
extra_rdoc_files:
|
62
|
+
- README.rdoc
|
63
|
+
- CHANGES
|
64
|
+
- LICENSE
|
65
|
+
- sample_config.yml
|
66
|
+
files:
|
67
|
+
- lib/dog_log.rb
|
68
|
+
- lib/watchdogger.rb
|
69
|
+
- lib/watcher
|
70
|
+
- lib/watcher/base.rb
|
71
|
+
- lib/watcher/http_watcher.rb
|
72
|
+
- lib/watcher/log_watcher.rb
|
73
|
+
- lib/watcher.rb
|
74
|
+
- lib/watcher_action
|
75
|
+
- lib/watcher_action/htpost.rb
|
76
|
+
- lib/watcher_action/kill_process.rb
|
77
|
+
- lib/watcher_action/log_action.rb
|
78
|
+
- lib/watcher_action/send_mail.rb
|
79
|
+
- lib/watcher_action.rb
|
80
|
+
- lib/watcher_event.rb
|
81
|
+
- test/http_watcher_test.rb
|
82
|
+
- test/kill_process_test.rb
|
83
|
+
- test/log_watcher_test.rb
|
84
|
+
- test/test_helper.rb
|
85
|
+
- test/watchdogger_test.rb
|
86
|
+
- bin/watchdogger
|
87
|
+
- README.rdoc
|
88
|
+
- CHANGES
|
89
|
+
- LICENSE
|
90
|
+
- sample_config.yml
|
91
|
+
has_rdoc: true
|
92
|
+
homepage: http://averell23.github.com/watchdogger
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options:
|
95
|
+
- --inline-source
|
96
|
+
- --charset=UTF-8
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: "0"
|
104
|
+
version:
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: "0"
|
110
|
+
version:
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.2.0
|
115
|
+
signing_key:
|
116
|
+
specification_version: 2
|
117
|
+
summary: Simple and flexible watchdog running on Ruby.
|
118
|
+
test_files: []
|
119
|
+
|