How to log something in Rails in an independent log file?

Ruby on-RailsLogging

Ruby on-Rails Problem Overview


In rails I want to log some information in a different log file and not the standard development.log or production.log. I want to do this logging from a model class.

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

You can create a Logger object yourself from inside any model. Just pass the file name to the constructor and use the object like the usual Rails logger:

class User < ActiveRecord::Base
  def my_logger
    @@my_logger ||= Logger.new("#{Rails.root}/log/my.log")
  end

  def before_save
    my_logger.info("Creating user with name #{self.name}")
  end
end

Here I used a class attribute to memoize the logger. This way it won't be created for every single User object that gets created, but you aren't required to do that. Remember also that you can inject the my_logger method directly into the ActiveRecord::Base class (or into some superclass of your own if you don't like to monkey patch too much) to share the code between your app's models.

Solution 2 - Ruby on-Rails

Update

I made a gem based on the solution below, called multi_logger. Just do this in the initializer:

MultiLogger.add_logger('post')

and call

Rails.logger.post.error('hi')
# or call logger.post.error('hi') if it is accessible.

and you are done.

If you want to code it yourself, see below:


A more complete solution would be to place the following in your lib/ or config/initializers/ directory.

The benefit is that you can setup formatter to prefix timestamps or severity to the logs automatically. This is accessible from anywhere in Rails, and looks neater by using the singleton pattern.

# Custom Post logger
require 'singleton'
class PostLogger < Logger
  include Singleton

  def initialize
    super(Rails.root.join('log/post_error.log'))
    self.formatter = formatter()
    self
  end

  # Optional, but good for prefixing timestamps automatically
  def formatter
    Proc.new{|severity, time, progname, msg|
      formatted_severity = sprintf("%-5s",severity.to_s)
      formatted_time = time.strftime("%Y-%m-%d %H:%M:%S")
      "[#{formatted_severity} #{formatted_time} #{$$}] #{msg.to_s.strip}\n"
    }
  end

  class << self
    delegate :error, :debug, :fatal, :info, :warn, :add, :log, :to => :instance
  end
end

PostLogger.error('hi')
# [ERROR 2012-09-12 10:40:15] hi

Solution 3 - Ruby on-Rails

A decent option that works for me is to just add a fairly plain class to your app/models folder such as app/models/my_log.rb

class MyLog
  def self.debug(message=nil)
    @my_log ||= Logger.new("#{Rails.root}/log/my.log")
    @my_log.debug(message) unless message.nil?
  end
end

then in your controller, or really almost anywhere that you could reference a model's class from within your rails app, i.e. anywhere you could do Post.create(:title => "Hello world", :contents => "Lorum ipsum"); or something similar you can log to your custom file like this

MyLog.debug "Hello world"

Solution 4 - Ruby on-Rails

Define a logger class in (say) app/models/special_log.rb:

class SpecialLog
  LogFile = Rails.root.join('log', 'special.log')
  class << self
    cattr_accessor :logger
    delegate :debug, :info, :warn, :error, :fatal, :to => :logger
  end
end

initialize the logger in (say) config/initializers/special_log.rb:

SpecialLog.logger = Logger.new(SpecialLog::LogFile)
SpecialLog.logger.level = 'debug' # could be debug, info, warn, error or fatal

Anywhere in your app, you can log with:

SpecialLog.debug("something went wrong")
# or
SpecialLog.info("life is good")

Solution 5 - Ruby on-Rails

Here is my custom logger:

class DebugLog
  def self.debug(message=nil)
    return unless Rails.env.development? and message.present?
    @logger ||= Logger.new(File.join(Rails.root, 'log', 'debug.log'))
    @logger.debug(message) 
  end
end

Solution 6 - Ruby on-Rails

class Article < ActiveRecord::Base  
 
      LOGFILE = File.join(RAILS_ROOT, '/log/', "article_#{RAILS_ENV}.log")  
      
      def validate  
        log "was validated!"  
      end   
      
      def log(*args)  
       args.size == 1 ? (message = args; severity = :info) : (severity, message = args)  
       Article.logger severity, "Article##{self.id}: #{message}"  
     end  
     
     def self.logger(severity = nil, message = nil)  
       @article_logger ||= Article.open_log  
       if !severity.nil? && !message.nil? && @article_logger.respond_to?(severity)  
         @article_logger.send severity, "[#{Time.now.to_s(:db)}] [#{severity.to_s.capitalize}] #{message}\n"  
       end  
       message or @article_logger  
     end  
     
     def self.open_log  
       ActiveSupport::BufferedLogger.new(LOGFILE)  
     end  
     
   end  

Solution 7 - Ruby on-Rails

I would suggest using Log4r gem for custom logging. Quoting description from its page:

> Log4r is a comprehensive and flexible logging library written in Ruby for use > in Ruby programs. It features a hierarchical logging system of any number of > levels, custom level names, logger inheritance, multiple output destinations > per log event, execution tracing, custom formatting, thread safteyness, XML > and YAML configuration, and more.

Solution 8 - Ruby on-Rails

class Post < ActiveRecord::Base
	def initialize(attributes)
		super(attributes)
		@logger = Logger.new("#{Rails.root}/log/post.log")
	end

	def logger
		@logger
	end

	def some_method
		logger.info('Test 1')
	end
end

ps = Post.new
ps.some_method
ps.logger.info('Test 2')
Post.new.logger.info('Test 3')

Solution 9 - Ruby on-Rails

The Logging framework, with its deceptively simple name, has the sophistication you crave!

Follow the very short instructions of logging-rails to get started filtering out noise, getting alerts, and choosing output in a fine-grained and high-level way.

Pat yourself on the back when you are done. Log-rolling, daily. Worth it for that alone.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionakshatView Question on Stackoverflow
Solution 1 - Ruby on-RailsThiago ArraisView Answer on Stackoverflow
Solution 2 - Ruby on-RailslulalalaView Answer on Stackoverflow
Solution 3 - Ruby on-RailsVaughn DraughonView Answer on Stackoverflow
Solution 4 - Ruby on-RailsLes NightingillView Answer on Stackoverflow
Solution 5 - Ruby on-RailsDorianView Answer on Stackoverflow
Solution 6 - Ruby on-RailsTonyView Answer on Stackoverflow
Solution 7 - Ruby on-RailsKangurView Answer on Stackoverflow
Solution 8 - Ruby on-RailsArtem PView Answer on Stackoverflow
Solution 9 - Ruby on-RailsolleolleolleView Answer on Stackoverflow