errorkit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +133 -0
- data/Rakefile +60 -0
- data/config/database.yml.example +19 -0
- data/errorkit.gemspec +25 -0
- data/lib/errorkit/config.rb +46 -0
- data/lib/errorkit/engine.rb +7 -0
- data/lib/errorkit/errors_controller.rb +49 -0
- data/lib/errorkit/errors_mailer.rb +43 -0
- data/lib/errorkit/ignorable_error.rb +3 -0
- data/lib/errorkit/version.rb +3 -0
- data/lib/errorkit.rb +86 -0
- data/lib/generators/errorkit/USAGE +19 -0
- data/lib/generators/errorkit/install_generator.rb +60 -0
- data/lib/generators/errorkit/templates/app/models/error.rb +9 -0
- data/lib/generators/errorkit/templates/app/views/errors/error_notification.html.erb +7 -0
- data/lib/generators/errorkit/templates/app/views/errors/show.html.erb +13 -0
- data/lib/generators/errorkit/templates/config/initializers/errorkit.rb +84 -0
- data/lib/generators/errorkit/templates/db/migrate/create_errors.rb +38 -0
- data/lib/generators/errorkit/templates/spec/models/error_spec.rb +18 -0
- data/spec/spec_helper.rb +16 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3b3a8d7d3ae4c413ca53a1f7d0463e80ddae34db
|
4
|
+
data.tar.gz: e55ce216c6f4d957e29883a3fde546fa52bd22cf
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: db9a77577712658b5af7d04aa64bca059343191d465deecad12a3b017c223cf1c8760daf8cd2fb1d770ab57693a55170d223c72fdeabd8a9414590fc9e26ab6a
|
7
|
+
data.tar.gz: 417b54060cd71254cd200e5b01729e34ea260780b056352886f99cafb9e95045a128b9809f37e42515fdd28936c6396391e06b6e2906cb70de74bf7cbb7e4a54
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jeff Rafter
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
# Errorkit
|
2
|
+
|
3
|
+
ErrorKit allows you to track errors within your application and generate a
|
4
|
+
notification when they happen.
|
5
|
+
|
6
|
+
ErrorKit is based on exception_notification and takes a similar approach. It allows
|
7
|
+
you to install Rack middleware that catches exceptions and allows you to notify a
|
8
|
+
list of recipients.
|
9
|
+
|
10
|
+
ErrorKit also allows you to record the errors to your database and resolve them
|
11
|
+
as necessary. This allows error handling to become an application concern and expects
|
12
|
+
that you will attach application specific information to the errors when possible
|
13
|
+
(such as the user that performed the action or the priority level of the error).
|
14
|
+
|
15
|
+
ErrorKit provides a generator to build the default Error model.
|
16
|
+
|
17
|
+
You can ignore specific exception classes and specific user agents. Additionally,
|
18
|
+
ErrorKit can throttle error notifications to prevent overwhelming your inbox.
|
19
|
+
|
20
|
+
Finally, ErrorKit keeps track of how many successful responses are made as well
|
21
|
+
so that it can track your error rate per server and per release.
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Add this line to your application's Gemfile:
|
26
|
+
|
27
|
+
gem 'errorkit'
|
28
|
+
|
29
|
+
And then execute:
|
30
|
+
|
31
|
+
$ bundle
|
32
|
+
|
33
|
+
Or install it yourself as:
|
34
|
+
|
35
|
+
$ gem install errorkit
|
36
|
+
|
37
|
+
## Usage
|
38
|
+
|
39
|
+
Once you have installed the gem, you need to run the generator:
|
40
|
+
|
41
|
+
$ rails g errorkit:install
|
42
|
+
|
43
|
+
After you run the generator you need to migrate the database:
|
44
|
+
|
45
|
+
$ rails db:migrate
|
46
|
+
|
47
|
+
You can override the default configuration in config/initializers/errorkit.rb.
|
48
|
+
|
49
|
+
## Custom Views
|
50
|
+
|
51
|
+
From this point you can customize most things. Errorkit handles errors
|
52
|
+
that occur within your application and displays a corresponding template.
|
53
|
+
By default, it uses app/views/errors/error.html.erb which you should
|
54
|
+
customize. If you want to have specific templates for specific pages
|
55
|
+
you can create them by name:
|
56
|
+
|
57
|
+
bad_request.html.erb
|
58
|
+
forbidden.html.erb
|
59
|
+
internal_server_error.html.erb
|
60
|
+
method_not_allowed.html.erb
|
61
|
+
not_acceptable.html.erb
|
62
|
+
not_found.html.erb
|
63
|
+
not_implemented.html.erb
|
64
|
+
unauthorized.html.erb
|
65
|
+
unprocessable_entity.html.erb
|
66
|
+
|
67
|
+
You can extend this list of defaults as well. See
|
68
|
+
http://guides.rubyonrails.org/layouts_and_rendering.html for more information.
|
69
|
+
|
70
|
+
It is also possible to customize the notification template found at
|
71
|
+
app/views/errors/notification.html.erb.
|
72
|
+
|
73
|
+
## Custom Errors Controller
|
74
|
+
|
75
|
+
You can override the errors_controller by creating a new one in your application:
|
76
|
+
|
77
|
+
class MyController < Errorkit::ErrorsController
|
78
|
+
end
|
79
|
+
|
80
|
+
You can even make this descend from your own application controller (though
|
81
|
+
this may generate additional errors if there is a problem in your controller)
|
82
|
+
|
83
|
+
class MyController < ApplicationController
|
84
|
+
def show
|
85
|
+
# You must implement show
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Once created, you must tell Errorkit to use this controller in the initializer:
|
90
|
+
|
91
|
+
config.errors_controller = MyController
|
92
|
+
|
93
|
+
## Custom Errors Mailer
|
94
|
+
|
95
|
+
You can override the errors_mailer by creating a new one in your application:
|
96
|
+
|
97
|
+
class MyMailer < Errorkit::ErrorsMailer
|
98
|
+
end
|
99
|
+
|
100
|
+
You can descend from ActionMailer::Base if you want to completely override the
|
101
|
+
behavior. However you must implement error_notification:
|
102
|
+
|
103
|
+
class MyMailer < ActionMailer::Base
|
104
|
+
def error_notification(error_id)
|
105
|
+
# You must implement error_notification
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
Once created, you must tell Errorkit to use this mailer in the initializer:
|
110
|
+
|
111
|
+
config.errors_mailer = MyMailer
|
112
|
+
|
113
|
+
## Contributing
|
114
|
+
|
115
|
+
1. Fork it
|
116
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
117
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
118
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
119
|
+
5. Create new Pull Request
|
120
|
+
|
121
|
+
## Acknowledgements
|
122
|
+
|
123
|
+
http://geekmonkey.org/articles/29-exception-applications-in-rails-3-2
|
124
|
+
https://github.com/sheerun/rails4-bootstrap/issues/26
|
125
|
+
https://github.com/sheerun/rails4-bootstrap/commit/5c2df5a108ad204bc407183b959bb355ff5ed53d
|
126
|
+
http://stackoverflow.com/questions/15459143/how-to-rescue-from-actiondispatchparamsparserparseerror-in-rails-4
|
127
|
+
https://github.com/mirego/gaffe
|
128
|
+
https://github.com/mirego/gaffe/blob/master/lib/gaffe/errors.rb
|
129
|
+
|
130
|
+
|
131
|
+
https://github.com/rails/rails/blob/f886fe2d8ccc900cde2629577e5c0be8c7d4c67f/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
|
132
|
+
https://github.com/rails/rails/blob/c2cb83b1447fee6cee496acd0816c0117b68b687/guides/source/layouts_and_rendering.md
|
133
|
+
http://stackoverflow.com/questions/15459143/how-to-rescue-from-actiondispatchparamsparserparseerror-in-rails-4
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
gem_name = :errorkit
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(spec: ["generator:cleanup", "generator:prepare", "generator:#{gem_name}"]) do |task|
|
7
|
+
task.pattern = "spec/**/*_spec.rb"
|
8
|
+
task.rspec_opts = "--color --drb"
|
9
|
+
task.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
namespace :spec do
|
13
|
+
RSpec::Core::RakeTask.new(database: ["generator:cleanup", "generator:prepare", "generator:database", "generator:#{gem_name}"]) do |task|
|
14
|
+
task.pattern = "spec/**/*_spec.rb"
|
15
|
+
task.verbose = true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
namespace :generator do
|
20
|
+
desc "Cleans up the sample app before running the generator"
|
21
|
+
task :cleanup do
|
22
|
+
FileUtils.rm_rf("spec/tmp/sample") if Dir.exist?("spec/tmp/sample") if ENV['SKIP_CLEANUP'].nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Prepare the sample app before running the generator"
|
26
|
+
task :prepare do
|
27
|
+
next if Dir.exist?("spec/tmp/sample")
|
28
|
+
|
29
|
+
FileUtils.mkdir_p("spec/tmp")
|
30
|
+
|
31
|
+
system "cd spec/tmp && rails new sample"
|
32
|
+
|
33
|
+
# bundle
|
34
|
+
gem_root = File.expand_path(File.dirname(__FILE__))
|
35
|
+
system "echo \"gem 'rspec-rails'\" >> spec/tmp/sample/Gemfile"
|
36
|
+
system "echo \"gem '#{gem_name}', :path => '#{gem_root}'\" >> spec/tmp/sample/Gemfile"
|
37
|
+
system "cd spec/tmp/sample && bundle install"
|
38
|
+
system "cd spec/tmp/sample && rails g rspec:install"
|
39
|
+
|
40
|
+
# Make a thing
|
41
|
+
system "cd spec/tmp/sample && rails g scaffold thing name:string mood:string"
|
42
|
+
end
|
43
|
+
|
44
|
+
# This task is not used unless you need to test the generator with an alternate database
|
45
|
+
# such as mysql or postgres. By default the sample application utilize sqlite3
|
46
|
+
desc "Prepares the application with an alternate database"
|
47
|
+
task :database do
|
48
|
+
puts "== Configuring the database =================================================="
|
49
|
+
system "cp config/database.yml.example spec/tmp/sample/config/database.yml"
|
50
|
+
system "cd spec/tmp/sample && rake db:migrate:reset"
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Run the #{gem_name} generator"
|
54
|
+
task gem_name do
|
55
|
+
system "cd spec/tmp/sample && rails g #{gem_name}:install --force && rake db:migrate db:test:prepare"
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
task :default => :spec
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# This file is not copied to or used by your Rails environment. The only time
|
2
|
+
# these settings are used is when you have executed rake test:database while
|
3
|
+
# running the tests for the gem (not from within Rails). This file makes
|
4
|
+
# it easy to test alternate database drivers with the gem. The
|
5
|
+
# default testing environment uses the rails default (sqlite3).
|
6
|
+
|
7
|
+
development:
|
8
|
+
adapter: mysql
|
9
|
+
database: errorkit_development
|
10
|
+
username: root
|
11
|
+
password:
|
12
|
+
host: localhost
|
13
|
+
|
14
|
+
test:
|
15
|
+
adapter: mysql
|
16
|
+
database: errorkit_test
|
17
|
+
username: root
|
18
|
+
password:
|
19
|
+
host: localhost
|
data/errorkit.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'errorkit/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "errorkit"
|
8
|
+
spec.version = Errorkit::VERSION
|
9
|
+
spec.authors = ["Jeff Rafter"]
|
10
|
+
spec.email = ["jeffrafter@gmail.com"]
|
11
|
+
spec.description = %q{ErrorKit allows you to track errors within your application and generate a notification when they happen.}
|
12
|
+
spec.summary = %q{ErrorKit allows you to track errors within your application and generate a notification when they happen.}
|
13
|
+
spec.homepage = "http://github.com/jeffrafter/errorkit"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec-rails"
|
24
|
+
spec.add_development_dependency "factory_girl_rails"
|
25
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Errorkit
|
2
|
+
class Config
|
3
|
+
attr_accessor \
|
4
|
+
:ignore_agents,
|
5
|
+
:ignore_exceptions,
|
6
|
+
:errors_class,
|
7
|
+
:errors_mailer,
|
8
|
+
:errors_controller,
|
9
|
+
:errors_layout,
|
10
|
+
:mailer_recipients,
|
11
|
+
:mailer_sender,
|
12
|
+
:max_notifications_per_minute,
|
13
|
+
:max_notifications_per_quarter_hour,
|
14
|
+
:alert_threshold
|
15
|
+
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@errors_mailer = Errorkit::ErrorsMailer
|
19
|
+
@errors_controller = Errorkit::ErrorsController
|
20
|
+
@errors_layout = false
|
21
|
+
@ignore_exceptions = []
|
22
|
+
@ignore_exceptions << ::ActiveRecord::RecordNotFound if defined? ::ActiveRecord::RecordNotFound
|
23
|
+
@ignore_exceptions << ::AbstractController::ActionNotFound if defined? ::AbstractController::ActionNotFound
|
24
|
+
@ignore_exceptions << ::ActionController::RoutingError if defined? ::ActionController::RoutingError
|
25
|
+
@ignore_agents = %w{Googlebot MSNBot Baiduspider Bing Inktomi Yahoo AskJeeves FastCrawler InfoSeek Lycos YandexBot NewRelicPinger Pingdom}
|
26
|
+
@max_notifications_per_minute = 5
|
27
|
+
@max_notifications_per_quarter_hour = 10
|
28
|
+
@alert_threshold = 0.4
|
29
|
+
end
|
30
|
+
|
31
|
+
def config
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def ignore_exception?(exception)
|
36
|
+
return false if @ignore_exceptions.nil? || @ignore_exceptions.length == 0
|
37
|
+
@ignore_exceptions.include?(exception.class)
|
38
|
+
end
|
39
|
+
|
40
|
+
def ignore_agent?(agent)
|
41
|
+
return false if @ignore_agents.nil? || @ignore_agents.length == 0
|
42
|
+
@ignore_agent_re ||= /(#{@ignore_agents.join('|')})/i
|
43
|
+
!!(agent =~ @ignore_agents_re)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Errorkit
|
2
|
+
class ErrorsController < ActionController::Base
|
3
|
+
before_filter :append_view_paths
|
4
|
+
|
5
|
+
helper_method :error, :exception, :status_code, :status_text
|
6
|
+
|
7
|
+
layout :error_layout
|
8
|
+
|
9
|
+
def show
|
10
|
+
begin
|
11
|
+
render "errors/#{rescue_response}", status: status_code
|
12
|
+
rescue ActionView::MissingTemplate
|
13
|
+
render "errors/show", status: status_code
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def error
|
20
|
+
@error ||= env['errorkit.error']
|
21
|
+
end
|
22
|
+
|
23
|
+
def exception
|
24
|
+
@exception ||= env['action_dispatch.exception']
|
25
|
+
end
|
26
|
+
|
27
|
+
def status_code
|
28
|
+
@status_code ||= ActionDispatch::ExceptionWrapper.new(env, exception).status_code
|
29
|
+
end
|
30
|
+
|
31
|
+
def status_text
|
32
|
+
Rack::Utils::HTTP_STATUS_CODES.fetch(status_code, "Internal Server Error")
|
33
|
+
end
|
34
|
+
|
35
|
+
def rescue_response
|
36
|
+
@rescue_response ||= ActionDispatch::ExceptionWrapper.rescue_responses[exception.class.name]
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def append_view_paths
|
42
|
+
append_view_path Pathname.new(File.expand_path('../../../', __FILE__)).join('lib', 'generators', 'errorkit', 'templates', 'app', 'views')
|
43
|
+
end
|
44
|
+
|
45
|
+
def error_layout
|
46
|
+
Errorkit.config.errors_layout
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'action_mailer'
|
2
|
+
|
3
|
+
module Errorkit
|
4
|
+
class ErrorsMailer < ActionMailer::Base
|
5
|
+
before_filter :append_view_paths
|
6
|
+
|
7
|
+
helper_method :error
|
8
|
+
|
9
|
+
self.mailer_name = 'errors'
|
10
|
+
|
11
|
+
def error_notification(error_id)
|
12
|
+
@error = Error.find(error_id)
|
13
|
+
|
14
|
+
mail(:to => mailer_recipients,
|
15
|
+
:from => mailer_sender,
|
16
|
+
:subject => mailer_subject) do |format|
|
17
|
+
format.html { render "#{mailer_name}/error_notification" }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def error
|
24
|
+
@error
|
25
|
+
end
|
26
|
+
|
27
|
+
def mailer_recipients
|
28
|
+
Errorkit.config.mailer_recipients
|
29
|
+
end
|
30
|
+
|
31
|
+
def mailer_sender
|
32
|
+
Errorkit.config.mailer_sender
|
33
|
+
end
|
34
|
+
|
35
|
+
def mailer_subject
|
36
|
+
"[#{error.environment || 'Error'}] #{error.exception}: #{error.message}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def append_view_paths
|
40
|
+
append_view_path Pathname.new(File.expand_path('../../../', __FILE__)).join('lib', 'generators', 'errorkit', 'templates', 'app', 'views')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/errorkit.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require "errorkit/version"
|
2
|
+
require 'errorkit/config'
|
3
|
+
require 'errorkit/ignorable_error'
|
4
|
+
require 'errorkit/errors_controller'
|
5
|
+
require 'errorkit/errors_mailer'
|
6
|
+
|
7
|
+
module Errorkit
|
8
|
+
require 'errorkit/engine' if defined?(Rails)
|
9
|
+
|
10
|
+
def self.configure(&block)
|
11
|
+
config.instance_eval(&block)
|
12
|
+
|
13
|
+
if defined?(Rails)
|
14
|
+
Rails.application.config.exceptions_app = lambda do |env|
|
15
|
+
Errorkit.server_error(env)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.config
|
21
|
+
@config ||= Errorkit::Config.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.server_error(env)
|
25
|
+
exception = env['action_dispatch.exception']
|
26
|
+
unless config.errors_class.nil? || config.ignore_exception?(exception) || config.ignore_agent?(env['HTTP_USER_AGENT'])
|
27
|
+
begin
|
28
|
+
request = ActionDispatch::Request.new(env)
|
29
|
+
error = config.errors_class.create(
|
30
|
+
server: server,
|
31
|
+
environment: environment,
|
32
|
+
version: application_version,
|
33
|
+
exception: exception.class.to_s,
|
34
|
+
message: exception.message,
|
35
|
+
backtrace: clean_backtrace(exception),
|
36
|
+
params: filtered_parameters(request).to_json,
|
37
|
+
session: filtered_session(request).to_json,
|
38
|
+
remote_ip: request.remote_ip.to_s,
|
39
|
+
controller: (env['action_controller.instance'].controller_name rescue nil),
|
40
|
+
action: (env['action_controller.instance'].action_name rescue nil))
|
41
|
+
|
42
|
+
env['errorkit.notified'] = send_notification(error)
|
43
|
+
env['errorkit.error'] = error
|
44
|
+
rescue Errorkit::IgnorableError
|
45
|
+
# noop
|
46
|
+
end
|
47
|
+
end
|
48
|
+
config.errors_controller.action(:show).call(env)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.environment
|
52
|
+
Rails.env.to_s if defined?(Rails)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.server
|
56
|
+
@server ||= `hostname`.chomp rescue nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.application_version
|
60
|
+
@version ||= `cd #{Rails.root.to_s} && git rev-parse HEAD`.chomp rescue nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.filtered_parameters(request)
|
64
|
+
request.filtered_parameters
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.filtered_session(request)
|
68
|
+
session = request.session.dup
|
69
|
+
session.delete(:session_id)
|
70
|
+
session
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.clean_backtrace(exception)
|
74
|
+
backtrace = Rails.backtrace_cleaner.send(:filter, exception.backtrace) if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
|
75
|
+
backtrace ||= exception.backtrace
|
76
|
+
backtrace ||= []
|
77
|
+
backtrace.join("\n")
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.send_notification(error)
|
81
|
+
return if config.mailer_recipients.blank? || config.mailer_sender.blank?
|
82
|
+
|
83
|
+
# TODO, throttle
|
84
|
+
config.errors_mailer.error_notification(error.id).deliver
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Usage:
|
2
|
+
rails generate errorkit:install [options]
|
3
|
+
|
4
|
+
Runtime options:
|
5
|
+
-f, [--force] # Overwrite files that already exist
|
6
|
+
-p, [--pretend] # Run but do not make any changes
|
7
|
+
-s, [--skip] # Skip files that already exist
|
8
|
+
-q, [--quiet] # Supress status output
|
9
|
+
|
10
|
+
Description:
|
11
|
+
ErrorKit allows you to track errors within your application and generate a
|
12
|
+
notification when they happen.
|
13
|
+
|
14
|
+
Example:
|
15
|
+
rails generate errorkit:install
|
16
|
+
|
17
|
+
This generator will create an error
|
18
|
+
model and corresponding migration. It will also install view templates
|
19
|
+
for the error notifier.
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/active_record'
|
3
|
+
|
4
|
+
module Errorkit
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
|
8
|
+
desc "An error system for your Rails app"
|
9
|
+
|
10
|
+
def self.source_root
|
11
|
+
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate_errorkit
|
15
|
+
generate_migration("create_errors")
|
16
|
+
|
17
|
+
# Ensure the destination structure
|
18
|
+
empty_directory "config"
|
19
|
+
empty_directory "initializers"
|
20
|
+
empty_directory "app"
|
21
|
+
empty_directory "app/models"
|
22
|
+
empty_directory "app/views"
|
23
|
+
empty_directory "app/views/errors"
|
24
|
+
empty_directory "spec"
|
25
|
+
empty_directory "spec/models"
|
26
|
+
empty_directory "spec/mailers"
|
27
|
+
empty_directory "lib"
|
28
|
+
|
29
|
+
# Fill out some templates (for now, this is just straight copy)
|
30
|
+
template "config/initializers/errorkit.rb", "config/initializers/errorkit.rb"
|
31
|
+
template "app/models/error.rb", "app/models/error.rb"
|
32
|
+
template "spec/models/error_spec.rb", "spec/models/error_spec.rb"
|
33
|
+
|
34
|
+
# Don't treat these like templates
|
35
|
+
copy_file "app/views/errors/error_notification.html.erb", "app/views/errors/error_notification.html.erb"
|
36
|
+
copy_file "app/views/errors/show.html.erb", "app/views/errors/show.html.erb"
|
37
|
+
|
38
|
+
# RSpec needs to be in the development group to be used in generators
|
39
|
+
gem_group :test, :development do
|
40
|
+
gem "rspec-rails"
|
41
|
+
gem "shoulda-matchers"
|
42
|
+
gem 'factory_girl_rails'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.next_migration_number(dirname)
|
47
|
+
ActiveRecord::Generators::Base.next_migration_number(dirname)
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def generate_migration(filename)
|
53
|
+
if self.class.migration_exists?("db/migrate", "#{filename}")
|
54
|
+
say_status "skipped", "Migration #{filename}.rb already exists"
|
55
|
+
else
|
56
|
+
migration_template "db/migrate/#{filename}.rb", "db/migrate/#{filename}.rb"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<!--[if IE 8]> <html lang="en" class="ie ie8 lt-ie9"> <![endif]-->
|
3
|
+
<!--[if IE 9]> <html lang="en" class="ie ie9"> <![endif]-->
|
4
|
+
<!--[if gt IE 9]><!--> <html lang="en"> <!--<![endif]-->
|
5
|
+
<head>
|
6
|
+
<title><%= status_code %> Error</title>
|
7
|
+
<meta charset="utf-8">
|
8
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
9
|
+
</head>
|
10
|
+
<body>
|
11
|
+
The server encountered an error: <%= status_code %> (<%= status_text %>)
|
12
|
+
</body>
|
13
|
+
</html>
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Configure Errorkit to display custom error pages and deliver error notifications.
|
2
|
+
#
|
3
|
+
# To view the errors in development you must change config/environments/development.rb:
|
4
|
+
#
|
5
|
+
# config.consider_all_requests_local = false
|
6
|
+
#
|
7
|
+
Errorkit.configure do
|
8
|
+
# Many bots create errors spidering your site. You may want to ignore those. By
|
9
|
+
# default the following bots are ignored:
|
10
|
+
#
|
11
|
+
# config.ignore_agents = %w{
|
12
|
+
# Googlebot MSNBot Baiduspider Bing Inktomi Yahoo AskJeeves FastCrawler
|
13
|
+
# InfoSeek Lycos YandexBot NewRelicPinger Pingdom
|
14
|
+
# }
|
15
|
+
#
|
16
|
+
# If you do not want to ignore bots set the ignore_agents to an empty array
|
17
|
+
#
|
18
|
+
# config,ignore_agents = []
|
19
|
+
|
20
|
+
|
21
|
+
# Some exceptions should be expected and you don't want to be notified when they
|
22
|
+
# occur. By default the following exceptions are ignored:
|
23
|
+
#
|
24
|
+
# config.ignore_exceptions = [
|
25
|
+
# ActiveRecord::RecordNotFound,
|
26
|
+
# AbstractController::ActionNotFound,
|
27
|
+
# ActionController::RoutingError
|
28
|
+
# ]
|
29
|
+
#
|
30
|
+
# If you want to be notified of all errors set ignore_exceptions to an empty
|
31
|
+
# array:
|
32
|
+
#
|
33
|
+
# config.ignore_exceptions = []
|
34
|
+
|
35
|
+
# The recipients you want to notify when there is an error. If you leave this
|
36
|
+
# blank then notifications will not be sent.
|
37
|
+
config.mailer_recipients = ["you@example.com"]
|
38
|
+
|
39
|
+
# The sender of the error notifications. If you leave this blank then
|
40
|
+
# notifications will not be sent.
|
41
|
+
config.mailer_sender = ["errors@example.com"]
|
42
|
+
|
43
|
+
# Overriding the default error pages allows you to customize their look
|
44
|
+
# and feel but still have them served through your application. You can
|
45
|
+
# override the view templates by creating new template within you
|
46
|
+
# app/views/errors folder. If you want to change the layout used when
|
47
|
+
# rendering the views, set:
|
48
|
+
#
|
49
|
+
# config.errors_layout = 'application'
|
50
|
+
#
|
51
|
+
# By default, no layout is used (layout is false).
|
52
|
+
|
53
|
+
# By default, Errorkit sends notifications with its own mailer. To override
|
54
|
+
# this, set:
|
55
|
+
#
|
56
|
+
# config.errors_mailer = MyMailer
|
57
|
+
|
58
|
+
# By default, Errorkit responds to errors with its own controller. To override
|
59
|
+
# this, set:
|
60
|
+
#
|
61
|
+
# config.errors_controller = MyController
|
62
|
+
|
63
|
+
|
64
|
+
# To persist errors, you must specify a class that acts like an ActiveRecord
|
65
|
+
# model. If errors_class is not set, errors will not be persisted.
|
66
|
+
config.errors_class = Error
|
67
|
+
|
68
|
+
# Getting hundreds or thousands of error notifications is not fun. You
|
69
|
+
# can set a max number of notifiactions per minute and per fifteen
|
70
|
+
# minutes:
|
71
|
+
#
|
72
|
+
# config.max_notifications_per_minute = 5
|
73
|
+
# config.max_notifications_per_quarter_hour = 10
|
74
|
+
#
|
75
|
+
# To turn off throttling set these values to nil
|
76
|
+
|
77
|
+
|
78
|
+
# It is possible to create alerts that occur only when the number of
|
79
|
+
# errors per request exceeds a specific percentage.
|
80
|
+
#
|
81
|
+
# config.alert_threshold = 0.4
|
82
|
+
#
|
83
|
+
# To turn off error rate alerts, set this to nil
|
84
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Generated by Errorkit.
|
2
|
+
#
|
3
|
+
# Create an errors table for managing errors.
|
4
|
+
class CreateErrors < ActiveRecord::Migration
|
5
|
+
def self.up
|
6
|
+
create_table :errors do |t|
|
7
|
+
t.string :environment
|
8
|
+
t.string :server
|
9
|
+
t.string :version
|
10
|
+
t.string :exception
|
11
|
+
t.string :message
|
12
|
+
t.text :backtrace
|
13
|
+
t.string :controller
|
14
|
+
t.string :action
|
15
|
+
t.string :remote_ip
|
16
|
+
t.text :session
|
17
|
+
t.text :params
|
18
|
+
t.string :worker
|
19
|
+
t.string :queue
|
20
|
+
t.string :payload
|
21
|
+
t.string :url
|
22
|
+
t.integer :user_id
|
23
|
+
t.integer :subject_id
|
24
|
+
t.string :subject_type
|
25
|
+
t.datetime :resolved_at
|
26
|
+
|
27
|
+
t.timestamps
|
28
|
+
end
|
29
|
+
|
30
|
+
add_index :errors, :exception
|
31
|
+
add_index :errors, :created_at
|
32
|
+
add_index :errors, :resolved_at
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.down
|
36
|
+
drop_table :errors
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Error do
|
4
|
+
let(:error) { Error.new }
|
5
|
+
|
6
|
+
it "resolves errors" do
|
7
|
+
now = Time.now
|
8
|
+
Time.stub(:now).and_return(now)
|
9
|
+
error.should_receive(:update_attribute).with(:resolved_at, now)
|
10
|
+
error.resolve!
|
11
|
+
end
|
12
|
+
|
13
|
+
it "does not resolve already resolved errors" do
|
14
|
+
error.should_not_receive(:update_attribute)
|
15
|
+
error.resolved_at = Time.now
|
16
|
+
error.resolve!
|
17
|
+
end
|
18
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
ENV["RAILS_ENV"] ||= 'test'
|
2
|
+
require File.expand_path('../tmp/sample/config/environment', __FILE__)
|
3
|
+
require 'rspec/rails'
|
4
|
+
require 'rspec/autorun'
|
5
|
+
|
6
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
|
7
|
+
|
8
|
+
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.use_transactional_fixtures = true
|
12
|
+
config.infer_base_class_for_anonymous_controllers = false
|
13
|
+
config.order = "random"
|
14
|
+
# Because we are not running things in Rails we need to stub some secrets
|
15
|
+
config.before(:each) { Rails.application.config.stub(:secret_token).and_return("SECRET") }
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: errorkit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeff Rafter
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: factory_girl_rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: ErrorKit allows you to track errors within your application and generate
|
70
|
+
a notification when they happen.
|
71
|
+
email:
|
72
|
+
- jeffrafter@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- config/database.yml.example
|
83
|
+
- errorkit.gemspec
|
84
|
+
- lib/errorkit.rb
|
85
|
+
- lib/errorkit/config.rb
|
86
|
+
- lib/errorkit/engine.rb
|
87
|
+
- lib/errorkit/errors_controller.rb
|
88
|
+
- lib/errorkit/errors_mailer.rb
|
89
|
+
- lib/errorkit/ignorable_error.rb
|
90
|
+
- lib/errorkit/version.rb
|
91
|
+
- lib/generators/errorkit/USAGE
|
92
|
+
- lib/generators/errorkit/install_generator.rb
|
93
|
+
- lib/generators/errorkit/templates/app/models/error.rb
|
94
|
+
- lib/generators/errorkit/templates/app/views/errors/error_notification.html.erb
|
95
|
+
- lib/generators/errorkit/templates/app/views/errors/show.html.erb
|
96
|
+
- lib/generators/errorkit/templates/config/initializers/errorkit.rb
|
97
|
+
- lib/generators/errorkit/templates/db/migrate/create_errors.rb
|
98
|
+
- lib/generators/errorkit/templates/spec/models/error_spec.rb
|
99
|
+
- spec/spec_helper.rb
|
100
|
+
homepage: http://github.com/jeffrafter/errorkit
|
101
|
+
licenses:
|
102
|
+
- MIT
|
103
|
+
metadata: {}
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - '>='
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 2.0.3
|
121
|
+
signing_key:
|
122
|
+
specification_version: 4
|
123
|
+
summary: ErrorKit allows you to track errors within your application and generate
|
124
|
+
a notification when they happen.
|
125
|
+
test_files:
|
126
|
+
- spec/spec_helper.rb
|