Working with Ruby
Occasional blog posts about Ruby updates, tools, editor tweaks, and random snippets. You might also be interested in my newer project that docuements lesser-known features in Ruby: Idiosyncratic Ruby.

Exploring the stdlib: logger

puts is great for a quick output, but when a script gets more complex or you want to offer a flexible executable, consider using the logger ;). Since the logger class is part of the Ruby standard library, it can be used everywhere, without installing any gems. And it’s very easy to use :D

STEP 1: At the top of your Ruby program do

require 'logger'
@log = Logger.new(STDOUT) # or whatever kind of variable/constant suits to your project

STEP 2: Use the logger methods instead of puts

The following methods are available: debug, info, warn, error or fatal. You need to use them on the logger object (@log in this example), or define some helper methods in your current namespace ;).

STEP 3: Set the log level

The log level decides, which logs actually get displayed. You can set it via

@log.level = Logger::WARN

The constants map to the uppercased method names. Setting this to WARN means, warn messages and everything of higher levels will be displayed (error and fatal). By the way, those constants contain just simple integers (DEBUG = 0, FATAL = 4).

When writing an executable, you should allow a command-line option for setting the debug level, for example:

 1
2
3
4
5
6
7
8
9
10
11
12
require 'logger'

@log = Logger.new(STDOUT)

log_level =
  if level_index = ARGV.index('-L')
    ARGV.delete_at level_index # -L
    ARGV.delete_at level_index # level
  end
@log.level = log_level ? log_level.to_i : Logger::INFO # default value

puts "Your log level: #{ @log.level }"

STEP 4: Customize the logging format

The default output format is pretty verbose:

I, [Wed Mar 03 02:34:24 JST 1999 895701 #19074]  INFO -- Main: info.

Fortunately, it’s easy to configure using a proc:

@log.formatter = proc{ |level, datetime, progname, msg|
  # return a string
}

u

To further customize the datetime argument, you can use the Logger#datetime_format method, which takes a strftime format string.

STEP 4B: colors are beautiful!

I’ve written a little script to colorize the logger messages, depending on the logger level. Just paste these lines into your Ruby script or install the logger-colors gem and require 'logger/colors'

As I said, Logger is really easy to use, isn’t it ;)? Now, let’s take a look at logger’s bonus features.

Tips & Tricks

Two more logging methods

Logger also provides an ANY log level taht can be used with the unknown method- it’s even higher than FATAL. And sometimes, you want to add something to your log without any formatting, you can use the << method in this case.

Log files

Besides using STDOUT and STDERR, you can alternatively initialize the logger with a filename and the logs will be saved in the file.

Logger also supports log rotation (use multiple small log files) in two ways:

Logger.new name, 5, 1048576 # 5 log files to keep, max size: 1048576
Logger.new name, 'daily'    # shift log every day, other values: 'weekly' or 'monthly'

Log Applications

You can let your custom class inherit from Logger::Application to get some free log helper methods (log, level, …), see the docs for more information.

Rails extensions

ActiveSupport adds two block helpers to Logger.

Logger was written in 2001. Is it still useful? Does it belong to the stdlib?

Logger only offers some basic features, but this is OK a good thing for libraries in the standard library. It is simple and helpful. For more flexible needs, there is the log4r gem.

Creative Commons License

dan | May 10, 2011

thank you so much for this post. i always wanted to use logger and now i have no excuses!

Arun Kumar Arjunan | May 10, 2011

Great post!!! Thanks for sharing...

Rudi | May 10, 2011

Nice post! Have you tried http://rubygems.org/gems/little_log_friend?

J-_-L | May 11, 2011

@Rudi, no haven't seen it, yet, looks nice :)

adit | March 20, 2013

Nice post! Thanks for the colors script. I modified it slightly:

if Logger::Colors::SCHEMA[@logdev.dev] && @logdev.dev.tty?

By checking `@logdev.dev.tty?` you only print colors if the output isn't being logged somewhere.