diff --git a/.gitignore b/.gitignore index d87d4be..00d9939 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# RubyMine project files +.idea + *.gem *.rbc .bundle diff --git a/README.markdown b/README.markdown index 539a426..00cd4e7 100644 --- a/README.markdown +++ b/README.markdown @@ -37,7 +37,7 @@ Include the middleware in your API classes with the `use` statement Require the middleware in `config/application.rb` - config.middleware.use( 'Rack::Logjam::Middleware' ) + config.middleware.use( 'Rack::Logjam::Rails::Middleware' ) ### Configuration diff --git a/lib/rack/logjam/filters.rb b/lib/rack/logjam/filters.rb index f01ba6a..6608ad1 100644 --- a/lib/rack/logjam/filters.rb +++ b/lib/rack/logjam/filters.rb @@ -3,6 +3,7 @@ module Logjam module Filters autoload :Base, 'rack/logjam/filters/base' + autoload :FormUrlencoded, 'rack/logjam/filters/form_urlencoded' autoload :Json, 'rack/logjam/filters/json' autoload :Nil, 'rack/logjam/filters/nil' diff --git a/lib/rack/logjam/filters/form_urlencoded.rb b/lib/rack/logjam/filters/form_urlencoded.rb new file mode 100644 index 0000000..fdf17ee --- /dev/null +++ b/lib/rack/logjam/filters/form_urlencoded.rb @@ -0,0 +1,71 @@ +require 'jsonpath' + +module Rack + module Logjam + module Filters + class FormUrlencoded < Rack::Logjam::Filters::Base + + def render + return content if blank_content? + apply_filters + query_hash.to_query + end + + protected + + def blank_content? + content.nil? || content.strip.empty? + end + + def apply_filters + filters.each do |param, action, length| + if value = query_hash[param] + if value.is_a?(Array) + query_hash[param] = value.map { |array_item| filter(array_item, action, length) } + else + query_hash[param] = filter(value, action, length) + end + end + end + end + + def filter(value, action, length) + method_name = "#{action}_#{value.class.name.downcase}" + if respond_to?( method_name, true ) + send( method_name, value, length ) + else + "[#{action.upcase}ED: #{value.class.name}]" + end + end + + def redact_nilclass( val, *args ) + nil + end + + def truncate_nilclass( val, length ) + nil + end + + def redact_string( val, *args ) + (val.nil? || val.empty?) ? + val : + "[REDACTED]" + end + + def truncate_string( val, length ) + (val.nil? || val.empty?) ? + val : + "#{val[0..length]}...[TRUNCATED]..." + end + + def query_hash + # This gives a weird response where every value is an array, even when there's no key + # @query_hash ||= CGI.parse(content) + + @query_hash ||= Rack::Utils.parse_nested_query(content) + end + + end + end + end +end diff --git a/lib/rack/logjam/grape/middleware.rb b/lib/rack/logjam/grape/middleware.rb index b13c59b..9bf4efa 100644 --- a/lib/rack/logjam/grape/middleware.rb +++ b/lib/rack/logjam/grape/middleware.rb @@ -7,17 +7,17 @@ module Grape class Middleware < ::Grape::Middleware::Base def before - return unless api_request?( env ) - logger.log_request( env ) end def after - return unless api_request?( env ) - - status = @app_response.first - headers = @app_response[1] - body = @app_response.last.body.last + if @app_response.nil? + ::Rack::Logjam::logger.info "@app_response is nil. WTF Grape? https://github.com/ruby-grape/grape/issues/1265" + return + end + status = @app_response.status + headers = @app_response.header + body = @app_response.body.last #logger.log_response( env, status, headers, response ) logger.log_response( env, status, headers, body ) diff --git a/lib/rack/logjam/logger.rb b/lib/rack/logjam/logger.rb index 24afbec..3b72151 100644 --- a/lib/rack/logjam/logger.rb +++ b/lib/rack/logjam/logger.rb @@ -5,82 +5,75 @@ module Rack module Logjam class Logger - def log_request( env ) - _logger.info <<-end_info -[#{ANSI.green { 'api' }}] #{ANSI.cyan { '--- Request Env ---' }} -#{ANSI.magenta { JSON.pretty_generate( request_log_data( env )) }} -[#{ANSI.green { 'api' }}] #{ANSI.cyan { '--- Request Body ---' }} -#{ANSI.cyan { formatted_request_body( env ) }} -end_info + def log_request(env) + _logger.info "HTTP Request: #{ANSI.magenta { request_log_data(env).inspect }}" + formatted_body = formatted_request_body(env) + _logger.info "HTTP Request Body: #{ANSI.cyan { formatted_body }}" if formatted_body end - def log_response( env, status, headers, response ) - _logger.info <<-end_info -[#{ANSI.green { 'api' }}] #{ANSI.cyan { '--- Response ---' }} -Status: #{status} -Headers: #{headers.inspect} -Body: -#{ANSI.cyan { format_body( (response.body rescue response), accept( env ), env ) }} - end_info + def log_response(env, status, headers, response) + _logger.info "HTTP Response: #{status} #{headers.inspect}" + formatted_body = format_body((response.body rescue response), accept(env), env) + _logger.info "HTTP Response Body: #{ANSI.cyan { formatted_body }}" if formatted_body end - protected + protected - def request_log_data( env ) + def request_log_data(env) request_data = { - content_type: content_type( env ), - content_length: env['CONTENT_LENGTH'], - accept: accept( env ), - accept_version: env['HTTP_ACCEPT_VERSION'], - method: env['REQUEST_METHOD'], - path: path_info( env ), - query: query( env ) + content_type: content_type(env), + content_length: env['CONTENT_LENGTH'], + accept: accept(env), + accept_version: env['HTTP_ACCEPT_VERSION'], + method: env['REQUEST_METHOD'], + path: path_info(env), + query: query(env) } #request_data[:user_id] = current_user.id if current_user request_data end - def content_type( env ) + def content_type(env) env['CONTENT_TYPE'] end - def accept( env ) + def accept(env) env['HTTP_ACCEPT'] end - def path_info( env ) + def path_info(env) env['PATH_INFO'] end - def query( env ) - URI.unescape( env['QUERY_STRING'] ) + def query(env) + URI.unescape(env['QUERY_STRING']) end - def formatted_request_body( env ) - format_body( rack_input_content( env ), content_type( env ), env ) + def formatted_request_body(env) + format_body(rack_input_content(env), content_type(env), env) end - def format_body( body, format, env ) - filter = fetch_filter( format, body ) + def format_body(body, format, env) + return if body.nil? || body.strip.empty? + return 'Body too large to log' if body.length > 4096 + filter = fetch_filter(format, body) filtered = filter.render - - formatter = fetch_formatter( format, body ).new( filtered, format ) + formatter = fetch_formatter(format, body).new(filtered, format) formatter.render end - def fetch_filter( format, body ) - klass, filters = Rack::Logjam::Filters.get( format ) - klass.new( body, filters ) + def fetch_filter(format, body) + klass, filters = Rack::Logjam::Filters.get(format) + klass.new(body, filters) end - def fetch_formatter( format, body ) - return Rack::Logjam::Formatters::Empty if body.nil? || body.strip.empty? - return Rack::Logjam::Formatters::Array if body.is_a?( Array ) - Rack::Logjam::Formatters.get( format ) + def fetch_formatter(format, body) + return Rack::Logjam::Formatters::Array if body.is_a?(Array) + Rack::Logjam::Formatters.get(format) unless body.nil? || body.strip.empty? end - def rack_input_content( env ) - ( rack_input = env['rack.input'] ).read.tap do |content| + def rack_input_content(env) + (rack_input = env['rack.input']).read.tap do |content| rack_input.rewind end end diff --git a/lib/rack/logjam/rails/middleware.rb b/lib/rack/logjam/rails/middleware.rb index 6559e90..7ea04c2 100644 --- a/lib/rack/logjam/rails/middleware.rb +++ b/lib/rack/logjam/rails/middleware.rb @@ -11,10 +11,14 @@ def initialize( app ) end def call( env ) - before env - - app.call( env ).tap do |rack_response| - after env, *rack_response + if api_request?(env) + app.call(env) + else + before env + + app.call( env ).tap do |rack_response| + after env, *rack_response + end end end @@ -23,19 +27,15 @@ def call( env ) attr_reader :app def before( env ) - return unless api_request?( env ) - logger.log_request( env ) end def after( env, status, headers, response ) - return unless api_request?( env ) - logger.log_response( env, status, headers, response ) end def api_request?( env ) - path_info( env ) =~ /^\/api\// + !(path_info( env ) =~ /^\/api\//).nil? end def path_info( env ) diff --git a/lib/rack/logjam/version.rb b/lib/rack/logjam/version.rb index 410eba8..b60d259 100644 --- a/lib/rack/logjam/version.rb +++ b/lib/rack/logjam/version.rb @@ -2,7 +2,7 @@ module Rack module Logjam - VERSION = '0.2.1' + VERSION = '0.2.1.1' end