简体   繁体   中英

Prepend user ID to all log messages in Rails

In order to help track user actions for debugging purposes, we are considering prepending the session's logged in user ID to every log message (when applicable). Our stack consists of Rails and Authlogic. I've tried a couple of different routes, but none has been 100% successful so far.

Since Authlogic does not store the user ID in plain text in the session data, we have to wait for it to be initialized. This happens only after the ApplicationController is initialized and set to be the active Authlogic controller. We cannot rely on code in config/application.rb because of this. It seems to me the only solution is to swap out the logger at a later time.

I've attempted creating a new logger class by subclassing Logger and overwriting the add() method:

class UserLogger < Logger
  def add(severity, message = nil, progname = nil, &block)
    begin
      session = UserSession.find
    rescue
      return super(severity, message, progname, &block)
    end

    user = session.user if session

    if block_given? || !user
      return super(severity, message, progname, &block)
    end

    unless message.nil?
      message = "[#{user.id}] " + message
    end

    super severity, message, progname, &block
  end
end

This doesn't seem to have any affect on the log outpost whatsoever. I also tried messing around with TaggedLogging, but that doesn't seem to be a good solution since you have to throw any tagged code in a block.

I also tried defining config.log_tags in the application config by giving it a Proc, but Authlogic threw the same Authlogic::Session::Activation::NotActivatedError exception. Attempting to catch this exception put Ruby into a very weird state that seemed to be an infinite loop somewhere and pegged my CPU at 100%.

Is there a simple solution to this or one I am completely missing?

It is not possible to access the session object from the request object. But you can access cookies .

So, add this code after your user login:

cookies.signed[:user_id] = @user.id

And add an initializer like:

MyApp::Application.config.log_tags = [
    -> request { "user-#{request.cookie_jar.signed[:user_id]}" }
]

Now all your logs will have [user-980191314] or [user-] prepended.

My project is using a custom logger as well, and we hook it up in environments/production.rb. Are you setting the Rails logger in production.rb?

config.logger = ActiveSupport::TaggedLogging.new(UserLogger.new)

Just adding on the Vedant's answer. Sometimed we don't need to print anything if User is not logged in. In that case:

config.log_tags = [Proc.new { |request|.request.cookie_jar:signed[.user_id]?nil? : "user_id. #{request.cookie_jar:signed[:user_id]}" : false } ]

Now the logs will have [user_id: XXXXXXXXX] prepended when any user is logged in otherwise, nothing will be prepended.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM