Class | Rack::ShowExceptions |
In: |
lib/rack/showexceptions.rb
|
Parent: | Object |
Rack::ShowExceptions catches all exceptions raised from the app it wraps. It shows a useful backtrace with the sourcefile and clickable context, the whole Rack environment and the request data.
Be careful when you use this on public-facing sites as it could reveal information helpful to attackers.
CONTEXT | = | 7 |
# File lib/rack/showexceptions.rb, line 17 17: def initialize(app) 18: @app = app 19: @template = ERB.new(TEMPLATE) 20: end
# File lib/rack/showexceptions.rb, line 22 22: def call(env) 23: @app.call(env) 24: rescue StandardError, LoadError, SyntaxError => e 25: backtrace = pretty(env, e) 26: [500, 27: {"Content-Type" => "text/html", 28: "Content-Length" => backtrace.join.size.to_s}, 29: backtrace] 30: end
# File lib/rack/showexceptions.rb, line 32 32: def pretty(env, exception) 33: req = Rack::Request.new(env) 34: path = (req.script_name + req.path_info).squeeze("/") 35: 36: frames = exception.backtrace.map { |line| 37: frame = OpenStruct.new 38: if line =~ /(.*?):(\d+)(:in `(.*)')?/ 39: frame.filename = $1 40: frame.lineno = $2.to_i 41: frame.function = $4 42: 43: begin 44: lineno = frame.lineno-1 45: lines = ::File.readlines(frame.filename) 46: frame.pre_context_lineno = [lineno-CONTEXT, 0].max 47: frame.pre_context = lines[frame.pre_context_lineno...lineno] 48: frame.context_line = lines[lineno].chomp 49: frame.post_context_lineno = [lineno+CONTEXT, lines.size].min 50: frame.post_context = lines[lineno+1..frame.post_context_lineno] 51: rescue 52: end 53: 54: frame 55: else 56: nil 57: end 58: }.compact 59: 60: env["rack.errors"].puts "#{exception.class}: #{exception.message}" 61: env["rack.errors"].puts exception.backtrace.map { |l| "\t" + l } 62: env["rack.errors"].flush 63: 64: [@template.result(binding)] 65: end