RSS

Add Logging to Ruby Scripts with Log4r

Tue, Oct 14, 2008    (Click to Rate!) Loading ... Loading ...

Linux, Programming


Log4r is a logging library inspired by Apache Foundation’s Log4j, “but is not a direct implementation or clone.” Of course this doesn’t change the fact that log4r is a very efficient, fast, and easy to use library. I’m going give a quick tutorial how to add logging capabilities to your Ruby scripts using Log4r. First, let’s get everything we need installed and then I’ll show how I added logging capabilities to fibonacci Ruby script I’ve written in a previous post.

We have two basic ways of installing the log4r library. We can either install directly by grabbing the source or we can install using ruby-gems.

To install using the source head on over to the Sourceforge download page.

Extract the .zip or .tar.gz, enter the directory, and issue the install command

~$unzip log4r-1.0.5.zip
~$ cd log4r-1.0.5/
~/log4r-1.0.5$ sudo ruby install.rb

To install using ruby-gems, first make sure you have gems installed:

~$ sudo apt-get install rubygems

Then install the library:

~$ sudo gem install Log4jr

This should get you everything you need to get started. Now, lets look at the previously written
script:

#!/usr/bin/ruby
require 'time'

puts "starting fibonacci"

def fib(num)
 if(num < 2)
   return 1
 else
   return fib(num-1) + fib(num-2)
 end
end

if ARGV[0] != nil
 if (ARGV[0].to_i >= 35)
  puts "This might take a bit...."
 end
 start = Time.now
 puts fib(ARGV[0].to_i)
 stop = Time.now - start
 puts "Finding the fib of #{ARGV[0]} took:"
 puts stop
 puts "seconds"
end

We will need to add:

require 'log4r'
include Log4r

to the top to get access to the Log4r library.

Then we will need to create a logger. We’ll do this by adding another method to setup the global
logger. You can do this by adding:

def setupLogger()
  # create a logger
  @logger = Logger.new 'logger'
  @logger.outputters = Outputter.stdout
  @logger.debug "Logger is now setup"
end

to just before the fib() method call in your script.

Normally, I would set this up in an initialize method (for those unfamiliar with Ruby, this is like a
constructor method), but we’ll keep this simple for later examples.

I’m also going to replace all of the standard out (ie “puts”) messages, and
replace them to be logged with the DEBUG logger. Replace all ‘puts’ messages with “@logger.debug”.

For instance:

puts "Finding the fib of #{ARGV[0]} took: #{stop} seconds"

should now look like this:

@logger.debug "Finding the fib of #{ARGV[0]} took: #{stop} seconds"

Of course, we still want feedback from our program so let’s change the logger to output directly
to the console. You can actually see that this is already being done with this line:

  @logger.outputters = Outputter.stdout

After all of your edits, your script should now look like this:

#!/usr/bin/ruby
require 'time'
require 'log4r'
include Log4r

def setupLogger()
  # create a logger
  @logger = Logger.new 'logger'
  @logger.outputters = Outputter.stdout
  @logger.debug "Logger is now setup"
end

def fib(num)
 if(num < 2)
   return num
 else
   return fib(num-1) + fib(num-2)
 end
end

#start of main script
@logger.debug "starting fibonacci"

if ARGV[0] != nil
 if (ARGV[0].to_i >= 35)
  @logger.debug "This might take a bit...."
 end
 setupLogger()
 start = Time.now
 @logger.debug fib(ARGV[0].to_i)
 stop = Time.now - start
 @logger.debug "Finding the fib of #{ARGV[0]} took: "
 @logger.debug "#{stop}"
 @logger.debug "seconds"
end

If you try and run your script at this point you’ll notice an “undefined method `info’ for nil:NilClass (NoMethodError)” error. This is because you haven’t setup the logger before you started debugging. Lets move this log line to after the setupLogger() method call:

...
#start of main script

if ARGV[0] != nil
 if (ARGV[0].to_i >= 35)
  @logger.debug "This might take a bit...."
 end
 setupLogger()
 @logger.debug "starting fibonacci"
 start = Time.now
 @logger.debug fib(ARGV[0].to_i)
 stop = Time.now - start
 @logger.debug "Finding the fib of #{ARGV[0]} took: "
 @logger.debug "#{stop}"
 @logger.debug "seconds"
end

If you run your script now, it should work. Here is output from my run:

~$ ruby fib-log.rb 10
DEBUG logger: Logger is now setup
DEBUG logger: starting fibonacci
DEBUG logger: Fixnum: 55
DEBUG logger: Finding the fib of 10 took:
DEBUG logger: 0.000828
DEBUG logger: seconds

As you can see, adding a logger to your existing script is very easy, and you can get even more
fancy with the types of logs you wish to create. Since there are multiple
levels of logging (DEBUG< INFO < WARN < ERROR < FATAL), you can customize which level’s you use by changing the second qualifier (ie. @logger.debug could become @logger.info). Lets do that for
a couple of lines.

Change

@logger.debug "Logger is now setup"

to

@logger.info "Logger is now setup"

and change

@logger.debug "starting fibonacci"

to

@logger.info "starting fibonacci"

Your final script should look like this:

#!/usr/bin/ruby
require 'time'
require 'log4r'
include Log4r

def setupLogger()
  # create a logger named 'mylog' that logs to stdout
  @logger = Logger.new 'logger'
  @logger.outputters = Outputter.stdout
 @logger.info "Logger is now setup"
end

def fib(num)
 if(num < 2)
   return num
 else
   return fib(num-1) + fib(num-2)
 end
end

#start of main script

if ARGV[0] != nil
 if (ARGV[0].to_i >= 35)
  @logger.debug "This might take a bit...."
 end
 setupLogger()
 @logger.info "starting fibonacci"
 start = Time.now
 @logger.debug fib(ARGV[0].to_i)
 stop = Time.now - start
 @logger.debug "Finding the fib of #{ARGV[0]} took: "
 @logger.debug "#{stop}"
 @logger.debug "seconds"
end

Now let’s run the final script. You should have received output like this:

~$ ruby fib-log.rb 10
 INFO logger: Logger is now setup
 INFO logger: starting fibonacci
DEBUG logger: Fixnum: 55
DEBUG logger: Finding the fib of 10 took:
DEBUG logger: 0.000823
DEBUG logger: seconds

If you are looking for a quick way to add log messages to your ruby scripts, log4r might be a
very quick and easy to implement solution for you. Offering features comparable to Apache
Foundation’s log4j, you will find quite it quite capable of handing any of your current project’s
logging needs. Check it out, and let us know what you think.

Share This on Your Favorite Social Network:
  • Digg
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Furl
  • Propeller
  • Reddit
  • Technorati
  • StumbleUpon
  • DZone
  • MisterWong
  • TwitThis
  • Slashdot
  • SphereIt
, , , , , ,

This post was written by:

Ray Gomez - who has written 46 posts on kallasoft.

Ray, a Linux and Unix nut, spends a majority of his daily ritual programming and testing for Big Blue. In his free time he manages to tweak the currently running thinkpad+KDE4 (WHOA) setup, read, and he occasionally gets out of the fluorescent lights to play roller hockey.

Leave a Reply