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.
9 Answers
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.

- 33,360
- 7
- 30
- 34
-
5If you want to change all the default logging for that specific model, you can simply use `User.logger = Logger.new(STDOUT)` or wherever you want to log to. In the same way, `ActiveRecord::Base.logger = Logger.new(STDOUT)` will change all the logging for all models. – Dave Aug 29 '11 at 21:31
-
Anyone know how to create folders to each log? – Mauro Dias Feb 26 '13 at 17:59
-
2@Dave I've tried your suggestion and it failed. `User.logger = Logger.new(STDOUT)` changed all the logging for all models. Well, it changed `ActiveRecord::Base.logger` – fetsh Apr 30 '13 at 15:51
-
@ilzoff Yep, it's quite possible this behaviour has changed in Rails since 3 years ago. Thanks for calling this out. – Dave Oct 14 '14 at 12:09
-
Thanks. Did pretty much the same for my controllers by placing `my_logger` in `application_controller.rb`. – stratis Dec 03 '17 at 09:48
-
In Rails 5 you can just write `Logger.new('my.log')`. It assumes your project `log` dir by default. – tetiross Jan 05 '18 at 12:50
-
@TeTiRoss I tried that, but it created log file in the project root dir. – x-yuri Jun 12 '18 at 11:38
-
For the curious, [here](https://github.com/rails/rails/blob/v5.2.0/activerecord/lib/active_record/base.rb#L293)'s where `logger=` method is [defined](https://github.com/rails/rails/blob/v5.2.0/activerecord/lib/active_record/core.rb#L18). – x-yuri Jun 12 '18 at 19:38
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

- 17,572
- 15
- 110
- 169
-
2
-
2@DanielCosta https://stackoverflow.com/questions/2177008/what-is-the-meaning-of-in-ruby – lulalala Oct 19 '18 at 01:38
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"

- 16,443
- 6
- 61
- 75

- 1,380
- 14
- 8
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")

- 5,662
- 1
- 29
- 32
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

- 18,776
- 31
- 129
- 193
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.
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')

- 5,198
- 5
- 40
- 44
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.

- 1,918
- 16
- 20