Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I log particular events from Rails to a log file?

Requirements

I would like to keep an audit log of particular events, such as:

  • User logged in successfully
  • User could not log in (with reason: wrong password, unconfirmed, etc.)
  • SuperUser modified another users details (with what they changed)
  • etc.

This log should include details such as:

  • The logged in user performing the action (based on the controller's current_user)
  • The record being modified (such as the other user record in the case of super users)
  • The IP address of request for that action

This log should also be stored in a file on the filesystem, not a database table so it can be ingested by another service on the machine at a later time.

Some possibilities

Here is a short list of the approaches I have considered so far:

ActiveRecord::Observer

Observers give a nice separated way of watching for these particular events.
I could then get the observer to append to a log file, but I'm not sure how easy I would be able to obtain the result of such a call (such as login failed or worked) and I would need to somehow call the controller method current_user to find out the logged in user and get the HTTP request to obtain the IP address.

An auditing gem (such as audited, auditable, paper_trail, etc.)

These gems have the convenience of knowing how to get access to the controller for the current user and IP address, but they all log to an audit table in the database. Auditable is particularly nice because it can audit any method call on an object, not just an AR callback, but I may need to patch it to write to a file instead of the database.. or something?

ActiveSupport::Notifications

I still need to read up on this, but I believe it offers low-level a way of subscribing to low-level events within rails. This might be too low-level for this situation, but I need to investigate further.

Log4r

It seems this will make a nice log file, but I don't think it has any way of watching for events. This would only be part of the problem.

Any advice?

Is there a best practices way of doing this? Can you recommend any gems or lessons learned from previous experience? Anything else I should consider?

like image 692
Steve Occhipinti Avatar asked Oct 27 '25 03:10

Steve Occhipinti


1 Answers

Thanks to everyone for the responses.
Casper, I did decide to build something custom.

I see your point with writing to a local db anyway, but the requirement for this project is to dump log files so a more elaborate log parsing service can interrogate the files and even combine them with information from other sources.

In order to get logging from both models and controllers, I ended up making a module that I would include in both the observers and ApplicationController.

The module looks a little something like this:

module MyEventLogger
  mattr_accessor :logged_current_user
  mattr_accessor :logged_remote_ip

  def log_event(message)
    @@logger ||= Logger.new(Rails.root.join('log', 'audit.log'))
    @@logger.info "#{Time.now} | #{logged_current_user}@#{logged_remote_ip} | #{message}"
  end

  def logged_current_user
    @@logged_current_user || "SYSTEM"
  end

  def logged_remote_ip
    @@logged_remote_ip || "NO IP ADDRESS"
  end
end

ApplicationController would have:

include MyEventLogger
before_filter :setup_logger

...

def setup_logger
  MyEventLogger.logged_current_user = current_user
  MyEventLogger.logged_ip_address = request.remote_ip
end

The observer would just have to include MyEventLogger and it would have access to the log_event method and the current user and ip address. For example:

class UserObserver < ActiveRecord::Observer
  include MyEventLogger

  def after_save(user)
    log_event "The User #{user} was saved by #{logged_current_user}"
  end

end
like image 96
Steve Occhipinti Avatar answered Oct 29 '25 19:10

Steve Occhipinti



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!