← recent

Watching Your Logs From The Console

I’ve often wished there was a way to see the rails logs right inside the console window, instead of having to switch back and forth betweeh console and a “tail -f” process. It wasn’t hard to find an answer – Jamis Buck blogged about it back in 2007 – but it didn’t quite do all I was hoping for, so I ended up going a different route, which I think gives a more complete solution.

The solution that I saw on Jamis’ blog was to replace wholesale the rails logger:

ActiveRecord::Base.logger = Logger.new(STDOUT)

The problems with this are:

  1. It must be done before any AR::Base logging is done, and
  2. It cannot be undone.
    (Both due to the logger object being cached)

For my needs, I’m interested in the logs for a particular method call, but I don’t really want to see all the logs, all the time. So, I wrote the code that follows (at the end of this post), and put it in my .irbrc file. It gets around the cached logger object by altering the logger, rather than trying to replace it. This allows me to turn it on or off mid-session. For example (from a personal side project):

>> wr = WeightRecord.first
=> #<weightrecord id:="id:">
...  # More commands, which I don't care to see the logs from ...
>> wr.weight = 176
=> 176

>> show_log
=> nil
>> wr.save
SQL (0.000154)   BEGIN
SQL (0.069810)   SELECT `date` FROM `weight_records` WHERE (`weight_records`.date = '2007-10-28' AND `weight_records`.user_id = 1 AND `weight_records`.id 
 1)
WeightRecord Update (0.000688)   UPDATE `weight_records` SET `updated_at` = '2009-03-16 01:04:08', `weight` = 176.0 WHERE `id` = 1
SQL (0.004874)   COMMIT
=> true

>> hide_log
=> nil
...  # More stuff I don't need to see the logs from...
</weightrecord>

(The “SELECT `date`” bit in the logs is because my model has: “validates_uniqueness_of :date, :scope => :user_id”)

The code:

def show_log
  unless @log_buffer_size
    @log_file = Rails.logger.instance_variable_get("@log")
    @log_level = Rails.logger.level
    @log_buffer_size = Rails.logger.auto_flushing
  end
  Rails.logger.flush
  Rails.logger.instance_variable_set("@log", STDOUT)
  Rails.logger.level = Logger::DEBUG
  Rails.logger.auto_flushing = 1
  nil
end

def hide_log
  if @log_buffer_size
    Rails.logger.instance_variable_set("@log", @log_file)
    Rails.logger.level = @log_level
    Rails.logger.auto_flushing = @log_buffer_size
  end
  nil
end