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 155
|
require 'grape'
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
|