Log4r and Rails 7
In a rails application I am working on I needed to set up logging for the events happening in the system. After a little perusing on the net I figured that log4r was the way to go. Then as with a lot of ruby apps, I found the documentation wanting. Yes I know the api and source is on line but a little more help to get started would be helpful. So I thought I would share what I had gleaned from the various sources and how I got it working.
Here are the problems I encountered and the solutions I came up with:
Install
Installation is easy using gem:
gem install log4r
Now you must include the log4r classes in your code with
require "log4r"
What is required for a simple logging setup?
First you must create a new logger. You can do that with code like:
MyLog = Log4r::Logger.new("mylog")
Now you must create an outputter for your log
I was interested in logging to a file so didn't bother with figuring out the ins and outs of logging to different devices.
To create a simple logger that logs to the file mylog.log in the rails log directory, you would create code like this:
Log4r::FileOutputter.new('my_log'
:filename=>"#{RAILS_ROOT}/log/mylog.log",
:trunc=>false)
This will create the log file named my_log which logs to the file mylog.log in the rails log directory and append to it. Note: Log4r has a log rotator, but since I am developing on linux, I elected to just let the system rotate my log files.
Now we must associate this file outputter with the logger we created earlier.
To do that we just user the following code:
myLog.add('my_log')
To put it all together
require "log4r"
MyLog = Log4r::Logger.new("mylog")
Log4r::FileOutputter.new('my_log'
:filename=>"#{RAILS_ROOT}/log/mylog.log",
:trunc=>false)
myLog.add('my_log')
Where do you put this code in a typical rails application?
I came up with two places, useful for different things.
First I placed it in config/environment.rb. This worked well, but I had to restart the web server every time I made a change. Debug messages were non-existent also.
Next I placed the setup in app/controllers/application.rb. This allowed me to make changes without restarting the webserver but slowed down the application.
So I did the initial setup and tweaking of the logging with the code in application.rb and moved it to environment.rb when it was done.
Now that we have the log setup how is it used?
Each log4r logger has default logging levels
DEBUG < INFO < WARN < ERROR < FATALTo log something in our code you would use something like:
MyLog.info('My Log Message')
This will produce log output like
INFO MyLog: My Log Message
You log a message by giving the name of your logger and the log level.
What if I want to change the levels?
In the application I am writing I needed to log login/logouts and all activity of the users. To do this I wanted different log levels than the default. Here is how I did it: First I had to include the log4r configurator like this:
require "log4r/configurator"Then I configured my custom levels:
Log4r::Configurator.custom_levels "Error","Access","Activity","Debug"These two lines were placed immediately after the initial require, before creating the logger. Now I could create log messages with:
MyLog.access("User #{@user.name} logged in")
Producing a log message like:
Access MyLog: User tomw logged in
What about changing the log format?
Log4r has several different log format options built in Basic Formatter (the default formatter), Object Formatter, Pattern Formatter and Simple Formatter. None of these produced exactly the output I wanted and Log4r allows you to create your own formatters. The way you do this is to create a class of the type Log4r::Formatter and use it in place of the built in formatters. A Formatter class looks like this:
class MyFormatter < Log4r::Formatter
def format(event)
buff = Time.now.strftime("%a %m/%d/%y %H:%M %Z")
buff += " - #{Log4r::LNAMES[event.level]}"
buff += " - #{event.data}\n"
end
end
This formatter produces log lines that look like this:
Thu 02/01/07 10:03 EST - Access - User Alfred E Newman From IP: 12.13.14.15 -- User Logged in.Change the buff statements in your class to reflect how you want the log line to look. I have another log that I only wanted to contain the data I feed it. The formatter looks like this:
class UpFormatter < Log4r::Formatter
def format(event)
"#{event.data}\n"
end
end
It puts a line in the log that only contain the data given it. Thus the log line:
MyLog.access("Some Log Event")
Will produce the following log line:
Some Log Event
How do you hook these new formatters into your log?
Its simple. When you are creating the log outputter simply add the formatter to the options hash, Thusly:
Log4r::FileOutputter.new('my_log',
:filename=>"#{RAILS_ROOT}/log/mylog.log",
:trunc=>false,
:formatter=> MyFormatter)
This only scratches the surface of what you can do with log4r but should get you going.

very useful, thanks much!
Have you run into problems such as http://dev.rubyonrails.org/ticket/3512 ? I would like to use log4r too, but elsewhere it is not recommended for rails.
I have not encountered any problems. My environment:
Ruby version 1.8.5 (i386-linux) RubyGems version 0.9.2 Rails version 1.2.1 Active Record version 1.15.1 Action Pack version 1.13.1 Action Web Service version 1.2.1 Action Mailer version 1.3.1 Active Support version 1.4.0
Tom, have you avoided the http://dev.rubyonrails.org/ticket/3512 issue because you did not have the default logger for the entire app use log4r?
These 2 settings make log4r the default and I think lead to the issue above: [in environment.rb] config.active_record.logger = myLog config.logger = myLog
You are correct in that I did not use log4r as the default logger, I left the default logger alone. I only used log4r for the custom logging I implemented. Perhaps that is why I have not encountered this bug.
Very useful but there are a couple of bugs in your sample code marked “putting it all together”. First, there is a comma missing at the end of the line:
Log4r::FileOutputter.new(‘my_log’
Second, the last line should really be “MyLog” instead of “myLog”.
Hi,
just wanted to say thanks for this paper. Being on a very tight schedule and being new to log4r this speeded up things a lot!
two thumbs up