Skip to content

Instantly share code, notes, and snippets.

@dblock
Created December 10, 2012 01:43
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save dblock/4247912 to your computer and use it in GitHub Desktop.
Save dblock/4247912 to your computer and use it in GitHub Desktop.
API logger with Grape under Rails
class ApiLogger < Grape::Middleware::Base
def before
Rails.logger.info "[api] Requested: #{request_log_data.to_json}\n" +
"[api] #{response_log_data[:description]} #{response_log_data[:source_file]}:#{response_log_data[:source_line]}"
end
private
def request_log_data
request_data = {
method: env['REQUEST_METHOD'],
path: env['PATH_INFO'],
query: env['QUERY_STRING']
}
request_data[:user_id] = current_user.id if current_user
request_data
end
def response_log_data
{
description: env['api.endpoint'].options[:route_options][:description],
source_file: env['api.endpoint'].block.source_location[0][(Rails.root.to_s.length+1)..-1],
source_line: env['api.endpoint'].block.source_location[1]
}
end
end
@onomated
Copy link

Thanks a lot dblock! Been looking for a way to accomplish this. How do I apply this in my grape api?

@onomated
Copy link

Found the Grape::API#use method (http://rubydoc.info/gems/grape/0.2.1/frameshttp://rubydoc.info/gems/grape/0.2.1/frames).
Applied as follows:

class MyAPI < Grape::API
use ApiLogger
end

@hamin
Copy link

hamin commented Oct 28, 2013

@dblock how would you suggest handling post params? I have something like this, but I don't think its very clean. Plus the resulting hash that gets logged isn't as clean as post params being logged in rails:

 def request_log_data
    # Escape the ampersand in the POST data.
    rack_input = env["rack.input"].gets

    if rack_input.present?
      rack_input = rack_input.gsub("&","%26")
      params_data = Rack::Utils.parse_query(rack_input, "&")
    else
      params_data = nil
    end

    request_data = {
      method: env['REQUEST_METHOD'],
      path:   env['PATH_INFO'],
      query:  env['QUERY_STRING'],
      params: params_data
    }
    # request_data[:user_id] = current_user.id if current_user
    request_data
  end

Any suggestions?

@dblock
Copy link
Author

dblock commented Oct 29, 2013

What does Rails log for POST params? Maybe we can replicate something similar?

@kushkella
Copy link

Are the helper methods such as current_user available in the middleware? I have been trying to call those methods but I always get method not found exception.

@pboling
Copy link

pboling commented Jan 14, 2015

@hamin - howdy padner! Do you have any updates to the logger? I am just stumbling onto this now. I've been manually logging params where needed, but I want to implement a global solution now.

Update: I went ahead and kicked its ass. Also @dblock

ruby-grape/grape#894

@aserafin
Copy link

Just recently created gem that accomplish something very similar. Just few lines of code in your app and you will get one log line per request with: status code, path, request time, db time and parameters.

Check it out: https://rubygems.org/gems/grape_logging

@mxvanzant
Copy link

@aserafin -- can you specify where to put those two lines of code -- Ruby beginner here.

@rubyconvict
Copy link

@hamin Yes, dirty... I found a nasty bug in this code:

        # Rack::Utils.parse_query('♥')
        # /.../vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/utils.rb:92: warning: regexp match /.../n against to UTF-8 string
        # => {"♥"=>nil}
        # [2] pry(#<Backbone::ApiLogger>)> Rack::Utils.parse_query('%')
        # ArgumentError: invalid %-encoding (%)
        # from /home/xxx/.rvm/rubies/ruby-2.2.0/lib/ruby/2.2.0/uri/common.rb:382:in `decode_www_form_component'

so the percent sign has to be escaped too, in case somebody wants to use it

rack_input = rack_input.gsub("&", "%26").gsub("%", "%25")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment