exception_handler 0.5.1 → 0.6.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +4 -4
- data/Gemfile +1 -3
- data/README.md +111 -98
- data/app/assets/images/exception_handler/connect/facebook.png +0 -0
- data/app/assets/images/exception_handler/connect/fusion.png +0 -0
- data/app/assets/images/exception_handler/connect/linkedin.png +0 -0
- data/app/assets/images/exception_handler/connect/twitter.png +0 -0
- data/app/assets/images/exception_handler/connect/youtube.png +0 -0
- data/app/assets/images/exception_handler/noise.png +0 -0
- data/app/assets/images/favicon.ico +0 -0
- data/app/assets/stylesheets/exception_handler.css.erb +18 -0
- data/app/assets/stylesheets/styles/_base.css.erb +34 -0
- data/app/assets/stylesheets/styles/_exception.css.erb +105 -0
- data/app/assets/stylesheets/styles/_footer.css.erb +27 -0
- data/app/assets/stylesheets/styles/_responsive.css +5 -0
- data/app/controllers/exception_handler/exception_controller.rb +28 -33
- data/app/mailers/exception_handler/exception_mailer.rb +17 -0
- data/app/models/exception_handler/exception.rb +191 -0
- data/app/views/exception_handler/exception/show.html.erb +3 -32
- data/app/views/exception_handler/mailers/layout.haml +8 -0
- data/app/views/exception_handler/mailers/layout.text.erb +1 -0
- data/app/views/exception_handler/mailers/new_exception.erb +4 -0
- data/app/views/layouts/exception.html.erb +15 -23
- data/config/locales/exception_handler.en.yml +13 -0
- data/exception_handler.gemspec +61 -16
- data/lib/exception_handler.rb +20 -79
- data/lib/exception_handler/config.rb +20 -22
- data/lib/exception_handler/engine.rb +36 -0
- data/lib/generators/exception_handler/migration_generator.rb +28 -10
- data/lib/generators/exception_handler/views_generator.rb +5 -5
- data/lib/generators/templates/migration.rb.erb +12 -11
- metadata +41 -64
- data/app/assets/images/exception_handler/close.png +0 -0
- data/app/assets/images/exception_handler/home.png +0 -0
- data/app/assets/stylesheets/exception_handler/error.css.erb +0 -309
- data/app/helpers/exception_handler/application_helper.rb +0 -56
- data/app/models/exception_handler/error.rb +0 -14
- data/app/services/exception_handler/exception.rb +0 -34
- data/config/locales/en.yml +0 -9
- data/lib/exception_handler/parse.rb +0 -23
- data/lib/exception_handler/parser/data.rb +0 -59
- data/lib/exception_handler/parser/ignore.rb +0 -32
- data/lib/exception_handler/version.rb +0 -3
- data/post_install_message.md +0 -53
- data/spec/helpers/exception_handler/application_helper_spec.rb +0 -42
@@ -0,0 +1,105 @@
|
|
1
|
+
/* ---------------------------------------------------- */
|
2
|
+
/* ---------------------------------------------------- */
|
3
|
+
|
4
|
+
.exception {
|
5
|
+
display: block;
|
6
|
+
color: #fff;
|
7
|
+
position: relative;
|
8
|
+
width: 30%;
|
9
|
+
top: 48%;
|
10
|
+
margin: auto;
|
11
|
+
background: rgba(255,255,255,0.15);
|
12
|
+
border: 1px solid rgba(0,0,0,1);
|
13
|
+
max-width: 450px;
|
14
|
+
min-width: 350px;
|
15
|
+
font-size: 0.85em;
|
16
|
+
border-radius: 5px;
|
17
|
+
box-sizing: border-box;
|
18
|
+
box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.8);
|
19
|
+
background-clip: border-box;
|
20
|
+
text-shadow: 0 1px 0 rgba(0,0,0,1);
|
21
|
+
overflow-x: hidden;
|
22
|
+
overflow-y: hidden;
|
23
|
+
transition: background 0.1s ease-in-out;
|
24
|
+
transform: translateY(-50%);
|
25
|
+
}
|
26
|
+
.exception::before {
|
27
|
+
content: attr(data-status) " Error (" attr(data-response) ") …";
|
28
|
+
display: block;
|
29
|
+
color: #fff;
|
30
|
+
font-size: 1.75em;
|
31
|
+
font-weight: bold;
|
32
|
+
text-transform: capitalize;
|
33
|
+
background-color: rgba(227,11,11,1);
|
34
|
+
padding: 1em;
|
35
|
+
box-sizing: border-box;
|
36
|
+
background-color: rgba(227,11,11,1);
|
37
|
+
|
38
|
+
border-bottom: 1px solid rgba(227,11,11,0.35);
|
39
|
+
|
40
|
+
background-image: url(<%= asset_url("exception_handler/noise.png") %>), -moz-linear-gradient(top, rgba(227,11,11,0) 0%, rgba(0,0,0,0.55) 100%); /* FF3.6+ */
|
41
|
+
background-image: url(<%= asset_url("exception_handler/noise.png") %>), -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(227,11,11,0)), color-stop(100%,rgba(0,0,0,0.55))); /* Chrome,Safari4+ */
|
42
|
+
background-image: url(<%= asset_url("exception_handler/noise.png") %>), -webkit-linear-gradient(top, rgba(227,11,11,0) 0%,rgba(0,0,0,0.55) 100%); /* Chrome10+,Safari5.1+ */
|
43
|
+
background-image: url(<%= asset_url("exception_handler/noise.png") %>), -o-linear-gradient(top, rgba(227,11,11,0) 0%,rgba(0,0,0,0.55) 100%); /* Opera 11.10+ */
|
44
|
+
background-image: url(<%= asset_url("exception_handler/noise.png") %>), -ms-linear-gradient(top, rgba(227,11,11,0) 0%,rgba(0,0,0,0.55) 100%); /* IE10+ */
|
45
|
+
background-image: url(<%= asset_url("exception_handler/noise.png") %>), linear-gradient(to bottom, rgba(227,11,11,0) 0%,rgba(0,0,0,0.55) 100%); /* W3C */
|
46
|
+
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#007a07ed', endColorstr='#000000',GradientType=0 ); /* IE6-9 */
|
47
|
+
}
|
48
|
+
.exception::after {
|
49
|
+
content: attr(data-rails) " \203A\203A Our developers have been notified. Click here to go home.";
|
50
|
+
display: block;
|
51
|
+
padding: 1em;
|
52
|
+
font-size: 0.9em;
|
53
|
+
background: rgba(0,0,0,0.5);
|
54
|
+
}
|
55
|
+
.exception:hover { cursor: pointer; }
|
56
|
+
|
57
|
+
.exception span:before {
|
58
|
+
display: block;
|
59
|
+
content: url(<%= asset_url("exception_handler/alert.png") %>);
|
60
|
+
padding: 5em 0;
|
61
|
+
text-align: center;
|
62
|
+
}
|
63
|
+
.exception span:after {
|
64
|
+
content: "";
|
65
|
+
display: block;
|
66
|
+
position: absolute;
|
67
|
+
left: 0;
|
68
|
+
top: 0;
|
69
|
+
width: 100%;
|
70
|
+
height: 2px;
|
71
|
+
|
72
|
+
background: rgba(0,0,0,0.35);
|
73
|
+
background: -moz-linear-gradient(top, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
|
74
|
+
background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(0,0,0,0.35)), color-stop(100%, rgba(0,0,0,0)));
|
75
|
+
background: -webkit-linear-gradient(top, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
|
76
|
+
background: -o-linear-gradient(top, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
|
77
|
+
background: -ms-linear-gradient(top, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
|
78
|
+
background: linear-gradient(to bottom, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 100%);
|
79
|
+
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#000000', endColorstr='#000000', GradientType=0 );
|
80
|
+
}
|
81
|
+
.exception span {
|
82
|
+
position: relative;
|
83
|
+
display: block;
|
84
|
+
min-height: 288px;
|
85
|
+
padding: 0 2em 3.5em;
|
86
|
+
box-sizing: border-box;
|
87
|
+
background: #000 url(<%= asset_url("exception_handler/alert.jpg") %>) top center no-repeat;
|
88
|
+
background-size: cover;
|
89
|
+
text-align: center;
|
90
|
+
|
91
|
+
border-width: 0 1px;
|
92
|
+
border-style: solid;
|
93
|
+
border-color: rgba(255,255,255,0.065);
|
94
|
+
}
|
95
|
+
.exception span strong {
|
96
|
+
display: block;
|
97
|
+
margin-bottom: 0.5em;
|
98
|
+
margin-top: 0.25em;
|
99
|
+
font-size: 1.95em;
|
100
|
+
text-transform: uppercase;
|
101
|
+
text-decoration: underline;
|
102
|
+
}
|
103
|
+
|
104
|
+
/* ---------------------------------------------------- */
|
105
|
+
/* ---------------------------------------------------- */
|
@@ -0,0 +1,27 @@
|
|
1
|
+
/* ---------------------------------------------------- */
|
2
|
+
/* ---------------------------------------------------- */
|
3
|
+
|
4
|
+
footer {
|
5
|
+
display: block;
|
6
|
+
position: absolute;
|
7
|
+
bottom: 0;
|
8
|
+
width: 100%;
|
9
|
+
opacity: 0.75;
|
10
|
+
font-size: 2em;
|
11
|
+
text-align: center;
|
12
|
+
vertical-align: middle;
|
13
|
+
transition: opacity 0.15s ease-in-out;
|
14
|
+
}
|
15
|
+
footer:hover { opacity: 1; }
|
16
|
+
footer a {
|
17
|
+
display: inline-block;
|
18
|
+
opacity: 0.45;
|
19
|
+
margin-right: -4px;
|
20
|
+
padding: 1.5em 0.3em;
|
21
|
+
transition: opacity 0.15s ease-in-out;
|
22
|
+
}
|
23
|
+
footer a:hover { opacity: 1; text-decoration: none; }
|
24
|
+
footer a img { width: 24px; vertical-align: middle; }
|
25
|
+
|
26
|
+
/* ---------------------------------------------------- */
|
27
|
+
/* ---------------------------------------------------- */
|
@@ -1,50 +1,45 @@
|
|
1
1
|
module ExceptionHandler
|
2
2
|
class ExceptionController < ApplicationController
|
3
3
|
|
4
|
-
#Response
|
5
|
-
#http://www.justinweiss.com/articles/respond-to-without-all-the-pain/
|
4
|
+
# => Response
|
5
|
+
# => http://www.justinweiss.com/articles/respond-to-without-all-the-pain/
|
6
6
|
respond_to :html, :xml, :json
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#Helpers
|
12
|
-
helper ExceptionHandler::Engine.helpers #-> HELPERS http://stackoverflow.com/questions/9809787/why-is-my-rails-mountable-engine-not-loading-helper-methods-correctly
|
13
|
-
include Rails.application.routes.url_helpers #-> ROUTES http://stackoverflow.com/a/6074911/1143732
|
14
|
-
|
15
|
-
####################
|
16
|
-
# Action #
|
17
|
-
####################
|
18
|
-
|
19
|
-
#Show
|
20
|
-
#Amend responses in tests
|
21
|
-
#Need to test validity of JSON responses etc
|
22
|
-
def show
|
23
|
-
@exception = ExceptionHandler::Exception.new request #-> Service Object
|
24
|
-
render status: @exception.status #-> Show apppropriate response
|
25
|
-
end
|
8
|
+
##################################
|
9
|
+
##################################
|
26
10
|
|
27
|
-
|
28
|
-
#
|
29
|
-
|
11
|
+
# => Definitions
|
12
|
+
# => Exception model (tied to DB)
|
13
|
+
before_action { |e| @exception = ExceptionHandler::Exception.new request: e.request }
|
14
|
+
before_action { @exception.save if @exception.valid? && ExceptionHandler.config.try(:db) }
|
30
15
|
|
31
|
-
|
16
|
+
# => Routes
|
17
|
+
# => Removes need for "main_app" prefix in routes
|
18
|
+
# => http://stackoverflow.com/a/40251516/1143732
|
19
|
+
helper Rails.application.routes.url_helpers
|
32
20
|
|
33
|
-
#
|
34
|
-
#
|
21
|
+
# => Layout
|
22
|
+
# => Layouts only 400 / 500 because they are the only error responses (300 is redirect)
|
23
|
+
# => http://guides.rubyonrails.org/layouts_and_rendering.html#the-status-option
|
24
|
+
# => Layout proc kills inheritance, needs to be method for now
|
25
|
+
layout :layout
|
35
26
|
|
36
27
|
####################
|
37
|
-
#
|
28
|
+
# Action #
|
38
29
|
####################
|
39
30
|
|
40
|
-
|
41
|
-
|
42
|
-
#Layout
|
43
|
-
def layout
|
44
|
-
(/^(5[0-9]{2})$/ !~ @exception.code.to_s) ? (ExceptionHandler.config.layouts["400"] || nil) : ExceptionHandler.config.layouts["500"] #-> if not 500, use predefined layout
|
31
|
+
def show
|
32
|
+
respond_with @exception, status: @exception.status
|
45
33
|
end
|
46
34
|
|
47
|
-
|
35
|
+
##################################
|
36
|
+
##################################
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def layout
|
41
|
+
ExceptionHandler.config.layouts[ @exception.status[0] + "00" ]
|
42
|
+
end
|
48
43
|
|
49
44
|
end
|
50
45
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ExceptionHandler
|
2
|
+
class ExceptionMailer < ActionMailer::Base
|
3
|
+
|
4
|
+
# Layout
|
5
|
+
layout "mailers/layouts/mailer"
|
6
|
+
|
7
|
+
# Defaults
|
8
|
+
default from: ExceptionHandler.config.email
|
9
|
+
default template_path: "exception_handler/mailers" # => http://stackoverflow.com/a/18579046/1143732
|
10
|
+
|
11
|
+
def new_exception e
|
12
|
+
@exception = e
|
13
|
+
mail to: ExceptionHandler.config.email
|
14
|
+
Rails.logger.info "Exception Sent To → #{ExceptionHandler.config.email}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
module ExceptionHandler
|
2
|
+
|
3
|
+
############################################################
|
4
|
+
############################################################
|
5
|
+
|
6
|
+
# => Search Bots
|
7
|
+
# => Used in "Exception" class
|
8
|
+
BOTS = %w(Baidu Gigabot Googlebot libwww-per lwp-trivial msnbot SiteUptime Slurp Wordpress ZIBB ZyBorg Yandex Jyxobot Huaweisymantecspider ApptusBot)
|
9
|
+
|
10
|
+
# => Attributes
|
11
|
+
# => Determine schema size etc
|
12
|
+
ATTRS = %i(class_name status message trace target referrer params user_agent)
|
13
|
+
|
14
|
+
############################################################
|
15
|
+
############################################################
|
16
|
+
|
17
|
+
# => Class (inheritance dependent on whether db option is available)
|
18
|
+
self::Exception = Class.new (ExceptionHandler.config.try(:db) ? ActiveRecord::Base : Object) do
|
19
|
+
|
20
|
+
# => Include individual elements
|
21
|
+
# => Only required if no db present (no ActiveRecord)
|
22
|
+
if ExceptionHandler.config.try(:db)
|
23
|
+
|
24
|
+
# => Set Attrs
|
25
|
+
def initialize attributes={}
|
26
|
+
super
|
27
|
+
ATTRS.each do |type|
|
28
|
+
self[type] = eval type.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
else
|
33
|
+
|
34
|
+
# => AciveModel
|
35
|
+
include ActiveModel::Model
|
36
|
+
include ActiveModel::Validations
|
37
|
+
|
38
|
+
# => Callback Extension
|
39
|
+
extend ActiveModel::Callbacks
|
40
|
+
define_model_callbacks :initialize, only: :after
|
41
|
+
|
42
|
+
# => Initialize
|
43
|
+
# => http://api.rubyonrails.org/classes/ActiveModel/Callbacks.html
|
44
|
+
# => http://stackoverflow.com/a/17682228/1143732
|
45
|
+
def initialize attributes={}
|
46
|
+
super
|
47
|
+
run_callbacks :initialize do
|
48
|
+
# => Needed for after_initialize
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
##################################
|
55
|
+
##################################
|
56
|
+
|
57
|
+
####################
|
58
|
+
# Table #
|
59
|
+
####################
|
60
|
+
|
61
|
+
# Schema
|
62
|
+
###################
|
63
|
+
# class_name @exception.class.name
|
64
|
+
# status ActionDispatch::ExceptionWrapper.new(@request.env, @exception).status_code
|
65
|
+
# message @exception.message
|
66
|
+
# trace @exception.backtrace.join("\n")
|
67
|
+
# target @request.url
|
68
|
+
# referer @request.referer
|
69
|
+
# params @request.params.inspect
|
70
|
+
# user_agent @request.user_agent
|
71
|
+
# created_at
|
72
|
+
# updated_at
|
73
|
+
|
74
|
+
# => Table is called "errors"
|
75
|
+
# => Dev needs to use migration to create db
|
76
|
+
if ExceptionHandler.config.try(:db)
|
77
|
+
def self.table_name
|
78
|
+
ExceptionHandler.config.db
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
##################################
|
83
|
+
##################################
|
84
|
+
|
85
|
+
####################
|
86
|
+
# Options #
|
87
|
+
####################
|
88
|
+
|
89
|
+
# => Email
|
90
|
+
# => after_initialize invoked after .new method called
|
91
|
+
# => Should have been after_create but user may not save
|
92
|
+
after_initialize Proc.new { |e| ExceptionHandler::ExceptionMailer.new_exception(e).deliver } if ExceptionHandler.config.try(:email) && ExceptionHandler.config.email.is_a?(String)
|
93
|
+
|
94
|
+
# => Attributes
|
95
|
+
attr_accessor :request, :klass, :exception, :description
|
96
|
+
attr_accessor *ATTRS unless ExceptionHandler.config.try(:db)
|
97
|
+
|
98
|
+
# => Validations
|
99
|
+
validates :klass, exclusion: { in: [ActionController::RoutingError, AbstractController::ActionNotFound, ActiveRecord::RecordNotFound], message: "%{value}" }, if: "referer.blank?"
|
100
|
+
validates :user_agent, format: { without: Regexp.new( BOTS.join("|"), Regexp::IGNORECASE ) }
|
101
|
+
|
102
|
+
##################################
|
103
|
+
##################################
|
104
|
+
|
105
|
+
####################################
|
106
|
+
# Virtual
|
107
|
+
####################################
|
108
|
+
|
109
|
+
# => Klass
|
110
|
+
# => Used for validation (needs to be cleaned up in 0.7.0)
|
111
|
+
def klass
|
112
|
+
exception.class
|
113
|
+
end
|
114
|
+
|
115
|
+
# => Exception (virtual)
|
116
|
+
def exception
|
117
|
+
request.env['action_dispatch.exception']
|
118
|
+
end
|
119
|
+
|
120
|
+
# => Description
|
121
|
+
def description
|
122
|
+
I18n.with_options scope: [:exception], message: message do |i18n|
|
123
|
+
i18n.t response, default: status
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
####################################
|
128
|
+
# Exception
|
129
|
+
####################################
|
130
|
+
|
131
|
+
# => Class Name
|
132
|
+
def class_name
|
133
|
+
exception.class.name
|
134
|
+
end
|
135
|
+
|
136
|
+
# => Message
|
137
|
+
def message
|
138
|
+
exception.message
|
139
|
+
end
|
140
|
+
|
141
|
+
# => Trace
|
142
|
+
def trace
|
143
|
+
exception.backtrace.join("\n")
|
144
|
+
end
|
145
|
+
|
146
|
+
####################################
|
147
|
+
# Request
|
148
|
+
####################################
|
149
|
+
|
150
|
+
# => Target URL
|
151
|
+
def target
|
152
|
+
request.url
|
153
|
+
end
|
154
|
+
|
155
|
+
# => Referrer URL
|
156
|
+
def referer
|
157
|
+
request.referer
|
158
|
+
end
|
159
|
+
|
160
|
+
# => Params
|
161
|
+
def params
|
162
|
+
request.params.inspect
|
163
|
+
end
|
164
|
+
|
165
|
+
# => User Agent
|
166
|
+
def user_agent
|
167
|
+
request.user_agent
|
168
|
+
end
|
169
|
+
|
170
|
+
####################################
|
171
|
+
# Other
|
172
|
+
####################################
|
173
|
+
|
174
|
+
# => Status code (404, 500 etc)
|
175
|
+
def status
|
176
|
+
ActionDispatch::ExceptionWrapper.new(request.env, exception).status_code.to_s
|
177
|
+
end
|
178
|
+
|
179
|
+
# => Server Response ("Not Found" etc)
|
180
|
+
def response
|
181
|
+
ActionDispatch::ExceptionWrapper.rescue_responses[class_name]
|
182
|
+
end
|
183
|
+
|
184
|
+
##################################
|
185
|
+
##################################
|
186
|
+
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
############################################################
|
191
|
+
############################################################
|
@@ -1,32 +1,3 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
<!--Message -->
|
5
|
-
<%= content_tag :div, class: "message" do %>
|
6
|
-
<%= content_tag :div, class: "title" do %>
|
7
|
-
<span><%= "#{@exception.status} Error - #{details[:name]}" %></span>
|
8
|
-
<%= link_to image_tag("exception_handler/close.png"), main_app.root_url, title: "Close (Go back home)", class: "close" %>
|
9
|
-
<% end %>
|
10
|
-
|
11
|
-
<%= content_tag :div, class: "details" do %>
|
12
|
-
<%= image_tag "exception_handler/alert.png", title: "#{@exception.status} Error" %>
|
13
|
-
<div class="status"><%= @exception.status %> Error</div>
|
14
|
-
<% end %>
|
15
|
-
|
16
|
-
<%= content_tag :div, class: "info" do %>
|
17
|
-
<span><%= details[:description] %></span>
|
18
|
-
<div class="notification">
|
19
|
-
<%= link_to image_tag("exception_handler/home.png", title: "Go Back Home"), main_app.root_url, class: "home" %>
|
20
|
-
<div class="version">v<%= Rails.version %></div>
|
21
|
-
<strong>Our developers have been notified - we're working on it!</strong>
|
22
|
-
</div>
|
23
|
-
<% end %>
|
24
|
-
|
25
|
-
<% end %>
|
26
|
-
|
27
|
-
<% else %>
|
28
|
-
|
29
|
-
<%= content_tag :div, details[:description], class: "message" %>
|
30
|
-
|
31
|
-
<% end %>
|
32
|
-
</div>
|
1
|
+
<%= content_tag :div, class: "exception", data: { status: @exception.status, response: @exception.response.to_s.humanize, rails: Rails.version }, onclick: "location.href=\"#{root_url}\";" do %>
|
2
|
+
<%= content_tag :span, @exception.description.html_safe %>
|
3
|
+
<% end %>
|