require 'logger' require 'rack/request' require 'active_support/core_ext/class/attribute_accessors' module MongoRequestLogger class Rack cattr_accessor :logger cattr_accessor :ignore_prefixes def self.ignore_prefix prefix self.ignore_prefixes ||= [] self.ignore_prefixes << prefix end self.ignore_prefix '/log' # TODO: dynamically detect this? def initialize(app, options = {}) @app = app @options = options end def logger self.class.logger end def call(env) if logger env['rack.logger'] = logger end if logger && logger.is_a?(MongoRequestLogger::Logger) #HACK: Don't log the log viewer itself self.class.ignore_prefixes.each do |prefix| if env["PATH_INFO"].to_s.start_with? prefix return @app.call(env) end end # TODO: filter parameters # KLUDGE: this will cause parameter parsing to happen twice: once here, once later on in Rails. # Or maybe it's automatically cached in env? logger.log_request do begin request = ::Rack::Request.new(env) begin cl = request.content_length.to_i rescue cl = 0 end options = { path: request.path_info, host: request.host_with_port, user_agent: request.user_agent, ip: request.ip, referer: request.referrer, query_string: request.query_string, request_method: request.request_method, content_type: request.content_type, content_length: cl, params: filter(request.params) } logger.add_metadata options logger.add_metadata_set :tags, "rack" status, headers, body = @app.call(env) logger.add_metadata response: status.to_i [status, headers, body] rescue Exception => e logger.add_metadata response: 500 raise end end else # No logger configured - just pass the request straight through @app.call(env) end end def filter(params) filtered = params.dup filtered.each do |key, value| if (key =~ /password/) && value.is_a?(String) filtered[key] = '*filtered*' end end filtered end end end