public
Clone URL: git://github.com/defunkt/exception_logger.git
Search Repo:
first public version of logged exceptions plugin

git-svn-id: 
http://svn.techno-weenie.net/projects/plugins/exception_logger@1271 
567b1171-46fb-0310-a4c9-b4bef9110e78
technoweenie (author)
Fri Jun 23 21:43:30 -0700 2006
commit  e33986d958396902eacc878ebd72e7539802f815
tree    c9d99339c6b7ec1fe009955376926cffb9b49256
0
...
 
 
 
 
0
...
1
2
3
4
5
0
@@ -0,0 +1,4 @@
0
+ExceptionLogger
0
+===============
0
+
0
+Description goes here
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
0
@@ -0,0 +1,22 @@
0
+require 'rake'
0
+require 'rake/testtask'
0
+require 'rake/rdoctask'
0
+
0
+desc 'Default: run unit tests.'
0
+task :default => :test
0
+
0
+desc 'Test the exception_logger plugin.'
0
+Rake::TestTask.new(:test) do |t|
0
+ t.libs << 'lib'
0
+ t.pattern = 'test/**/*_test.rb'
0
+ t.verbose = true
0
+end
0
+
0
+desc 'Generate documentation for the exception_logger plugin.'
0
+Rake::RDocTask.new(:rdoc) do |rdoc|
0
+ rdoc.rdoc_dir = 'rdoc'
0
+ rdoc.title = 'ExceptionLogger'
0
+ rdoc.options << '--line-numbers' << '--inline-source'
0
+ rdoc.rdoc_files.include('README')
0
+ rdoc.rdoc_files.include('lib/**/*.rb')
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
0
@@ -0,0 +1,28 @@
0
+ExceptionLogger = {
0
+ filters: ['exception_names', 'controller_actions', 'date_ranges'],
0
+ setPage: function(num) {
0
+ $('page').value = num;
0
+ $('query-form').onsubmit();
0
+ },
0
+
0
+ setFilter: function(context, name) {
0
+ var filterName = context + '_filter'
0
+ $(filterName).value = ($F(filterName) == name) ? '' : name;
0
+ this.deselect(context, filterName);
0
+ $('page').value = '1';
0
+ $('query-form').onsubmit();
0
+ },
0
+
0
+ deselect: function(context, filterName) {
0
+ $$('#' + context + ' a').each(function(a) {
0
+ var value = $(filterName) ? $F(filterName) : null;
0
+ a.className = (value && (a.getAttribute('title') == value || a.innerHTML == value)) ? 'selected' : '';
0
+ });
0
+ }
0
+}
0
+
0
+Event.observe(window, 'load', function() {
0
+ ExceptionLogger.filters.each(function(context) {
0
+ $(context + '_filter').value = '';
0
+ });
0
+});
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
0
@@ -0,0 +1,292 @@
0
+body
0
+{
0
+ margin:0;
0
+ padding:0;
0
+ background:#000;
0
+ font-family:'Lucida Grande', Arial, Helvetica, sans-serif;
0
+ font-size:1.0em;
0
+ color:white;
0
+}
0
+
0
+#container
0
+{
0
+ xwidth:95%;
0
+ margin:0 auto;
0
+ min-width:800px;
0
+}
0
+
0
+#left
0
+{
0
+ xfloat:left;
0
+ xwidth:76%;
0
+ margin-right:235px;
0
+
0
+}
0
+
0
+#left .page
0
+{
0
+ font-size:0.9em;
0
+ background:white;
0
+ border:2px solid #999;
0
+ border-width:0 2px 2px 0;
0
+ padding:25px;
0
+ xmargin-bottom:1em;
0
+ color:black;
0
+}
0
+
0
+#right
0
+{
0
+ margin-top:1em;
0
+ float:right;
0
+ xwidth:22%;
0
+ font-size:0.9em;
0
+ width:200px;
0
+ margin-right:1.25em;
0
+}
0
+
0
+#right hr
0
+{
0
+ border:0;
0
+ border-top:1px solid #222;
0
+}
0
+
0
+#search
0
+{
0
+ margin-top:2em;
0
+ background:#111;
0
+ padding:10px 5px;
0
+ border:1px solid #222;
0
+ border-width:1px 0;
0
+}
0
+
0
+
0
+ul.filters
0
+{
0
+ list-style-type:none;
0
+ padding:0;
0
+ margin:0;
0
+ font-size:0.9em;
0
+}
0
+ul.filters li { margin-bottom:0.2em;}
0
+
0
+
0
+ul.filters a,
0
+ul.filters a:visited {
0
+ display:block;
0
+ padding:1px 7px;
0
+ color:#fff;
0
+ xbackground-color:#fff;
0
+ text-decoration:none;
0
+}
0
+
0
+ul.filters a:hover
0
+{
0
+ background:#666;
0
+ color:white;
0
+}
0
+
0
+ul.filters a.selected,
0
+ul.filters a.selected:visited,
0
+ul.filters a:active {
0
+ color:gold;
0
+ background-color:#333;
0
+ text-decoration:none;
0
+ font-weight:bold;
0
+}
0
+
0
+
0
+onclick a:hover
0
+{
0
+ color:#fff;
0
+ text-decoration:none;
0
+}
0
+
0
+#exceptions table
0
+{
0
+ width:99%;
0
+ border-collapse:collapse;
0
+}
0
+
0
+td
0
+{
0
+ padding:5px 10px;
0
+ xborder:1px solid #ddd;
0
+}
0
+
0
+#backtrace
0
+{
0
+ overflow:auto;
0
+ font-family:"Bitstream Vera Sans Mono", "Monaco", "Courier", monospace;;
0
+ font-size:0.85em;
0
+ margin-top:0.25em;
0
+}
0
+
0
+h2
0
+{
0
+ background-color:#ddd;
0
+ font-size:0.8em;
0
+ padding:3px 10px;
0
+}
0
+
0
+form {margin:0;}
0
+
0
+h3 {
0
+ font-size:0.8em;
0
+ color:#ddd;
0
+ background:#222;
0
+ padding:3px 7px;
0
+}
0
+
0
+div.date
0
+{
0
+ color:#666;
0
+ font-size:0.8em;
0
+}
0
+
0
+h1
0
+{
0
+ margin-top:0.25em;
0
+ font-size:1.25em;
0
+ padding-bottom:5px;
0
+ border-bottom:2px solid #ddd;
0
+}
0
+
0
+h1 span
0
+{
0
+ color:#aaa;
0
+ font-weight:normal;
0
+}
0
+
0
+a
0
+{
0
+ color:#369;
0
+ text-decoration:none;
0
+}
0
+a:hover
0
+{
0
+ color:blue;
0
+ text-decoration:underline;
0
+}
0
+
0
+th
0
+{
0
+ text-align:left;
0
+ xbackground:#333;
0
+ xcolor:gold;
0
+ font-size:0.75em;
0
+ padding:2px 10px;
0
+}
0
+
0
+tr { xcursor:pointer; }
0
+
0
+tr.eor td
0
+{
0
+ background:#e7e7e7;
0
+
0
+}
0
+
0
+/*
0
+tr:hover td,
0
+tr.eor:hover td
0
+{
0
+ background:#333;
0
+ color:white;
0
+}
0
+tr:hover td a,
0
+tr.eor:hover td a { color:gold; }
0
+*/
0
+
0
+.message
0
+{
0
+ font-size:0.8em;
0
+}
0
+
0
+a.util
0
+{
0
+ color:#c00;
0
+ font-size:0.7em;
0
+}
0
+
0
+.pipe
0
+{
0
+ font-size:0.75em;
0
+ color:#999;
0
+}
0
+
0
+.tools { float:right; }
0
+
0
+.time
0
+{
0
+ color:#666;
0
+ font-size:0.75em;
0
+ xvertical-align:top;
0
+}
0
+
0
+
0
+.expclass
0
+{
0
+ xcolor:#999;
0
+}
0
+.expclass a
0
+{
0
+ font-size:0.9em;
0
+}
0
+
0
+tr.deleted td {
0
+ color:#aaa;
0
+ text-decoration: line-through;
0
+}
0
+tr.deleted td a { color:#aaa; }
0
+
0
+.pages { float:right; margin-right:1em; }
0
+.pages a { text-decoration:underline; }
0
+.pages-bottom { border-top:2px solid #ddd; text-align:right; float:none;
0
+ padding-top:0.4em;
0
+ margin-top:0.4em;
0
+ padding-right:1em;
0
+ margin-right:0;
0
+ }
0
+
0
+/* right */
0
+
0
+#right h4
0
+{
0
+ font-size:0.75em;
0
+ xbackground:#171717;
0
+ xbackground:#333;
0
+ color:#999;
0
+ padding:3px 5px;
0
+ margin-bottom:0.5em;
0
+ font-weight:normal;
0
+}
0
+
0
+/* tabs */
0
+
0
+ul.tabs
0
+{
0
+ list-style-type:none;
0
+ padding:0;
0
+ margin:1em 0;
0
+ float:left;
0
+}
0
+ul.tabs li { float:left; display:inline; }
0
+ul.tabs li a
0
+{
0
+ font-size:0.8em;
0
+ padding:3px 7px;
0
+ margin-right:1em;
0
+ text-decoration:none;
0
+ color:black;
0
+}
0
+
0
+ul.tabs li a:hover
0
+{
0
+ background:#666;
0
+ color:white;
0
+}
0
+ul.tabs li.selected a
0
+{
0
+ background:black;
0
+ color:white;
0
+}
0
+
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
0
@@ -0,0 +1,14 @@
0
+Description:
0
+ The exception migration generator creates a migration for the logged exceptions model.
0
+
0
+ The generator takes a migration name as its argument. The migration name may be
0
+ given in CamelCase or under_score. 'add_exception_table' is the default.
0
+
0
+ The generator creates a migration class in db/migrate prefixed by its number
0
+ in the queue.
0
+
0
+Example:
0
+ ./script/generate exception_migration add_exception_table
0
+
0
+ With 4 existing migrations, this will create an AddExceptionTable migration in the
0
+ file db/migrate/5_add_exception_table.rb
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
0
@@ -0,0 +1,14 @@
0
+class ExceptionMigrationGenerator < Rails::Generator::NamedBase
0
+ attr_reader :exception_table_name
0
+ def initialize(runtime_args, runtime_options = {})
0
+ @exception_table_name = (runtime_args.length < 2 ? 'logged_exceptions' : runtime_args[1]).tableize
0
+ runtime_args << 'add_exception_table' if runtime_args.empty?
0
+ super
0
+ end
0
+
0
+ def manifest
0
+ record do |m|
0
+ m.migration_template 'migration.rb', 'db/migrate'
0
+ end
0
+ end
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0
@@ -0,0 +1,18 @@
0
+class <%= class_name %> < ActiveRecord::Migration
0
+ def self.up
0
+ create_table "<%= exception_table_name %>", :force => true do |t|
0
+ t.column :exception_class, :string
0
+ t.column :controller_name, :string
0
+ t.column :action_name, :string
0
+ t.column :message, :string
0
+ t.column :backtrace, :text
0
+ t.column :environment, :text
0
+ t.column :request, :text
0
+ t.column :created_at, :datetime
0
+ end
0
+ end
0
+
0
+ def self.down
0
+ drop_table "<%= exception_table_name %>"
0
+ end
0
+end
...
 
0
...
1
2
0
@@ -0,0 +1 @@
0
+# Include hook code here
0
\ No newline at end of file
...
 
...
1
0
@@ -0,0 +1 @@
0
+# Install hook code here
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
0
@@ -0,0 +1,90 @@
0
+require 'ipaddr'
0
+
0
+# Copyright (c) 2005 Jamis Buck
0
+#
0
+# Permission is hereby granted, free of charge, to any person obtaining
0
+# a copy of this software and associated documentation files (the
0
+# "Software"), to deal in the Software without restriction, including
0
+# without limitation the rights to use, copy, modify, merge, publish,
0
+# distribute, sublicense, and/or sell copies of the Software, and to
0
+# permit persons to whom the Software is furnished to do so, subject to
0
+# the following conditions:
0
+#
0
+# The above copyright notice and this permission notice shall be
0
+# included in all copies or substantial portions of the Software.
0
+#
0
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
0
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0
+module ExceptionLoggable
0
+ def self.included(target)
0
+ target.extend(ClassMethods)
0
+ end
0
+
0
+ module ClassMethods
0
+ def consider_local(*args)
0
+ local_addresses.concat(args.flatten.map { |a| IPAddr.new(a) })
0
+ end
0
+
0
+ def local_addresses
0
+ addresses = read_inheritable_attribute(:local_addresses)
0
+ unless addresses
0
+ addresses = [IPAddr.new("127.0.0.1")]
0
+ write_inheritable_attribute(:local_addresses, addresses)
0
+ end
0
+ addresses
0
+ end
0
+
0
+ def exception_data(deliverer=self)
0
+ if deliverer == self
0
+ read_inheritable_attribute(:exception_data)
0
+ else
0
+ write_inheritable_attribute(:exception_data, deliverer)
0
+ end
0
+ end
0
+ end
0
+
0
+ def local_request?
0
+ return false
0
+ remote = IPAddr.new(request.remote_ip)
0
+ !self.class.local_addresses.detect { |addr| addr.include?(remote) }.nil?
0
+ end
0
+
0
+ def render_404
0
+ respond_to do |type|
0
+ type.html { render :file => "#{RAILS_ROOT}/public/404.html", :status => "404 Not Found" }
0
+ type.all { render :nothing => true, :status => "404 Not Found" }
0
+ end
0
+ end
0
+
0
+ def render_500
0
+ respond_to do |type|
0
+ type.html { render :file => "#{RAILS_ROOT}/public/500.html", :status => "500 Error" }
0
+ type.all { render :nothing => true, :status => "500 Error" }
0
+ end
0
+ end
0
+
0
+ def rescue_action_in_public(exception)
0
+ case exception
0
+ when ActiveRecord::RecordNotFound, ActionController::UnknownController, ActionController::UnknownAction
0
+ render_404
0
+
0
+ else
0
+ render_500
0
+
0
+ deliverer = self.class.exception_data
0
+ data = case deliverer
0
+ when nil then {}
0
+ when Symbol then send(deliverer)
0
+ when Proc then deliverer.call(self)
0
+ end
0
+
0
+ LoggedException.create_from_exception(self, exception)
0
+ end
0
+ end
0
+
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
0
@@ -0,0 +1,62 @@
0
+class LoggedException < ActiveRecord::Base
0
+ class << self
0
+ def create_from_exception(controller, exception)
0
+ create! \
0
+ :exception_class => exception.class.name,
0
+ :controller_name => controller.controller_name,
0
+ :action_name => controller.action_name,
0
+ :message => exception.message.inspect,
0
+ :backtrace => exception.backtrace,
0
+ :request => controller.request
0
+ end
0
+
0
+ def find_exception_class_names
0
+ connection.select_values "SELECT DISTINCT exception_class FROM #{table_name} ORDER BY exception_class"
0
+ end
0
+
0
+ def find_exception_controllers_and_actions
0
+ find(:all, :select => "DISTINCT controller_name, action_name", :order => "controller_name, action_name").collect(&:controller_action)
0
+ end
0
+ end
0
+
0
+ def backtrace=(backtrace)
0
+ if backtrace.is_a?(String)
0
+ write_attribute :backtrace, backtrace
0
+ else
0
+ re = Regexp.new(/^#{Regexp.escape(rails_root)}/)
0
+ write_attribute(:backtrace, backtrace.collect { |line| Pathname.new(line.gsub(re, "[RAILS_ROOT]")).cleanpath.to_s } * "\n")
0
+ end
0
+ end
0
+
0
+ def request=(request)
0
+ if request.is_a?(String)
0
+ write_attribute :request, request
0
+ else
0
+ max = request.env.keys.max { |a,b| a.length <=> b.length }
0
+ env = request.env.keys.sort.inject [] do |env, key|
0
+ env << '* ' + ("%*-s: %s" % [max.length, key, request.env[key].to_s.strip])
0
+ end
0
+ write_attribute(:environment, (env << "* Process: #{$$}" << "* Server : #{`hostname -s`.chomp}") * "\n")
0
+
0
+ write_attribute(:request, [
0
+ "* URL: #{request.protocol}#{request.env["HTTP_HOST"]}#{request.request_uri}",
0
+ "* Parameters: #{request.parameters.inspect}",
0
+ "* Rails Root: #{rails_root}"
0
+ ] * "\n")
0
+ end
0
+ end
0
+
0
+ def controller_action
0
+ "#{controller_name.camelcase}/#{action_name}"
0
+ end
0
+
0
+ private
0
+ def sanitize_backtrace(trace)
0
+ re = Regexp.new(/^#{Regexp.escape(rails_root)}/)
0
+ trace.map { |line| Pathname.new(line.gsub(re, "[RAILS_ROOT]")).cleanpath.to_s }
0
+ end
0
+
0
+ def rails_root
0
+ @rails_root ||= Pathname.new(RAILS_ROOT).cleanpath.to_s
0
+ end
0
+end
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
0
@@ -0,0 +1,41 @@
0
+class LoggedExceptionsController < ActionController::Base
0
+ self.template_root = File.join(RAILS_ROOT, 'vendor/plugins/exception_logger/views')
0
+ layout nil
0
+
0
+ def index
0
+ @exception_names = LoggedException.find_exception_class_names
0
+ @controller_actions = LoggedException.find_exception_controllers_and_actions
0
+ query
0
+ end
0
+
0
+ def query
0
+ conditions = []
0
+ parameters = []
0
+ unless params[:query].blank?
0
+ conditions << 'message LIKE ?'
0
+ parameters << "%#{params[:query]}%"
0
+ end
0
+ unless params[:date_ranges_filter].blank?
0
+ conditions << 'created_at >= ?'
0
+ parameters << params[:date_ranges_filter].to_f.days.ago.utc
0
+ end
0
+ unless params[:exception_names_filter].blank?
0
+ conditions << 'exception_class = ?'
0
+ parameters << params[:exception_names_filter]
0
+ end
0
+ unless params[:controller_actions_filter].blank?
0
+ conditions << 'controller_name = ? AND action_name = ?'
0
+ parameters += params[:controller_actions_filter].split('/').collect(&:downcase)
0
+ end
0
+ @exception_pages, @exceptions = paginate :logged_exceptions, :order => 'created_at desc', :per_page => 30,
0
+ :conditions => conditions.empty? ? nil : parameters.unshift(conditions * ' and ')
0
+ end
0
+
0
+ def show
0
+ @exc = LoggedException.find params[:id]
0
+ end
0
+
0
+ def destroy
0
+ LoggedException.destroy params[:id]
0
+ end
0
+end
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0
@@ -0,0 +1,15 @@
0
+module LoggedExceptionsHelper
0
+ def filtered?
0
+ [:query, :date_ranges_filter, :exception_names_filter, :controller_actions_filter].any? { |p| params[p] }
0
+ end
0
+
0
+ def pagination_remote_links(paginator, options={}, html_options={})
0
+ name = options[:name] || ActionController::Pagination::DEFAULT_OPTIONS[:name]
0
+ params = (options[:params] || ActionController::Pagination::DEFAULT_OPTIONS[:params]).clone
0
+
0
+ pagination_links_each(paginator, options) do |n|
0
+ params[name] = n
0
+ link_to_function n.to_s, "ExceptionLogger.setPage(#{n})"
0
+ end
0
+ end
0
+end
0
\ No newline at end of file
...
 
 
 
 
0
...
1
2
3
4
5
0
@@ -0,0 +1,4 @@
0
+# desc "Explaining what the task does"
0
+# task :exception_logger do
0
+# # Task goes here
0
+# end
0
\ No newline at end of file
...
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
0
@@ -0,0 +1,8 @@
0
+require 'test/unit'
0
+
0
+class ExceptionLoggerTest < Test::Unit::TestCase
0
+ # Replace this with your real tests.
0
+ def test_this_plugin
0
+ flunk
0
+ end
0
+end
...
 
...
1
0
@@ -0,0 +1 @@
0
+# Uninstall hook code here
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
0
@@ -0,0 +1,79 @@
0
+<div id="exceptions">
0
+
0
+<% if @exception_pages.page_count>1 %>
0
+<div class="pages">
0
+Pages: <strong><%= pagination_remote_links @exception_pages, :params => { :action => :index } %></strong>
0
+</div>
0
+<% end %>
0
+
0
+<h1>Exceptions <%= "<span>(filtered)</span>" if filtered? %> </h1>
0
+
0
+<table cellspacing="0">
0
+
0
+ <thead style="display:none;">
0
+ <tr>
0
+ <th>Exception</th>
0
+ <th>Date</th>
0
+<!--
0
+ <th></th>
0
+
0
+ <th><%= link_to_function "All", "$$('#exceptions table input').each(function(a){a.checked= (a.checked ? '' : 'checked'); });" %></th>
0
+-->
0
+ </tr>
0
+ </thead>
0
+
0
+ <tbody>
0
+ <% exceptions.each do |exc| -%>
0
+ <tr id="exception-<%= exc.id %>" class="<%= cycle("eor", "") %>">
0
+ <td>
0
+<div class="expclass">
0
+
0
+<%= link_to_remote "#{exc.exception_class} in #{exc.controller_action}", :url => { :action => 'show', :id => exc } %></div>
0
+<span class="message"><%=h exc.message %></span>
0
+
0
+</td>
0
+ <td nowrap=nowrap class="time">
0
+<!--
0
+
0
+-->
0
+<%
0
+if Date.today==exc.created_at.to_date
0
+ if exc.created_at > Time.now - 4.hours
0
+ %>
0
+ <%= time_ago_in_words(exc.created_at).gsub(/about /,"~ ") %> ago
0
+ <% else %>
0
+ Today, <%= exc.created_at.strftime("%l:%M %p") %>
0
+ <% end %>
0
+<% else %>
0
+<%= exc.created_at.strftime("%b %d, %Y") %>