-
Notifications
You must be signed in to change notification settings - Fork 76
/
request_logger.rb
154 lines (124 loc) · 3.64 KB
/
request_logger.rb
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
require 'grape/middleware/base'
module GrapeLogging
module Middleware
class RequestLogger < Grape::Middleware::Base
ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
event = ActiveSupport::Notifications::Event.new(*args)
GrapeLogging::Timings.append_db_runtime(event)
end if defined?(ActiveRecord)
# Persist response status & response (body)
# to use int in parameters
attr_accessor :response_status, :response_body
def initialize(app, options = {})
super
@included_loggers = @options[:include] || []
@reporter = if options[:instrumentation_key]
Reporters::ActiveSupportReporter.new(@options[:instrumentation_key])
else
Reporters::LoggerReporter.new(@options[:logger], @options[:formatter], @options[:log_level])
end
end
def before
reset_db_runtime
start_time
invoke_included_loggers(:before)
end
def after(status, response)
stop_time
# Response status
@response_status = status
@response_body = response
# Perform repotters
@reporter.perform(collect_parameters)
# Invoke loggers
invoke_included_loggers(:after)
nil
end
# Call stack and parse responses & status.
#
# @note Exceptions are logged as 500 status & re-raised.
def call!(env)
@env = env
# Before hook
before
# Catch error
error = catch(:error) do
begin
@app_response = @app.call(@env)
rescue => e
# Log as 500 + message
after(e.respond_to?(:status) ? e.status : 500, e.message)
# Re-raise exception
raise e
end
nil
end
# Get status & response from app_response
# when no error occures.
if error
# Call with error & response
after(error[:status], error[:message])
# Throw again
throw(:error, error)
else
status, _, resp = *@app_response
# Call after hook properly
after(status, resp)
end
# Otherwise return original response
@app_response
end
protected
def parameters
{
status: response_status,
time: {
total: total_runtime,
db: db_runtime,
view: view_runtime
},
method: request.request_method,
path: request.path,
params: request.params,
host: request.host
}
end
private
def request
@request ||= ::Rack::Request.new(@env)
end
def total_runtime
((stop_time - start_time) * 1000).round(2)
end
def view_runtime
total_runtime - db_runtime
end
def db_runtime
GrapeLogging::Timings.db_runtime.round(2)
end
def reset_db_runtime
GrapeLogging::Timings.reset_db_runtime
end
def start_time
@start_time ||= Time.now
end
def stop_time
@stop_time ||= Time.now
end
def collect_parameters
parameters.tap do |params|
@included_loggers.each do |logger|
params.merge! logger.parameters(request, response_body) do |_, oldval, newval|
oldval.respond_to?(:merge) ? oldval.merge(newval) : newval
end
end
end
end
def invoke_included_loggers(method_name)
@included_loggers.each do |logger|
logger.send(method_name) if logger.respond_to?(method_name)
end
end
end
end
end