Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 115 lines (96 sloc) 3.056 kb
8aac3b5 @rtomayko add Rack::MailExceptions middleware (songbird)
rtomayko authored
1 require 'net/smtp'
94ba52d @carlhoerberg Replaced TMail with Mail in MailExceptions
carlhoerberg authored
2 require 'mail'
8aac3b5 @rtomayko add Rack::MailExceptions middleware (songbird)
rtomayko authored
3 require 'erb'
4
5 module Rack
6 # Catches all exceptions raised from the app it wraps and
7 # sends a useful email with the exception, stacktrace, and
8 # contents of the environment.
9
10 class MailExceptions
11 attr_reader :config
12
13 def initialize(app)
14 @app = app
15 @config = {
16 :to => nil,
94ba52d @carlhoerberg Replaced TMail with Mail in MailExceptions
carlhoerberg authored
17 :from => ENV['USER'] || 'rack@localhost',
8aac3b5 @rtomayko add Rack::MailExceptions middleware (songbird)
rtomayko authored
18 :subject => '[exception] %s',
19 :smtp => {
94ba52d @carlhoerberg Replaced TMail with Mail in MailExceptions
carlhoerberg authored
20 :address => 'localhost',
8aac3b5 @rtomayko add Rack::MailExceptions middleware (songbird)
rtomayko authored
21 :domain => 'localhost',
22 :port => 25,
23 :authentication => :login,
24 :user_name => nil,
25 :password => nil
26 }
27 }
28 @template = ERB.new(TEMPLATE)
29 yield self if block_given?
30 end
31
32 def call(env)
33 status, headers, body =
34 begin
35 @app.call(env)
36 rescue => boom
37 send_notification boom, env
38 raise
39 end
40 send_notification env['mail.exception'], env if env['mail.exception']
41 [status, headers, body]
42 end
43
44 %w[to from subject].each do |meth|
45 define_method(meth) { |value| @config[meth.to_sym] = value }
46 end
47
48 def smtp(settings={})
49 @config[:smtp].merge! settings
50 end
51
52 private
53 def generate_mail(exception, env)
af3663c @rkh fix indentation
rkh authored
54 mail = Mail.new({
55 :from => config[:from],
56 :to => config[:to],
57 :subject => config[:subject] % [exception.to_s],
58 :body => @template.result(binding)
59 })
8aac3b5 @rtomayko add Rack::MailExceptions middleware (songbird)
rtomayko authored
60 end
61
62 def send_notification(exception, env)
63 mail = generate_mail(exception, env)
64 smtp = config[:smtp]
af3663c @rkh fix indentation
rkh authored
65 # for backward compability, replace the :server key with :address
66 address = smtp.delete :server
67 smtp[:address] = address if address
68 mail.delivery_method :smtp, smtp
69 mail.deliver!
8aac3b5 @rtomayko add Rack::MailExceptions middleware (songbird)
rtomayko authored
70 env['mail.sent'] = true
af3663c @rkh fix indentation
rkh authored
71 mail
72 end
8aac3b5 @rtomayko add Rack::MailExceptions middleware (songbird)
rtomayko authored
73
74 def extract_body(env)
75 if io = env['rack.input']
76 io.rewind if io.respond_to?(:rewind)
77 io.read
78 end
79 end
80
81 TEMPLATE = (<<-'EMAIL').gsub(/^ {4}/, '')
82 A <%= exception.class.to_s %> occured: <%= exception.to_s %>
83 <% if body = extract_body(env) %>
84
85 ===================================================================
86 Request Body:
87 ===================================================================
88
89 <%= body.gsub(/^/, ' ') %>
90 <% end %>
91
92 ===================================================================
93 Rack Environment:
94 ===================================================================
95
96 PID: <%= $$ %>
97 PWD: <%= Dir.getwd %>
98
99 <%= env.to_a.
100 sort{|a,b| a.first <=> b.first}.
101 map{ |k,v| "%-25s%p" % [k+':', v] }.
102 join("\n ") %>
103
104 <% if exception.respond_to?(:backtrace) %>
105 ===================================================================
106 Backtrace:
107 ===================================================================
108
109 <%= exception.backtrace.join("\n ") %>
110 <% end %>
111 EMAIL
112
113 end
114 end
Something went wrong with that request. Please try again.