A skeleton web application configured to use Sinatra and ActiveRecord
1module Rack
2 class ExceptionMailer
3 def initialize(app)
4 @app = app
5 end
6
7 def call(env)
8 return @app.call(env)
9
10 rescue => e
11 unless boring?(e)
12 email e, env
13 end
14
15 return [
16 500,
17 { "Content-Type" => "text/html" },
18 [ "<html><body><h1>Internal Server Error</h1><p>:(</p></body></html>" ],
19 ]
20 end
21
22 private
23 def boring?(exception)
24 [
25 EOFError,
26 Rack::QueryParser::InvalidParameterError,
27 ].include?(exception.class)
28 end
29
30 def email(exception, env)
31 b = body(exception, env)
32
33 if App.exception_recipients.any?
34 Pony.mail(
35 :to => App.exception_recipients,
36 :subject => "[#{App.name}] #{exception.class} exception " <<
37 "(#{exception.message[0, 50]})",
38 :body => b
39 )
40 end
41
42 STDERR.puts b
43 end
44
45 def first_app_call(exception)
46 exception.backtrace.each do |l|
47 if (rp = relative_path(l)).match(/^app\//)
48 return rp
49 end
50 end
51
52 relative_path(exception.backtrace[0])
53 end
54
55 def body(exception, env)
56 o = [
57 "#{exception.class} exception:",
58 "",
59 " #{exception.message}",
60 "",
61 first_app_call(exception),
62 "",
63 "Request:",
64 "-------------------------------",
65 "",
66 " URL: #{env["REQUEST_URI"]}",
67 " Method: #{env["REQUEST_METHOD"]}",
68 " IP address: #{env["REMOTE_ADDR"]}",
69 " User agent: #{env["HTTP_USER_AGENT"]}",
70 "",
71 "Parameters:",
72 "-------------------------------",
73 ]
74
75 App.filter_parameters(env["sinatra.error.params"] || {}).each do |k,v|
76 o.push " #{k}: #{v}"
77 end
78
79 o += [
80 "",
81 "Backtrace:",
82 "-------------------------------",
83 ]
84
85 exception.backtrace.each do |l|
86 o.push " #{relative_path(l)}"
87 end
88
89 o.join("\n")
90 end
91
92 def relative_path(path)
93 if path[0, App.root.length] == App.root
94 path[App.root.length .. -1].gsub(/^\//, "")
95 else
96 path
97 end
98 end
99 end
100end