exception_notification_more_info 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Appraisals +7 -0
- data/CHANGELOG.rdoc +141 -0
- data/CODE_OF_CONDUCT.md +22 -0
- data/CONTRIBUTING.md +42 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +839 -0
- data/Rakefile +23 -0
- data/examples/sinatra/Gemfile +8 -0
- data/examples/sinatra/Gemfile.lock +95 -0
- data/examples/sinatra/Procfile +2 -0
- data/examples/sinatra/README.md +11 -0
- data/examples/sinatra/config.ru +3 -0
- data/examples/sinatra/sinatra_app.rb +32 -0
- data/exception_notification_more_info.gemspec +34 -0
- data/gemfiles/rails4_0.gemfile +7 -0
- data/gemfiles/rails4_1.gemfile +7 -0
- data/gemfiles/rails4_2.gemfile +7 -0
- data/lib/exception_notification.rb +11 -0
- data/lib/exception_notification/rack.rb +59 -0
- data/lib/exception_notification/rails.rb +8 -0
- data/lib/exception_notification/resque.rb +24 -0
- data/lib/exception_notification/sidekiq.rb +31 -0
- data/lib/exception_notifier.rb +121 -0
- data/lib/exception_notifier/base_notifier.rb +25 -0
- data/lib/exception_notifier/campfire_notifier.rb +36 -0
- data/lib/exception_notifier/email_notifier.rb +204 -0
- data/lib/exception_notifier/hipchat_notifier.rb +45 -0
- data/lib/exception_notifier/irc_notifier.rb +51 -0
- data/lib/exception_notifier/modules/backtrace_cleaner.rb +13 -0
- data/lib/exception_notifier/notifier.rb +16 -0
- data/lib/exception_notifier/slack_notifier.rb +73 -0
- data/lib/exception_notifier/views/exception_notifier/_backtrace.html.erb +3 -0
- data/lib/exception_notifier/views/exception_notifier/_backtrace.text.erb +1 -0
- data/lib/exception_notifier/views/exception_notifier/_data.html.erb +6 -0
- data/lib/exception_notifier/views/exception_notifier/_data.text.erb +1 -0
- data/lib/exception_notifier/views/exception_notifier/_environment.html.erb +10 -0
- data/lib/exception_notifier/views/exception_notifier/_environment.text.erb +5 -0
- data/lib/exception_notifier/views/exception_notifier/_request.html.erb +36 -0
- data/lib/exception_notifier/views/exception_notifier/_request.text.erb +10 -0
- data/lib/exception_notifier/views/exception_notifier/_session.html.erb +10 -0
- data/lib/exception_notifier/views/exception_notifier/_session.text.erb +2 -0
- data/lib/exception_notifier/views/exception_notifier/_title.html.erb +3 -0
- data/lib/exception_notifier/views/exception_notifier/_title.text.erb +3 -0
- data/lib/exception_notifier/views/exception_notifier/background_exception_notification.html.erb +53 -0
- data/lib/exception_notifier/views/exception_notifier/background_exception_notification.text.erb +14 -0
- data/lib/exception_notifier/views/exception_notifier/exception_notification.html.erb +54 -0
- data/lib/exception_notifier/views/exception_notifier/exception_notification.text.erb +24 -0
- data/lib/exception_notifier/webhook_notifier.rb +47 -0
- data/lib/generators/exception_notification/install_generator.rb +15 -0
- data/lib/generators/exception_notification/templates/exception_notification.rb +53 -0
- data/test/dummy/.gitignore +4 -0
- data/test/dummy/Gemfile +34 -0
- data/test/dummy/Gemfile.lock +137 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/posts_controller.rb +30 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/posts_helper.rb +2 -0
- data/test/dummy/app/models/post.rb +2 -0
- data/test/dummy/app/views/exception_notifier/_new_bkg_section.html.erb +1 -0
- data/test/dummy/app/views/exception_notifier/_new_bkg_section.text.erb +1 -0
- data/test/dummy/app/views/exception_notifier/_new_section.html.erb +1 -0
- data/test/dummy/app/views/exception_notifier/_new_section.text.erb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/posts/_form.html.erb +0 -0
- data/test/dummy/app/views/posts/new.html.erb +0 -0
- data/test/dummy/app/views/posts/show.html.erb +0 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +42 -0
- data/test/dummy/config/boot.rb +6 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +17 -0
- data/test/dummy/config/environments/development.rb +25 -0
- data/test/dummy/config/environments/production.rb +50 -0
- data/test/dummy/config/environments/test.rb +38 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +8 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/db/migrate/20110729022608_create_posts.rb +15 -0
- data/test/dummy/db/schema.rb +24 -0
- data/test/dummy/db/seeds.rb +7 -0
- data/test/dummy/lib/tasks/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/images/rails.png +0 -0
- data/test/dummy/public/index.html +239 -0
- data/test/dummy/public/javascripts/application.js +2 -0
- data/test/dummy/public/javascripts/controls.js +965 -0
- data/test/dummy/public/javascripts/dragdrop.js +974 -0
- data/test/dummy/public/javascripts/effects.js +1123 -0
- data/test/dummy/public/javascripts/prototype.js +6001 -0
- data/test/dummy/public/javascripts/rails.js +191 -0
- data/test/dummy/public/robots.txt +5 -0
- data/test/dummy/public/stylesheets/.gitkeep +0 -0
- data/test/dummy/public/stylesheets/scaffold.css +56 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/test/fixtures/posts.yml +11 -0
- data/test/dummy/test/functional/posts_controller_test.rb +224 -0
- data/test/dummy/test/test_helper.rb +13 -0
- data/test/exception_notification/rack_test.rb +20 -0
- data/test/exception_notifier/campfire_notifier_test.rb +100 -0
- data/test/exception_notifier/email_notifier_test.rb +185 -0
- data/test/exception_notifier/hipchat_notifier_test.rb +177 -0
- data/test/exception_notifier/irc_notifier_test.rb +121 -0
- data/test/exception_notifier/sidekiq_test.rb +27 -0
- data/test/exception_notifier/slack_notifier_test.rb +179 -0
- data/test/exception_notifier/webhook_notifier_test.rb +68 -0
- data/test/exception_notifier_test.rb +103 -0
- data/test/test_helper.rb +18 -0
- metadata +428 -0
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
Bundler::GemHelper.install_tasks
|
4
|
+
require 'appraisal'
|
5
|
+
|
6
|
+
require 'rake/testtask'
|
7
|
+
|
8
|
+
task 'setup_dummy_app' do
|
9
|
+
unless File.exists? "test/dummy/db/test.sqlite3"
|
10
|
+
Bundler.with_clean_env do
|
11
|
+
sh "cd test/dummy; bundle; bundle exec rake db:migrate; bundle exec rake db:test:prepare; cd ../../;"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Rake::TestTask.new(:test) do |t|
|
17
|
+
t.libs << 'lib'
|
18
|
+
t.libs << 'test'
|
19
|
+
t.pattern = 'test/**/*_test.rb'
|
20
|
+
t.verbose = true
|
21
|
+
end
|
22
|
+
|
23
|
+
task :default => [:setup_dummy_app, :test]
|
@@ -0,0 +1,95 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../../
|
3
|
+
specs:
|
4
|
+
exception_notification (3.0.1)
|
5
|
+
actionmailer (>= 3.0.4)
|
6
|
+
activesupport (>= 3.0.4)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionmailer (3.2.13)
|
12
|
+
actionpack (= 3.2.13)
|
13
|
+
mail (~> 2.5.3)
|
14
|
+
actionpack (3.2.13)
|
15
|
+
activemodel (= 3.2.13)
|
16
|
+
activesupport (= 3.2.13)
|
17
|
+
builder (~> 3.0.0)
|
18
|
+
erubis (~> 2.7.0)
|
19
|
+
journey (~> 1.0.4)
|
20
|
+
rack (~> 1.4.5)
|
21
|
+
rack-cache (~> 1.2)
|
22
|
+
rack-test (~> 0.6.1)
|
23
|
+
sprockets (~> 2.2.1)
|
24
|
+
activemodel (3.2.13)
|
25
|
+
activesupport (= 3.2.13)
|
26
|
+
builder (~> 3.0.0)
|
27
|
+
activesupport (3.2.13)
|
28
|
+
i18n (= 0.6.1)
|
29
|
+
multi_json (~> 1.0)
|
30
|
+
builder (3.0.4)
|
31
|
+
daemons (1.1.9)
|
32
|
+
erubis (2.7.0)
|
33
|
+
eventmachine (1.0.3)
|
34
|
+
foreman (0.61.0)
|
35
|
+
thor (>= 0.13.6)
|
36
|
+
haml (4.0.2)
|
37
|
+
tilt
|
38
|
+
hike (1.2.1)
|
39
|
+
i18n (0.6.1)
|
40
|
+
journey (1.0.4)
|
41
|
+
mail (2.5.3)
|
42
|
+
i18n (>= 0.4.0)
|
43
|
+
mime-types (~> 1.16)
|
44
|
+
treetop (~> 1.4.8)
|
45
|
+
mailcatcher (0.5.11)
|
46
|
+
activesupport (~> 3.0)
|
47
|
+
eventmachine (~> 1.0.0)
|
48
|
+
haml (>= 3.1, < 5)
|
49
|
+
mail (~> 2.3)
|
50
|
+
sinatra (~> 1.2)
|
51
|
+
skinny (~> 0.2.3)
|
52
|
+
sqlite3 (~> 1.3)
|
53
|
+
thin (~> 1.5.0)
|
54
|
+
mime-types (1.22)
|
55
|
+
multi_json (1.7.2)
|
56
|
+
polyglot (0.3.3)
|
57
|
+
rack (1.4.5)
|
58
|
+
rack-cache (1.2)
|
59
|
+
rack (>= 0.4)
|
60
|
+
rack-protection (1.5.0)
|
61
|
+
rack
|
62
|
+
rack-test (0.6.2)
|
63
|
+
rack (>= 1.0)
|
64
|
+
sinatra (1.3.6)
|
65
|
+
rack (~> 1.4)
|
66
|
+
rack-protection (~> 1.3)
|
67
|
+
tilt (~> 1.3, >= 1.3.3)
|
68
|
+
skinny (0.2.3)
|
69
|
+
eventmachine (~> 1.0.0)
|
70
|
+
thin (~> 1.5.0)
|
71
|
+
sprockets (2.2.2)
|
72
|
+
hike (~> 1.2)
|
73
|
+
multi_json (~> 1.0)
|
74
|
+
rack (~> 1.0)
|
75
|
+
tilt (~> 1.1, != 1.3.0)
|
76
|
+
sqlite3 (1.3.7)
|
77
|
+
thin (1.5.1)
|
78
|
+
daemons (>= 1.0.9)
|
79
|
+
eventmachine (>= 0.12.6)
|
80
|
+
rack (>= 1.0.0)
|
81
|
+
thor (0.18.1)
|
82
|
+
tilt (1.3.6)
|
83
|
+
treetop (1.4.12)
|
84
|
+
polyglot
|
85
|
+
polyglot (>= 0.3.1)
|
86
|
+
|
87
|
+
PLATFORMS
|
88
|
+
ruby
|
89
|
+
|
90
|
+
DEPENDENCIES
|
91
|
+
exception_notification!
|
92
|
+
foreman
|
93
|
+
mailcatcher
|
94
|
+
sinatra (~> 1.3.5)
|
95
|
+
thin (~> 1.5.1)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Using Exception Notification with Sinatra
|
2
|
+
|
3
|
+
## Quick start
|
4
|
+
|
5
|
+
git clone git@github.com:smartinez87/exception_notification.git
|
6
|
+
cd exception_notification/examples/sinatra
|
7
|
+
bundle install
|
8
|
+
bundle exec foreman start
|
9
|
+
|
10
|
+
|
11
|
+
The last command starts two services, a smtp server and the sinatra app itself. Thus, visit [http://localhost:1080/](http://localhost:1080/) to check the emails sent and, in a separated tab, visit [http://localhost:3000](http://localhost:3000) and cause some errors. For more info, use the [source](https://github.com/smartinez87/exception_notification/blob/master/examples/sinatra/sinatra_app.rb) Luke.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'sinatra/base'
|
4
|
+
require 'exception_notification'
|
5
|
+
|
6
|
+
class SinatraApp < Sinatra::Base
|
7
|
+
use Rack::Config do |env|
|
8
|
+
env["action_dispatch.parameter_filter"] = [:password] # This is highly recommended. It will prevent the ExceptionNotification email from including your users' passwords
|
9
|
+
end
|
10
|
+
|
11
|
+
use ExceptionNotification::Rack,
|
12
|
+
:email => {
|
13
|
+
:email_prefix => "[Example] ",
|
14
|
+
:sender_address => %{"notifier" <notifier@example.com>},
|
15
|
+
:exception_recipients => %w{exceptions@example.com},
|
16
|
+
:smtp_settings => { :address => "localhost", :port => 1025 }
|
17
|
+
}
|
18
|
+
|
19
|
+
get '/' do
|
20
|
+
raise StandardError, "ERROR: #{params[:error]}" unless params[:error].blank?
|
21
|
+
'Everything is fine! Now, lets break things clicking <a href="/?error=ops"> here </a>. Dont forget to see the emails at <a href="http://localhost:1080">mailcatcher</a> !'
|
22
|
+
end
|
23
|
+
|
24
|
+
get '/background_notification' do
|
25
|
+
begin
|
26
|
+
1/0
|
27
|
+
rescue Exception => e
|
28
|
+
ExceptionNotifier.notify_exception(e, :data => {:msg => "Cannot divide by zero!"})
|
29
|
+
end
|
30
|
+
'Check email at <a href="http://localhost:1080">mailcatcher</a>.'
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'exception_notification_more_info'
|
3
|
+
s.version = '1.0.0'
|
4
|
+
s.authors = ["Jamis Buck", "Josh Peek", "Hyunjae Park"]
|
5
|
+
s.summary = "Exception notification for Rails apps(+ More Info!)"
|
6
|
+
s.homepage = "https://smartinez87.github.io/exception_notification/"
|
7
|
+
s.email = "dev.hyunjae.park@gmail.com"
|
8
|
+
s.license = "MIT"
|
9
|
+
|
10
|
+
s.required_ruby_version = '>= 2.0'
|
11
|
+
s.required_rubygems_version = '>= 1.8.11'
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.files -= `git ls-files -- .??*`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- test`.split("\n")
|
16
|
+
s.require_path = 'lib'
|
17
|
+
|
18
|
+
s.add_dependency("actionmailer", "~> 4.0")
|
19
|
+
s.add_dependency("activesupport", "~> 4.0")
|
20
|
+
|
21
|
+
s.add_development_dependency "rails", "~> 4.0"
|
22
|
+
s.add_development_dependency "resque", "~> 1.2.0"
|
23
|
+
# Sidekiq 3.2.2 does not support Ruby 1.9.
|
24
|
+
s.add_development_dependency "sidekiq", "~> 3.0.0", "< 3.2.2"
|
25
|
+
s.add_development_dependency "tinder", "~> 1.8"
|
26
|
+
s.add_development_dependency "httparty", "~> 0.10.2"
|
27
|
+
s.add_development_dependency "mocha", ">= 0.13.0"
|
28
|
+
s.add_development_dependency "sqlite3", ">= 1.3.4"
|
29
|
+
s.add_development_dependency "coveralls", "~> 0.8.2"
|
30
|
+
s.add_development_dependency "appraisal", "~> 2.0.0"
|
31
|
+
s.add_development_dependency "hipchat", ">= 1.0.0"
|
32
|
+
s.add_development_dependency "carrier-pigeon", ">= 0.7.0"
|
33
|
+
s.add_development_dependency "slack-notifier", ">= 1.0.0"
|
34
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'exception_notifier'
|
2
|
+
require 'exception_notification/rack'
|
3
|
+
|
4
|
+
module ExceptionNotification
|
5
|
+
# Alternative way to setup ExceptionNotification.
|
6
|
+
# Run 'rails generate exception_notification:install' to create
|
7
|
+
# a fresh initializer with all configuration values.
|
8
|
+
def self.configure
|
9
|
+
yield ExceptionNotifier
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module ExceptionNotification
|
2
|
+
class Rack
|
3
|
+
class CascadePassException < Exception; end
|
4
|
+
|
5
|
+
def initialize(app, options = {})
|
6
|
+
@app = app
|
7
|
+
|
8
|
+
ExceptionNotifier.ignored_exceptions = options.delete(:ignore_exceptions) if options.key?(:ignore_exceptions)
|
9
|
+
|
10
|
+
if options.key?(:ignore_if)
|
11
|
+
rack_ignore = options.delete(:ignore_if)
|
12
|
+
ExceptionNotifier.ignore_if do |exception, options|
|
13
|
+
options.key?(:env) && rack_ignore.call(options[:env], exception)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if options.key?(:ignore_crawlers)
|
18
|
+
ignore_crawlers = options.delete(:ignore_crawlers)
|
19
|
+
ExceptionNotifier.ignore_if do |exception, options|
|
20
|
+
options.key?(:env) && from_crawler(options[:env], ignore_crawlers)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
@ignore_cascade_pass = options.delete(:ignore_cascade_pass) { true }
|
25
|
+
|
26
|
+
options.each do |notifier_name, options|
|
27
|
+
ExceptionNotifier.register_exception_notifier(notifier_name, options)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def call(env)
|
32
|
+
_, headers, _ = response = @app.call(env)
|
33
|
+
|
34
|
+
if !@ignore_cascade_pass && headers['X-Cascade'] == 'pass'
|
35
|
+
msg = "This exception means that the preceding Rack middleware set the 'X-Cascade' header to 'pass' -- in " <<
|
36
|
+
"Rails, this often means that the route was not found (404 error)."
|
37
|
+
raise CascadePassException, msg
|
38
|
+
end
|
39
|
+
|
40
|
+
response
|
41
|
+
rescue Exception => exception
|
42
|
+
if ExceptionNotifier.notify_exception(exception, :env => env)
|
43
|
+
env['exception_notifier.delivered'] = true
|
44
|
+
end
|
45
|
+
|
46
|
+
raise exception unless exception.is_a?(CascadePassException)
|
47
|
+
response
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def from_crawler(env, ignored_crawlers)
|
53
|
+
agent = env['HTTP_USER_AGENT']
|
54
|
+
Array(ignored_crawlers).any? do |crawler|
|
55
|
+
agent =~ Regexp.new(crawler)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'resque/failure/base'
|
2
|
+
|
3
|
+
module ExceptionNotification
|
4
|
+
class Resque < Resque::Failure::Base
|
5
|
+
|
6
|
+
def self.count
|
7
|
+
Stat[:failed]
|
8
|
+
end
|
9
|
+
|
10
|
+
def save
|
11
|
+
data = {
|
12
|
+
:failed_at => Time.now.to_s,
|
13
|
+
:queue => queue,
|
14
|
+
:worker => worker.to_s,
|
15
|
+
:payload => payload,
|
16
|
+
:error_class => exception.class.name,
|
17
|
+
:error_message => exception.message
|
18
|
+
}
|
19
|
+
|
20
|
+
ExceptionNotifier.notify_exception(exception, :data => { :resque => data })
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
# Note: this class is only needed for Sidekiq version < 3.
|
4
|
+
module ExceptionNotification
|
5
|
+
class Sidekiq
|
6
|
+
|
7
|
+
def call(worker, msg, queue)
|
8
|
+
begin
|
9
|
+
yield
|
10
|
+
rescue Exception => exception
|
11
|
+
ExceptionNotifier.notify_exception(exception, :data => { :sidekiq => msg })
|
12
|
+
raise exception
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if ::Sidekiq::VERSION < '3'
|
20
|
+
::Sidekiq.configure_server do |config|
|
21
|
+
config.server_middleware do |chain|
|
22
|
+
chain.add ::ExceptionNotification::Sidekiq
|
23
|
+
end
|
24
|
+
end
|
25
|
+
else
|
26
|
+
::Sidekiq.configure_server do |config|
|
27
|
+
config.error_handlers << Proc.new { |ex, context|
|
28
|
+
ExceptionNotifier.notify_exception(ex, :data => { :sidekiq => context })
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'active_support/core_ext/string/inflections'
|
3
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
4
|
+
require 'exception_notifier/base_notifier'
|
5
|
+
|
6
|
+
module ExceptionNotifier
|
7
|
+
|
8
|
+
autoload :BacktraceCleaner, 'exception_notifier/modules/backtrace_cleaner'
|
9
|
+
|
10
|
+
autoload :Notifier, 'exception_notifier/notifier'
|
11
|
+
autoload :EmailNotifier, 'exception_notifier/email_notifier'
|
12
|
+
autoload :CampfireNotifier, 'exception_notifier/campfire_notifier'
|
13
|
+
autoload :HipchatNotifier, 'exception_notifier/hipchat_notifier'
|
14
|
+
autoload :WebhookNotifier, 'exception_notifier/webhook_notifier'
|
15
|
+
autoload :IrcNotifier, 'exception_notifier/irc_notifier'
|
16
|
+
autoload :SlackNotifier, 'exception_notifier/slack_notifier'
|
17
|
+
|
18
|
+
class UndefinedNotifierError < StandardError; end
|
19
|
+
|
20
|
+
# Define logger
|
21
|
+
mattr_accessor :logger
|
22
|
+
@@logger = Logger.new(STDOUT)
|
23
|
+
|
24
|
+
# Define a set of exceptions to be ignored, ie, dont send notifications when any of them are raised.
|
25
|
+
mattr_accessor :ignored_exceptions
|
26
|
+
@@ignored_exceptions = %w{ActiveRecord::RecordNotFound AbstractController::ActionNotFound ActionController::RoutingError ActionController::UnknownFormat}
|
27
|
+
|
28
|
+
mattr_accessor :testing_mode
|
29
|
+
@@testing_mode = false
|
30
|
+
|
31
|
+
class << self
|
32
|
+
# Store conditions that decide when exceptions must be ignored or not.
|
33
|
+
@@ignores = []
|
34
|
+
|
35
|
+
# Store notifiers that send notifications when exceptions are raised.
|
36
|
+
@@notifiers = {}
|
37
|
+
|
38
|
+
def testing_mode!
|
39
|
+
self.testing_mode = true
|
40
|
+
end
|
41
|
+
|
42
|
+
def notify_exception(exception, options={})
|
43
|
+
return false if ignored_exception?(options[:ignore_exceptions], exception)
|
44
|
+
return false if ignored?(exception, options)
|
45
|
+
selected_notifiers = options.delete(:notifiers) || notifiers
|
46
|
+
[*selected_notifiers].each do |notifier|
|
47
|
+
fire_notification(notifier, exception, options.dup)
|
48
|
+
end
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def register_exception_notifier(name, notifier_or_options)
|
53
|
+
if notifier_or_options.respond_to?(:call)
|
54
|
+
@@notifiers[name] = notifier_or_options
|
55
|
+
elsif notifier_or_options.is_a?(Hash)
|
56
|
+
create_and_register_notifier(name, notifier_or_options)
|
57
|
+
else
|
58
|
+
raise ArgumentError, "Invalid notifier '#{name}' defined as #{notifier_or_options.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
alias add_notifier register_exception_notifier
|
62
|
+
|
63
|
+
def unregister_exception_notifier(name)
|
64
|
+
@@notifiers.delete(name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def registered_exception_notifier(name)
|
68
|
+
@@notifiers[name]
|
69
|
+
end
|
70
|
+
|
71
|
+
def notifiers
|
72
|
+
@@notifiers.keys
|
73
|
+
end
|
74
|
+
|
75
|
+
# Adds a condition to decide when an exception must be ignored or not.
|
76
|
+
#
|
77
|
+
# ExceptionNotifier.ignore_if do |exception, options|
|
78
|
+
# not Rails.env.production?
|
79
|
+
# end
|
80
|
+
def ignore_if(&block)
|
81
|
+
@@ignores << block
|
82
|
+
end
|
83
|
+
|
84
|
+
def clear_ignore_conditions!
|
85
|
+
@@ignores.clear
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
def ignored?(exception, options)
|
90
|
+
@@ignores.any?{ |condition| condition.call(exception, options) }
|
91
|
+
rescue Exception => e
|
92
|
+
raise e if @@testing_mode
|
93
|
+
|
94
|
+
logger.warn "An error occurred when evaluating an ignore condition. #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
|
95
|
+
false
|
96
|
+
end
|
97
|
+
|
98
|
+
def ignored_exception?(ignore_array, exception)
|
99
|
+
(Array(ignored_exceptions) + Array(ignore_array)).map(&:to_s).include?(exception.class.name)
|
100
|
+
end
|
101
|
+
|
102
|
+
def fire_notification(notifier_name, exception, options)
|
103
|
+
notifier = registered_exception_notifier(notifier_name)
|
104
|
+
notifier.call(exception, options)
|
105
|
+
rescue Exception => e
|
106
|
+
raise e if @@testing_mode
|
107
|
+
|
108
|
+
logger.warn "An error occurred when sending a notification using '#{notifier_name}' notifier. #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
|
109
|
+
false
|
110
|
+
end
|
111
|
+
|
112
|
+
def create_and_register_notifier(name, options)
|
113
|
+
notifier_classname = "#{name}_notifier".camelize
|
114
|
+
notifier_class = ExceptionNotifier.const_get(notifier_classname)
|
115
|
+
notifier = notifier_class.new(options)
|
116
|
+
register_exception_notifier(name, notifier)
|
117
|
+
rescue NameError => e
|
118
|
+
raise UndefinedNotifierError, "No notifier named '#{name}' was found. Please, revise your configuration options. Cause: #{e.message}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|