15

I'm trying to get some more information into my Rails logs, specifically the requested URI or current params, if available (and I appreciate that they won't always be). However I just don't seem able to. Here's what I've done so far:

#config/environments/production.rb
config.logger = Logger.new(config.log_path)
config.log_level = :error
config.logger.level = Logger::ERROR

#config/environment.rb
class Logger
  def format_message(level, time, progname, msg)
    "**********************************************************************\n#{level} #{time.to_s(:db)} -- #{msg}\n"
  end  
end

So I can customize the message fine, yet I don't seem to be able to access the params/request variables here. Does anyone know if this is possible, and if so how? Or if there's a better way to get this information? (Perhaps even something Redis based?)

Thanks loads,

Dan

Dan Hill
  • 151
  • 1
  • 1
  • 3

3 Answers3

30

(Responding a long time after this was asked, but maybe it will help the next person.)

I just did something similar.

1) you need to override your logger separately from logging request-leve details. Looks like you've figured customizing your logger out. Answer is here: Rails logger format string configuration

2) I log the request and response of all requests into my service. Note, that Rails puts a tonne of stuff into the headers, so just straight dumping the request or the headers is probably a bad idea. Also of note, my application is primarily accessed via an API. If yours is primarily a web-app, as I'm guessing most people's are, you probably don't want to inspect the response.body as it will contain your html.

class ApplicationController < ActionController::Base 
  around_filter :global_request_logging
...
  def global_request_logging 
    http_request_header_keys = request.headers.keys.select{|header_name| header_name.match("^HTTP.*")}
    http_request_headers = request.headers.select{|header_name, header_value| http_request_header_keys.index(header_name)}
    logger.info "Received #{request.method.inspect} to #{request.url.inspect} from #{request.remote_ip.inspect}.  Processing with headers #{http_request_headers.inspect} and params #{params.inspect}"
    begin 
      yield 
    ensure 
      logger.info "Responding with #{response.status.inspect} => #{response.body.inspect}"
    end 
  end 
end
Community
  • 1
  • 1
John Hinnegan
  • 5,864
  • 2
  • 48
  • 64
  • 1
    This is exactly what I was looking for. Worked great. Thank you. – Howler Sep 01 '11 at 19:39
  • This response is amazing! Thanks – Rafael Oliveira Nov 14 '12 at 19:17
  • 2
    Actually it only worked for me when changed from `request.headers` to `request.headers.env`. (I'm using Rails 4). Made edit suggestion. – Igor Medeiros Aug 07 '14 at 18:51
  • I think you want to change `("^HTTP.*")` to `(/^HTTP.*/)` but I'm also curious as to why you're only matching on headers that start with HTTP, other than saying that rails adds a lot of headers. Do all the headers that rails doesn't add start with HTTP? – 0xtobit Jul 09 '18 at 16:42
  • `String#match` is valid with either syntax https://ruby-doc.org/core-2.4.0/String.html#method-i-match. And, yes, rails puts a ton of stuff in there that doesn't actually come over the wire. At the time, no, I was not aware of any headers from the client that weren't prefixed with HTTP. YMMV – John Hinnegan Aug 29 '18 at 13:56
3

This should work! :) cheers.

logger.info({:user_agent => request.user_agent, :remote_ip => request.remote_ip}.inspect)

logger.info(params.inspect)

By the by.. This should be placed in your controllers action. Ex: If you place it in your create action it should also log the user_agent i.e the browser, remote_ip i.e the remote ip of the user and all the params.

Shripad Krishna
  • 10,463
  • 4
  • 52
  • 65
  • Hi Paddy, thanks for this. Whilst this would work, is there a way to automatically have the request/params available to the logger itself? I.e. if, rather than me calling logger.info/warn/error from the controller, it's been called from an exception being raised anywhere in the code. E.g. I may have in the code a wayward call to current_user.profesion.blank? This would error as profesion should be profession (undefined function on nil etc). It would be great in the log to have the url/current params as well as the stack trace. – Dan Hill Apr 19 '10 at 16:03
  • I tried that. But as you said Logger is configured before Rails is loaded. I found this article which i don't really know how helpful it might be: http://www.ubuntusolutions.org/2009/08/custom-logger-in-rails.html – Shripad Krishna Apr 19 '10 at 16:40
  • Yea. The other way round it might be to somehow extend the class/code that calls the Raise/logger in the first place, to add some extra data into the msg? Even just the ActionController somewhere? – Dan Hill Apr 19 '10 at 17:00
  • This might help with the params problem. But is still too verbose. `ActionController::Base.logger = Logger.new(STDOUT)` – Shripad Krishna Apr 19 '10 at 17:21
0

you should look in the request class

like puts request.uri.

check here for more detail http://api.rubyonrails.org/classes/ActionController/AbstractRequest.html

VP.
  • 5,122
  • 6
  • 46
  • 71
  • Thanks VP, but it doesn't seem to work. I believe, because the Logger is configured before most of Rails is loaded, it doesn't have access to the @env variable, or indeed the params/request variables. @env is nil within the scope of the format_message, as is request, and request_uri thus errors too. – Dan Hill Apr 19 '10 at 14:08