-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a8faf8d
commit 81693c8
Showing
10 changed files
with
254 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
module DaemonKit | ||
module ErrorHandlers | ||
# Error handlers in DaemonKit are used by the #Safety class. Any | ||
# error handler has to support the interface provided by this | ||
# class. It's also required that safety handlers implement a | ||
# singleton approach (handled by default by #Base). | ||
class Base | ||
|
||
class << self | ||
|
||
@instance = nil | ||
|
||
def instance | ||
@instance ||= new | ||
end | ||
private :new | ||
|
||
# When we're inherited, immediately register the handler with | ||
# the safety net | ||
def inherited( child ) #:nodoc: | ||
Safety.register_error_handler( child ) | ||
end | ||
end | ||
|
||
# Error handlers should overwrite this method and implement | ||
# their own reporting method. | ||
def handle_exception( exception ) | ||
raise NoMethodError, "Error handler doesn't support #handle_exception" | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
require 'net/http' | ||
|
||
module DaemonKit | ||
module ErrorHandlers | ||
# Error reporting via Hoptoad. | ||
class Hoptoad < Base | ||
|
||
# Your hoptoad API key | ||
@api_key = nil | ||
attr_accessor :api_key | ||
|
||
def handle_exception( exception ) | ||
headers = { | ||
'Content-type' => 'application/x-yaml', | ||
'Accept' => 'text/xml, application/xml' | ||
} | ||
|
||
http = Net::HTTP.new( url.host, url.port ) | ||
data = clean_exception( exception ) | ||
|
||
response = begin | ||
http.post( url.path, data.to_yaml, headers ) | ||
rescue TimoutError => e | ||
DaemonKit.logger.error("Timeout while contacting the Hoptoad server.") | ||
nil | ||
end | ||
case response | ||
when Net::HTTPSuccess then | ||
DaemonKit.logger.info "Hoptoad Success: #{response.class}" | ||
else | ||
DaemonKit.logger.error "Hoptoad Failure: #{response.class}\n#{response.body if response.respond_to? :body}" | ||
end | ||
end | ||
|
||
def url | ||
URI.parse("http://hoptoadapp.com/notices/") | ||
end | ||
|
||
def clean_exception( exception ) | ||
data = { | ||
:api_key => self.api_key, | ||
:error_class => exception.class.name, | ||
:error_message => "#{exception.class.name}: #{exception.message}", | ||
:backtrace => exception.backtrace, | ||
:environment => ENV.to_hash, | ||
:request => [], | ||
:session => [] | ||
} | ||
|
||
stringify_keys( data ) | ||
end | ||
|
||
def stringify_keys(hash) #:nodoc: | ||
hash.inject({}) do |h, pair| | ||
h[pair.first.to_s] = pair.last.is_a?(Hash) ? stringify_keys(pair.last) : pair.last | ||
h | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
require 'net/smtp' | ||
|
||
module DaemonKit | ||
module ErrorHandlers | ||
# Send an email notification of the exception via SMTP | ||
class Mail < Base | ||
|
||
# SMTP hostname | ||
@host = 'localhost' | ||
attr_accessor :host | ||
|
||
# Recipients of the notification | ||
@recipients = [] | ||
attr_accessor :recipients | ||
|
||
# Subject prefix | ||
@prefix = '[DAEMON-KIT]' | ||
attr_accessor :prefix | ||
|
||
# Sender address | ||
@sender = 'daemon-kit' | ||
attr_accessor :sender | ||
|
||
def handle_exception( exception ) | ||
email = <<EOF | ||
To: #{self.recipients.map { |r| '<' + r + '>' }.join(', ')} | ||
From: <#{self.sender}> | ||
Subject: #{self.prefix} #{exception.message} | ||
Date: #{Time.now} | ||
DaemonKit caught an exception inside #{DaemonKit.configuration.daemon_name}. | ||
Message: #{exception.message} | ||
Backtrace: | ||
#{exception.backtrace.join("\n ")} | ||
Environment: #{ENV.inspect} | ||
EOF | ||
begin | ||
Net::SMTP.start( self.host ) do |smtp| | ||
smtp.send_message( email, self.sender, self.recipients ) | ||
end | ||
rescue | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
module DaemonKit | ||
# Provides a wrapper for running code inside a 'safety net' Any | ||
# exceptions raised inside a safety net is handled and reported via | ||
# loggers, email or Hoptoad. | ||
# | ||
# The safety net can be configured via DaemonKit.config.safety, | ||
# which holds the only instance of the safety net. | ||
class Safety | ||
|
||
# Who get's notified. | ||
@handler = nil | ||
attr_accessor :handler | ||
|
||
# Registered error handlers | ||
@error_handlers = {} | ||
attr_reader :error_handlers | ||
|
||
class << self | ||
|
||
# Singleton | ||
@instance = nil | ||
|
||
def instance | ||
@instance ||= new | ||
end | ||
private :new | ||
|
||
# Run the provided block inside a safety net. | ||
def run(&block) | ||
self.instance.run(&block) | ||
end | ||
|
||
def register_error_handler( klass ) | ||
name = klass.to_s.split('::').last.downcase | ||
|
||
DaemonKit.logger.debug( "Registering error handler '#{name}' (#{klass})" ) if DaemonKit.logger | ||
|
||
instance.instance_eval( <<-EOF, __FILE__, __LINE__ ) | ||
def #{name} | ||
@#{name} ||= #{klass}.instance | ||
end | ||
EOF | ||
end | ||
end | ||
|
||
# Run the provided block inside a safety net. | ||
def run(&block) | ||
begin | ||
block.call | ||
rescue => e | ||
# Log | ||
DaemonKit.logger.fatal "Safety net caught exception: #{e.message}" | ||
DaemonKit.logger.fatal "Backtrace: #{e.backtrace.join("\n ")}" | ||
|
||
get_handler.handle_exception( e ) if get_handler | ||
end | ||
end | ||
|
||
def get_handler | ||
if @handler && self.respond_to?( @handler ) | ||
h = send( @handler ) | ||
return h if h.class.ancestors.include?( DaemonKit::ErrorHandlers::Base ) | ||
end | ||
|
||
return nil | ||
end | ||
end | ||
end | ||
|
||
class Object | ||
class << self | ||
def safely(&block) | ||
DaemonKit::Safety.run(&block) | ||
end | ||
end | ||
|
||
def safely(&block) | ||
DaemonKit::Safety.run(&block) | ||
end | ||
end | ||
|
||
# Load our error handlers | ||
require 'daemon_kit/error_handlers/base' | ||
require 'daemon_kit/error_handlers/mail' | ||
require 'daemon_kit/error_handlers/hoptoad' |