A skeleton web application configured to use Sinatra and ActiveRecord
1module Sinatra
2 class Request
3 def current_controller
4 env["sinatree_current_controller"]
5 end
6 def current_controller=(c)
7 env["sinatree_current_controller"] = c
8 end
9
10 def log_extras
11 env["sinatree_log_extras"] ||= {}
12 end
13
14 def uuid
15 @uuid ||= SecureRandom.uuid
16 end
17 end
18end
19
20module Sinatree
21 class Logger
22 def initialize(app, logger = nil)
23 @app = app
24 @logger = logger
25 end
26
27 def call(env)
28 began_at = Time.now.to_f
29 request = Sinatra::Request.new(env)
30 status, headers, body = @app.call(env)
31 headers["X-Request-Id"] = request.uuid
32 body = Rack::BodyProxy.new(body) {
33 log(env, request, status, headers, began_at, body.try(:first))
34 }
35 [status, headers, body]
36 end
37
38 private
39 # Log the request to the configured logger.
40 def log(env, request, status, headers, began_at, body = nil)
41 logger = @logger || env[RACK_ERRORS]
42
43 # "text/html" -> "html", "application/ld+json; profile..." -> "ld+json"
44 output_format = headers["Content-Type"].to_s.split("/")[1].to_s.
45 split(";")[0]
46
47 msg = [
48 "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}]",
49 "[#{headers["X-Request-Id"]}]",
50 "[#{env["HTTP_X_FORWARDED_FOR"] || env["REMOTE_ADDR"] || "?"}]",
51 "method=#{env["REQUEST_METHOD"]}",
52 "path=#{env["PATH_INFO"]}",
53 "controller=#{request.current_controller}",
54 "input=#{request.content_length.to_i}",
55 "output=#{headers["Content-Length"]}",
56 "format=#{output_format}",
57 "status=#{status}",
58 ]
59
60 case status
61 when 300..399
62 msg << "location=#{headers["Location"]}"
63 when 400..403, 405..499
64 if body
65 msg << "error=\"#{body}\""
66 end
67 end
68
69 msg += [
70 "duration=#{sprintf("%0.2f", Time.now.to_f - began_at)}",
71 "params=#{App.filter_parameters(request.params).inspect}",
72 ]
73
74 request.log_extras.each do |k,v|
75 msg << "#{k}=#{v}"
76 end
77
78 msg = msg.join(" ") << "\n"
79
80 if logger.respond_to?(:write)
81 logger.write(msg)
82 else
83 logger << msg
84 end
85 rescue => e
86 STDERR.puts "failed writing log!: #{e.message}\n"
87 STDERR.puts e.backtrace.map{|l| " #{l}" }.join("\n")
88 end
89 end
90end